From fe1ca6f07c5735d08e80ff08008378384ac239dc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 3 Jan 2014 12:36:54 +0100 Subject: [PATCH 01/32] update READMEs for mingw and macos --- README.macos | 2 +- README.mingw | 103 ++++++++++++++++++++++----------------------------- 2 files changed, 45 insertions(+), 60 deletions(-) diff --git a/README.macos b/README.macos index db01b4869..cc89ded86 100644 --- a/README.macos +++ b/README.macos @@ -30,7 +30,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" - $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names" - Install libantlr3c (library used by belle-sip for parsing) $ git clone -b linphone git://git.linphone.org/antlr3.git diff --git a/README.mingw b/README.mingw index cb1f60c01..4ac4661a7 100644 --- a/README.mingw +++ b/README.mingw @@ -9,7 +9,7 @@ In the feature list, select: * Mingw developer toolkit Let the installer fetch and install everything. -In mingw shell, run +In mingw shell (also refered as msys), run mingw-get install msys-zip mingw-get install msys-unzip @@ -45,70 +45,63 @@ libintl.a libintl.la libintl.dll.a * Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable. -Get Linphone source code -************************ +* Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. -Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. -Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. -It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example -c:\sources\ -Within msys-git bash, do +General rules for compilation +***************************** + +- It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example c:\sources\. + This is the place where source code must be compiled. +- git commands (to retrieve source code) must be performed within msys-git terminal. +- all other commands (configure, autogen.sh, make) must be done within the mingw shell (msys). +In both msys and msys-git windows, change into the directory you created for sources: cd /c/sources -git clone git://git.linphone.org/linphone.git --recursive +Building belle-sip +****************** + * download the sources with msys-git shell using the following command: + $ git clone git://git.linphone.org/belle-sip.git + * compile and install + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install -Building -******** +Building Linphone +***************** -WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del to start the windows system monitor, - you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu. -Kill it. Don't know what it is, but once killed, windows runs normally. + * download the sources using the following command: + $ git clone git://git.linphone.org/linphone.git --recursive -#Build linphone itself: -#run autogen.sh after a git checkout or update + * compile + #always run autogen.sh after a git checkout or update + $ ./autogen.sh -./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + #note: in order to use the tunnel (commercial extension), append --enable-tunnel to the configure line above. -./configure --prefix=/usr --enable-shared --disable-static -#note: in order to use the tunnel, append --enable-tunnel to the configure line above. + $ make + $ make install -#compile: + #Option: make a portable binary zip of linphone + $ make zip -make + #additionally you can make binary installer if you have Inno Setup 5 installed in its default path -#now install to /usr, required for compilation of plugins. + $ make setup.exe + #now you're done, you have a fresh linphone windows installer in the current directory. -make install +Building plugins (optional) +*************************** -#make a binary zip of linphone - -make zip - -#additionally you can make binary installer if you have Inno Setup 5 installed in its default path - -make setup.exe - -#now you're done, you have a fresh linphone windows installer in the current directory. - - - -#build plugins -cd mediastreamer2/plugins/msx264 -./autogen.sh -PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static -#make a binary zip of this plugin -make zip -#or make an installer -make setup.exe - -#the buddylookup plugin enables lookup of buddies in a remote database using xml-rpc over http/https. -cd coreapi/plugins/buddylookup -./autogen.sh -PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static -make -#make a binary zip of this plugin -make zip + This the example for msx264 (H264 plugin), the same applies for other linphone plugins. + $ cd mediastreamer2/plugins/msx264 + $ ./autogen.sh + $ PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static + #make a binary zip of this plugin + $ make zip + #or make an installer + $ make setup.exe ****************************************************** @@ -161,14 +154,6 @@ When running "make install DESTDIR=", somepath must be absolute and sh $ make install DESTDIR=/usr $ make install DESTDIR=/home//polarssl-install -- building belle-sip - * download the sources with: - $ git clone git://git.linphone.org/belle-sip.git - * compile and install, assuming you have already compiled polarssl and antlr3c and installed in /. - $ ./autogen.sh - $ ./configure --prefix=/usr --enable-shared --disable-static - $ make && make install && make install DESTDIR=/home//belle-sip-install - - building libsrtp * download the sources with $ git clone git://git.linphone.org/srtp.git From d468050c8ba5daec52477df6229c77773a831478 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 Jan 2014 15:41:40 +0100 Subject: [PATCH 02/32] Implement RFC3994: Indication of Message Composition for Instant Messaging. --- console/Makefile.am | 6 +- coreapi/Makefile.am | 1 + coreapi/bellesip_sal/sal_impl.c | 11 +- coreapi/bellesip_sal/sal_op_message.c | 20 ++- coreapi/callbacks.c | 16 +- coreapi/chat.c | 246 +++++++++++++++++++++++++- coreapi/linphonecore.h | 23 +++ coreapi/presence.c | 173 +++++------------- coreapi/private.h | 40 +++++ coreapi/xml.c | 98 ++++++++++ gtk/chat.c | 21 ++- gtk/friendlist.c | 24 ++- gtk/linphone.h | 1 + gtk/main.c | 1 + include/sal/sal.h | 10 ++ pixmaps/Makefile.am | 2 +- pixmaps/active_chat.png | Bin 3415 -> 3386 bytes pixmaps/composing_active_chat.png | Bin 0 -> 3398 bytes pixmaps/composing_chat.png | Bin 0 -> 3291 bytes tester/Makefile.am | 4 +- 20 files changed, 552 insertions(+), 145 deletions(-) create mode 100644 coreapi/xml.c create mode 100644 pixmaps/composing_active_chat.png create mode 100644 pixmaps/composing_chat.png diff --git a/console/Makefile.am b/console/Makefile.am index 3a975e9c4..314f5d612 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -13,7 +13,8 @@ COMMON_CFLAGS=\ $(MEDIASTREAMER_CFLAGS) \ $(VIDEO_CFLAGS) \ $(READLINE_CFLAGS) \ - $(SQLITE3_CFLAGS) + $(SQLITE3_CFLAGS) \ + $(LIBXML2_CFLAGS) if BUILD_CONSOLE @@ -29,7 +30,8 @@ linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(READLINE_LIBS) \ $(SQLITE3_LIBS) \ $(X11_LIBS) \ - $(BELLESIP_LIBS) + $(BELLESIP_LIBS) \ + $(LIBXML2_LIBS) if BUILD_WIN32 #special build of linphonec to detach from the windows console diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 3933ddb05..61d240464 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -51,6 +51,7 @@ liblinphone_la_SOURCES=\ contactprovider.c contactprovider.h contact_providers_priv.h \ ldap/ldapprovider.c ldap/ldapprovider.h \ dict.c \ + xml.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 08986eb89..f15b07ffb 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -464,6 +464,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub; if (ctx->callbacks.text_received==NULL) ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; + if (ctx->callbacks.is_composing_received==NULL) + ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; if (ctx->callbacks.auth_requested==NULL) @@ -915,5 +917,12 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } +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); +} diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 1e3dc12f0..25402aef2 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -76,6 +76,10 @@ 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 bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { + return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("im-iscomposing+xml",belle_sip_header_content_type_get_subtype(content_type))==0; +} static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; @@ -88,8 +92,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t 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); - SalMessage salmsg; - char message_id[256]={0}; int response_code=501; char* from; bool_t plain_text=FALSE; @@ -99,7 +101,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); if (content_type && ((plain_text=is_plain_text(content_type)) || (external_body=is_external_body(content_type)))) { - + SalMessage salmsg; + char message_id[256]={0}; 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)); @@ -121,6 +124,17 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_free(from); if (salmsg.url) ms_free((char*)salmsg.url); response_code=200; + } else if (content_type && is_im_iscomposing(content_type)) { + SalIsComposing saliscomposing; + 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)); + saliscomposing.from=from; + saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + op->base.root->callbacks.is_composing_received(op,&saliscomposing); + belle_sip_object_unref(address); + belle_sip_free(from); + response_code=200; } else { ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) ,belle_sip_header_content_type_get_subtype(content_type)); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a9c364c52..3ebce7488 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -843,6 +843,11 @@ static void text_received(SalOp *op, const SalMessage *msg){ } } +static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) { + LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_core_is_composing_received(lc, op, is_composing); +} + static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) { linphone_notify_parse_presence(op, content_type, content_subtype, body, result); } @@ -1001,8 +1006,14 @@ static int op_equals(LinphoneCall *a, SalOp *b) { static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); - const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc); - + const MSList* calls; + + if (chat_msg == NULL) { + // Do not handle delivery status for isComposing messages. + return; + } + calls = linphone_core_get_calls(chat_msg->chat_room->lc); + chat_msg->state=chatStatusSal2Linphone(status); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { @@ -1123,6 +1134,7 @@ SalCallbacks linphone_sal_callbacks={ refer_received, text_received, text_delivery_update, + is_composing_received, notify_refer, subscribe_received, subscribe_closed, diff --git a/coreapi/chat.c b/coreapi/chat.c index c2e6a9cf5..ddb6ba262 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -26,6 +26,12 @@ #include "private.h" #include "lpconfig.h" +#include + +#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 +#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 +#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 + /** * @addtogroup chatroom * @{ @@ -85,13 +91,40 @@ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const } return ret; } - + +static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) { + if (cr->composing_idle_timer) { + sal_cancel_timer(cr->lc->sal, cr->composing_idle_timer); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + } +} + +static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->composing_refresh_timer) { + sal_cancel_timer(cr->lc->sal, cr->composing_refresh_timer); + belle_sip_object_unref(cr->composing_refresh_timer); + cr->composing_refresh_timer = NULL; + } +} + +static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->remote_composing_refresh_timer) { + sal_cancel_timer(cr->lc->sal, cr->remote_composing_refresh_timer); + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + } +} + /** * Destroy a LinphoneChatRoom. * @param cr #LinphoneChatRoom object */ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ LinphoneCore *lc=cr->lc; + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + linphone_chat_room_delete_remote_composing_refresh_timer(cr); lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); linphone_address_destroy(cr->peer_url); ms_free(cr->peer); @@ -142,6 +175,12 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); msg->storage_id=linphone_chat_message_store(msg); + + if (cr->is_composing == LinphoneIsComposingActive) { + cr->is_composing = LinphoneIsComposingIdle; + } + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); } /** @@ -225,6 +264,89 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag ms_free(from); } +static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + cr->remote_is_composing = LinphoneIsComposingIdle; + if (cr->lc->vtable.is_composing_received != NULL) + cr->lc->vtable.is_composing_received(cr->lc, cr); + return BELLE_SIP_STOP; +} + +static const char *iscomposing_prefix = "/xsi:isComposing"; + +static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr iscomposing_object; + const char *state_str = NULL; + const char *refresh_str = NULL; + int refresh_duration = COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT; + int i; + LinphoneIsComposingState state = LinphoneIsComposingIdle; + + if (linphone_create_xml_xpath_context(xml_ctx) < 0) return; + + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix); + if ((iscomposing_object != NULL) && (iscomposing_object->nodesetval != NULL)) { + for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i); + state_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (state_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i); + refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + } + } + + if (state_str != NULL) { + if (strcmp(state_str, "active") == 0) { + state = LinphoneIsComposingActive; + if (refresh_str != NULL) { + refresh_duration = atoi(refresh_str); + } + if (!cr->remote_composing_refresh_timer) { + cr->remote_composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_remote_refresh_composing_expired, cr, refresh_duration * 1000, "composing remote refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->remote_composing_refresh_timer, refresh_duration * 1000); + } + } else { + linphone_chat_room_delete_remote_composing_refresh_timer(cr); + } + + cr->remote_is_composing = state; + if (cr->lc->vtable.is_composing_received != NULL) + cr->lc->vtable.is_composing_received(cr->lc, cr); + } +} + +static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const char *text) { + xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); + xml_ctx->doc = xmlReadDoc((const unsigned char*)text, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + process_im_is_composing_notification(cr, xml_ctx); + } else { + ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); + } + linphone_xmlparsing_context_destroy(xml_ctx); +} + +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { + LinphoneChatRoom *cr = NULL; + LinphoneAddress *addr = linphone_address_new(is_composing->from); + linphone_address_clean(addr); + cr = linphone_core_get_chat_room(lc, addr); + if (cr != NULL) { + linphone_chat_room_notify_is_composing(cr, is_composing->text); + } + linphone_address_destroy(addr); +} + +bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { + return (cr->remote_is_composing == LinphoneIsComposingActive) ? TRUE : FALSE; +} + /** * Returns back pointer to LinphoneCore object. **/ @@ -319,6 +441,128 @@ void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* _linphone_chat_room_send_message(cr, msg); } +static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = 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; + } + + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"isComposing", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi", + NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xsi", (const xmlChar *)"schemaLocation", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:im-composing iscomposing.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"state", + (cr->is_composing == LinphoneIsComposingActive) ? (const xmlChar *)"active" : (const xmlChar *)"idle"); + } + if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) { + char refresh_str[4] = { 0 }; + snprintf(refresh_str, sizeof(refresh_str), "%u", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str); + } + if (err >= 0) { + /* Close the "isComposing" 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); + return content; +} + +static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) { + SalOp *op = NULL; + LinphoneCall *call; + const char *identity = NULL; + char *content = NULL; + + if (lp_config_get_int(cr->lc->config, "sip", "chat_use_call_dialogs", 0)) { + if ((call = linphone_core_get_call_by_remote_address(cr->lc, cr->peer)) != NULL) { + if (call->state == LinphoneCallConnected || + call->state == LinphoneCallStreamsRunning || + call->state == LinphoneCallPaused || + call->state == LinphoneCallPausing || + call->state == LinphoneCallPausedByRemote) { + ms_message("send SIP message through the existing call."); + op = call->op; + identity = linphone_core_find_best_identity(cr->lc, linphone_call_get_remote_address(call)); + } + } + } + if (op == NULL) { + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url); + if (proxy) + identity = linphone_proxy_config_get_identity(proxy); + else + identity = linphone_core_get_primary_contact(cr->lc); + /*sending out of calls*/ + op = sal_op_new(cr->lc->sal); + linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0)); + } + content = linphone_chat_room_create_is_composing_xml(cr); + if (content != NULL) { + sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content); + ms_free(content); + } +} + +static int linphone_chat_room_stop_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + cr->is_composing = LinphoneIsComposingIdle; + linphone_chat_room_send_is_composing_notification(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + return BELLE_SIP_STOP; +} + +static int linphone_chat_room_refresh_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + linphone_chat_room_send_is_composing_notification(cr); + return BELLE_SIP_CONTINUE; +} + +void linphone_chat_room_compose(LinphoneChatRoom *cr) { + if (cr->is_composing == LinphoneIsComposingIdle) { + cr->is_composing = LinphoneIsComposingActive; + linphone_chat_room_send_is_composing_notification(cr); + if (!cr->composing_refresh_timer) { + cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000, "composing refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->composing_refresh_timer, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000); + } + if (!cr->composing_idle_timer) { + cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000, "composing idle timeout"); + } + } + belle_sip_source_set_timeout(cr->composing_idle_timer, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000); +} + /** * Returns a #LinphoneChatMessageState as a string. */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c6a3332df..4aa4d0942 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -977,6 +977,20 @@ LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); + +/** + * Notify 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); + LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); @@ -1130,6 +1144,14 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat */ typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +/** + * Is composing notification callback prototype. + * + * @param[in] lc #LinphoneCore object + * @param[in] room #LinphoneChatRoom involved in the conversation. + */ +typedef void (*LinphoneCoreIsComposingReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room); + /** * Callback for being notified of DTMFs received. * @param lc the linphone core @@ -1179,6 +1201,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */ LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */ LinphoneCoreMessageReceivedCb message_received; /** a message is received, can be text or external body*/ + LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */ LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */ LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */ LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /** -#include -#include -#include - - -#define XMLPARSING_BUFFER_LEN 2048 -#define MAX_XPATH_LENGTH 256 - extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); @@ -83,13 +74,6 @@ struct _LinphonePresenceModel { MSList *notes; /**< A list of _LinphonePresenceNote structures. */ }; -typedef struct _xmlparsing_context { - xmlDoc *doc; - xmlXPathContextPtr xpath_ctx; - char errorBuffer[XMLPARSING_BUFFER_LEN]; - char warningBuffer[XMLPARSING_BUFFER_LEN]; -} xmlparsing_context_t; - static const char *person_prefix = "/pidf:presence/dm:person"; @@ -98,38 +82,6 @@ static const char *person_prefix = "/pidf:presence/dm:person"; * PRIVATE FUNCTIONS * ****************************************************************************/ -static xmlparsing_context_t * xmlparsing_context_new() { - xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); - if (xmlCtx != NULL) { - xmlCtx->doc = NULL; - xmlCtx->xpath_ctx = NULL; - xmlCtx->errorBuffer[0] = '\0'; - xmlCtx->warningBuffer[0] = '\0'; - } - return xmlCtx; -} - -static void xmlparsing_context_destroy(xmlparsing_context_t *ctx) { - if (ctx->doc != NULL) { - xmlFreeDoc(ctx->doc); - ctx->doc = NULL; - } - if (ctx->xpath_ctx != NULL) { - xmlXPathFreeContext(ctx->xpath_ctx); - ctx->xpath_ctx = NULL; - } - free(ctx); -} - -static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { - xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; - int sl = strlen(xmlCtx->errorBuffer); - va_list args; - va_start(args, fmt); - vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); - va_end(args); -} - static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static char * generate_presence_id(void) { @@ -1183,45 +1135,6 @@ void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { * XML PRESENCE INTERNAL HANDLING * ****************************************************************************/ -static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { - if (xml_ctx->xpath_ctx != NULL) { - xmlXPathFreeContext(xml_ctx->xpath_ctx); - } - xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); - if (xml_ctx->xpath_ctx == NULL) return -1; - return 0; -} - -static char * get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { - xmlXPathObjectPtr xpath_obj; - xmlChar *text = NULL; - int i; - - xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); - if (xpath_obj != NULL) { - if (xpath_obj->nodesetval != NULL) { - xmlNodeSetPtr nodes = xpath_obj->nodesetval; - for (i = 0; i < nodes->nodeNr; i++) { - xmlNodePtr node = nodes->nodeTab[i]; - if (node->children != NULL) { - text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); - } - } - } - xmlXPathFreeObject(xpath_obj); - } - - return (char *)text; -} - -static void free_xml_text_content(const char *text) { - xmlFree((xmlChar *)text); -} - -static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { - return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); -} - static const char *service_prefix = "/pidf:presence/pidf:tuple"; static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceService *service, unsigned int service_idx) { @@ -1233,19 +1146,19 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx int i; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_service_add_note(service, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1264,11 +1177,11 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin LinphonePresenceBasicStatus basic_status; int i; - service_object = get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); + service_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); if ((service_object != NULL) && (service_object->nodesetval != NULL)) { for (i = 1; i <= service_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i); - basic_status_str = get_xml_text_content(xml_ctx, xpath_str); + basic_status_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (basic_status_str == NULL) continue; @@ -1278,33 +1191,33 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin basic_status = LinphonePresenceBasicStatusClosed; } else { /* Invalid value for basic status. */ - free_xml_text_content(basic_status_str); + linphone_free_xml_text_content(basic_status_str); return -1; } snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i); - timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i); - contact_str = get_xml_text_content(xml_ctx, xpath_str); + contact_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i); - service_id_str = get_xml_text_content(xml_ctx, xpath_str); + service_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); service = presence_service_new(service_id_str, basic_status); if (service != NULL) { if (timestamp_str != NULL) { presence_service_set_timestamp(service, parse_timestamp(timestamp_str)); - free_xml_text_content(timestamp_str); + linphone_free_xml_text_content(timestamp_str); } if (contact_str != NULL) { linphone_presence_service_set_contact(service, contact_str); - free_xml_text_content(contact_str); + linphone_free_xml_text_content(contact_str); } process_pidf_xml_presence_service_notes(xml_ctx, service, i); linphone_presence_model_add_service(model, service); } - free_xml_text_content(basic_status_str); - if (service_id_str != NULL) free_xml_text_content(service_id_str); + linphone_free_xml_text_content(basic_status_str); + if (service_id_str != NULL) linphone_free_xml_text_content(service_id_str); } } if (service_object != NULL) xmlXPathFreeObject(service_object); @@ -1333,11 +1246,11 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml int err = 0; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities", person_prefix, person_idx); - activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + activities_nodes_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) { for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/rpid:*", person_prefix, person_idx, i); - activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + activities_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { activity_node = activities_object->nodesetval->nodeTab[j]; @@ -1345,14 +1258,14 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml LinphonePresenceActivityType acttype; description = (const char *)xmlNodeGetContent(activity_node); if ((description != NULL) && (description[0] == '\0')) { - free_xml_text_content(description); + linphone_free_xml_text_content(description); description = NULL; } err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); if (err < 0) break; activity = linphone_presence_activity_new(acttype, description); linphone_presence_person_add_activity(person, activity); - if (description != NULL) free_xml_text_content(description); + if (description != NULL) linphone_free_xml_text_content(description); } } } @@ -1374,37 +1287,37 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, int i; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note", person_prefix, person_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]", person_prefix, person_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_person_add_activities_note(person, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note", person_prefix, person_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]", person_prefix, person_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_person_add_note(person, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1422,13 +1335,13 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp int i; int err = 0; - person_object = get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); + person_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); if ((person_object != NULL) && (person_object->nodesetval != NULL)) { for (i = 1; i <= person_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i); - person_id_str = get_xml_text_content(xml_ctx, xpath_str); + person_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i); - person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + person_timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (person_timestamp_str == NULL) timestamp = time(NULL); else @@ -1446,8 +1359,8 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp break; } } - if (person_id_str != NULL) free_xml_text_content(person_id_str); - if (person_timestamp_str != NULL) free_xml_text_content(person_timestamp_str); + if (person_id_str != NULL) linphone_free_xml_text_content(person_id_str); + if (person_timestamp_str != NULL) linphone_free_xml_text_content(person_timestamp_str); } } if (person_object != NULL) xmlXPathFreeObject(person_object); @@ -1467,19 +1380,19 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho const char *lang; int i; - note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]", i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_model_add_note(model, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1491,7 +1404,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing LinphonePresenceModel *model = NULL; int err; - if (create_xml_xpath_context(xml_ctx) < 0) + if (linphone_create_xml_xpath_context(xml_ctx) < 0) return NULL; model = linphone_presence_model_new(); @@ -1606,15 +1519,15 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c } if (strcmp(content_subtype, "pidf+xml") == 0) { - xml_ctx = xmlparsing_context_new(); - xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error); + xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0); if (xml_ctx->doc != NULL) { model = process_pidf_xml_presence_notification(xml_ctx); } else { ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); } - xmlparsing_context_destroy(xml_ctx); + linphone_xmlparsing_context_destroy(xml_ctx); } else { ms_error("Unknown content type '%s/%s' for presence", content_type, content_subtype); } diff --git a/coreapi/private.h b/coreapi/private.h index 5225b6a3c..012484c1d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -338,6 +338,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); void linphone_core_play_tone(LinphoneCore *lc); @@ -426,12 +427,22 @@ struct _LinphoneAuthInfo bool_t works; }; +typedef enum _LinphoneIsComposingState { + LinphoneIsComposingIdle, + LinphoneIsComposingActive +} LinphoneIsComposingState; + struct _LinphoneChatRoom{ struct _LinphoneCore *lc; char *peer; LinphoneAddress *peer_url; void * user_data; MSList *messages_hist; + LinphoneIsComposingState remote_is_composing; + LinphoneIsComposingState is_composing; + belle_sip_source_t *remote_composing_refresh_timer; + belle_sip_source_t *composing_idle_timer; + belle_sip_source_t *composing_refresh_timer; }; @@ -788,6 +799,35 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); + +/***************************************************************************** + * XML UTILITY FUNCTIONS * + ****************************************************************************/ + +#include +#include +#include +#include + +#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); +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +void linphone_free_xml_text_content(const char *text); +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); + + #ifdef __cplusplus } #endif diff --git a/coreapi/xml.c b/coreapi/xml.c new file mode 100644 index 000000000..b4b994174 --- /dev/null +++ b/coreapi/xml.c @@ -0,0 +1,98 @@ +/* +linphone +Copyright (C) 2010-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, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "private.h" + +#include +#include +#include +#include + + +xmlparsing_context_t * linphone_xmlparsing_context_new(void) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); + if (xmlCtx != NULL) { + xmlCtx->doc = NULL; + xmlCtx->xpath_ctx = NULL; + xmlCtx->errorBuffer[0] = '\0'; + xmlCtx->warningBuffer[0] = '\0'; + } + return xmlCtx; +} + +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx) { + if (ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + if (ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(ctx->xpath_ctx); + ctx->xpath_ctx = NULL; + } + free(ctx); +} + +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); + va_end(args); +} + +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { + if (xml_ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(xml_ctx->xpath_ctx); + } + xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); + if (xml_ctx->xpath_ctx == NULL) return -1; + return 0; +} + +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + xmlXPathObjectPtr xpath_obj; + xmlChar *text = NULL; + int i; + + xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); + if (xpath_obj != NULL) { + if (xpath_obj->nodesetval != NULL) { + xmlNodeSetPtr nodes = xpath_obj->nodesetval; + for (i = 0; i < nodes->nodeNr; i++) { + xmlNodePtr node = nodes->nodeTab[i]; + if (node->children != NULL) { + text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); + } + } + } + xmlXPathFreeObject(xpath_obj); + } + + return (char *)text; +} + +void linphone_free_xml_text_content(const char *text) { + xmlFree((xmlChar *)text); +} + +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); +} diff --git a/gtk/chat.c b/gtk/chat.c index b44605ae3..0c9aa400b 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -279,6 +279,16 @@ static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageS 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); + } +} + void linphone_gtk_send_text(){ GtkWidget *main_window=linphone_gtk_get_main_window(); GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); @@ -293,7 +303,11 @@ void linphone_gtk_send_text(){ linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL); 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); } } @@ -410,6 +424,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); entry = linphone_gtk_get_widget(chat_view,"text_entry"); 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); ms_free(with_str); return chat_view; @@ -417,7 +432,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){ char *tmp=linphone_address_as_string(with); - LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp); + LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp); ms_free(tmp); return cr; } @@ -516,3 +531,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, linphone_gtk_show_friends(); } + +void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + linphone_gtk_friend_list_update_chat_picture(); +} diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 523cf13b3..0316dd699 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -87,6 +87,18 @@ static GdkPixbuf *create_chat_picture(){ return pixbuf; } +static GdkPixbuf *create_composing_unread_msg(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("composing_active_chat.png"); + return pixbuf; +} + +static GdkPixbuf *create_composing_chat_picture(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("composing_chat.png"); + return pixbuf; +} + /* void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ GtkTreeIter iter; @@ -227,15 +239,23 @@ void linphone_gtk_friend_list_update_chat_picture(){ GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); LinphoneChatRoom *cr=NULL; + bool_t is_composing; int nbmsg=0; if (gtk_tree_model_get_iter_first(model,&iter)) { do{ 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){ - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); + if (is_composing == TRUE) + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_unread_msg(),-1); + else + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); } else { - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); + if (is_composing == TRUE) + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_chat_picture(),-1); + else + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); } }while(gtk_tree_model_iter_next(model,&iter)); } diff --git a/gtk/linphone.h b/gtk/linphone.h index 1d674f876..f9d918c51 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -116,6 +116,7 @@ void linphone_gtk_send_text(); GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with); LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); +void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void linphone_gtk_friend_list_update_chat_picture(); void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); diff --git a/gtk/main.c b/gtk/main.c index 135dfe5f4..e47af7f3a 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -266,6 +266,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_log_updated=linphone_gtk_call_log_updated; //vtable.text_received=linphone_gtk_text_received; 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; diff --git a/include/sal/sal.h b/include/sal/sal.h index b76d70b05..6044205be 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mscommon.h" #include "ortp/ortp_srtp.h" +#include "belle-sip/belle-sip.h" #ifndef LINPHONE_PUBLIC #define LINPHONE_PUBLIC MS2_PUBLIC @@ -224,6 +225,11 @@ typedef struct SalMessage{ time_t time; }SalMessage; +typedef struct SalIsComposing { + const char *from; + const char *text; +} SalIsComposing; + #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); @@ -390,6 +396,7 @@ typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg); typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); +typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body); @@ -425,6 +432,7 @@ typedef struct SalCallbacks{ SalOnRefer refer_received; SalOnTextReceived text_received; SalOnTextDeliveryUpdate text_delivery_update; + SalOnIsComposingReceived is_composing_received; SalOnNotifyRefer notify_refer; SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; @@ -690,6 +698,8 @@ LINPHONE_PUBLIC bool_t sal_dns_srv_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 char * sal_get_random_bytes(unsigned char *ret, size_t size); +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); int sal_body_has_type(const SalBody *body, const char *type, const char *subtype); /*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index 2386d68cf..5e9b7a177 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -11,7 +11,7 @@ status-orange.png \ status-red.png \ status-offline.png \ call.png \ -chat.png active_chat.png\ +chat.png active_chat.png composing_chat.png composing_active_chat.png\ chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\ contact-orange.png dialer-orange.png history-orange.png\ startcall-green.png startcall-small.png stopcall-red.png stopcall-small.png addcall-green.png linphone.icns \ diff --git a/pixmaps/active_chat.png b/pixmaps/active_chat.png index d82b7c595c8a90fddb3c313be4bd9c6c524b0af4..ef3cedd1d2cf251b517f1b9840dd0d36b457fcb1 100644 GIT binary patch delta 696 zcmV;p0!RJV8oC;gBe6JK3J(TiOGiWi000000Qp0^e~}>qD4Uwwy}jFX%J`#MGH65&myEE zs1~*?C~Vh25Co>i5QQcZ*+#5JMj80B(9N%eWjLrCDd;}dhi}!us zyXQOiUcM_NfAO!OZ1hKS`~iFy4q-Mj3hVo`$_BSkM0mtE)^Y6aIEp=0ICC%POhhXz zK>zcAQeAyt`MlXX@7*aTP>Q;P-q)?gek{(sQ5AhF06@(aps%lwB4R6IY{`eWtO8>b zbNKXb8m{sR;ENl3evP&-gvZL3k=K$~O!xrY0LfMKfBXH6#bQh*lQd0pO@>Ebu}lGh zGG9EtJaP+XA)k#kdP9k65(j!7Zr+;{svDhT*cWfg7?mhqT$)zC{ zWv$72U6qca@&oudJ%PvV1E{ZZ!=(T>+geZ_slrR{yGj$$tWJ7+d+7wBsVNQ*4KY2Y zl35aG&rH6mA`*?-KPyf})Vw?-5{cDo8wr%{eRiOGIYb1OW!a}Il}b5E zS3DkvrfI8%|F#|s1{n&4pzAse!$56qEdXF-WCYP@6e0o<`IEAhTU(X|lCUfbjg5_x zk>9o0)zw9k3B(A?ZCPRFnO e8rL&E7yJhK0Wf%d8%Lf10000 z06Lfe02gnPU&TfM00M$ZL_t(|+RRm7NK;W9{?7H&?sR*hEdn_pGtw9h3rpAau6N&6atfrF)f+(~?t4Su)muh26i$Iu=6X6-y{+OT-gi0M|is1$;gqqtPfW%c5zT z84((L#R>%kQs6G5D`mZ{<<1PrbSAp4!|8OcEtgS_o4!ZbG(Uls3)f(pN#JJ)a{$VA zR>M?_Z_Q49`v3rGOrG}kGN)QHd1hZRp@0H{LMvi>*9gxJ{1Wa-_?D9Xo}~#~YxTF}&!!4J#Hp(RAdHZp)-M2PWaKZ|N3-fKK1YEThry zY}~$;0J!Je!zUMqSz_zSTB%B{lFI$~I6aBS9fN4BalxqoH*U3|GF*d~+({Rnm8PeoS6tAAf?RCB$-U+C08sKgQjUK8?W{t5C||B3_{m+7>0rR z`g#Ds=;$aSkqCqk5JD_V^!L?LN|1z<63xxcBF*Sb=Q%{fhtkkI$w43;=loR6owzNErYC002ov JPDHLkV1n*lRrde@ diff --git a/pixmaps/composing_active_chat.png b/pixmaps/composing_active_chat.png new file mode 100644 index 0000000000000000000000000000000000000000..77da9e37f79077c2eba5ac6ef2077a8867cfbdb0 GIT binary patch literal 3398 zcmV-M4Y~4(P)P000&U1^@s6HNQ8u000V4X+uL$P-t&- zZ*ypGa3D!TLm+T+Z)Rz1WdHzp+MQEpR8#2|J@?-9LQ9B%luK_?6$l_wLW_VDktQl3 z2@pz%A)(n7QNa;KMFbnjpojyGj)066Q7jCK3fKqaA)=0hqlk*i`{8?|Yu3E?=FR@K z*FNX0^PRKL2fzpnmPj*EHGmAMLLL#|gU7_i;p8qrfeIvW01ybXWFd3?BLM*Temp!Y zBESc}00DT@3kU$fO`E_l9Ebl8>Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGi!~g&e!~vBn4jTXf00(qQO+^RZ0Rs&T1s^hbaR2}Ucu7P- zR7l6oRbNO`VHE#;ch~N%bk`7;xd!S(4+TZoi#-_93<8Zo(StA2pNEi&pn9;!g2LV! z1VLbGj3_jb$X;aCbR&Ww3a!v`lF8=FHeIee=l%6y#@4oLa|He1$K~Gpecw61bIx~; zAc=nsX}ufuiFm15|rPiknm zD}CJPn0IU!I#7kC{f?I%6&@_kzLF(%GXOx&b->`@AcYX7Mzl>Oa8%b~d~yyS-ps&S zQww~uVb_nbu7%Ke^)f8&iN%B)z%`J}pvU83EEZ!jnWV1kc^Mje!D#bRm*-BJZh1F_ZJ6u{7Zg?JG!~6tV&tHYEr+{xE%mJv}Q3qWv>kLnSc?SSlN*?$3 zvmh+%JiWJ!kU#-Jp_Hn8 zH9^tic-DOr$$02^%i)7+P9^;XD2aT2O}h{TRC-3kjK!wdylo2saQE5!k1mX`JZDbU zs;YF9*X+alnMpkC8b))y4OR)b-r0_tNIjl&&t>X}=2S8;FhH)ffi;;6!Rcv^j*Kw< zOgTFx%y<@x5?Mwh8Z~b##r87UVnHI2$o!UXaUr=$chDdq%ktkDS+61?1PsG44_7Lc zDk@y@cpQqNWE%d{W53_eU@!<(RiSAboK7bIAP@*38jb$GjH~-ry*3PEC0vF9m&+xx z!jg}@y}cw!pU+3H*GsdtW;C5AilU&euMbO0OK5Ct6zi_Id_UZ7H#JQ|TU(nbcKnL} cdd3%mpBADUr1!WH9{>OV07*qoM6N<$f*r6_oB#j- literal 0 HcmV?d00001 diff --git a/pixmaps/composing_chat.png b/pixmaps/composing_chat.png new file mode 100644 index 0000000000000000000000000000000000000000..2d329ed21dccdfa12ce40308e8e2e22336faec20 GIT binary patch literal 3291 zcmV<13?%c3P)P000&U1^@s6HNQ8u000V4X+uL$P-t&- zZ*ypGa3D!TLm+T+Z)Rz1WdHzp+MQEpR8#2|J@?-9LQ9B%luK_?6$l_wLW_VDktQl3 z2@pz%A)(n7QNa;KMFbnjpojyGj)066Q7jCK3fKqaA)=0hqlk*i`{8?|Yu3E?=FR@K z*FNX0^PRKL2fzpnmPj*EHGmAMLLL#|gU7_i;p8qrfeIvW01ybXWFd3?BLM*Temp!Y zBESc}00DT@3kU$fO`E_l9Ebl8>Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RZ0Rs&U1aU5SrT_o}4M{{n zR7l6YmNAPOK@`XTGrLQ6WwBb$Vo}I95DbDv3LDwRG9SP;MN$V0DI{EZrNyBZSH@tc zjVVNeD0d$q!3!rTf(m-as<`etFU2Ou9mpZ9o~wmN5n)1nj%JuR@6PkEf@LjUubnN;XaNJeSMGHBG}){URb< zU0%Mb)oL>UrHvx4=c$HaM8e_l&S;{s7&zz813lqH0MU9M{;uZ%Lfi&=0wM+?_LuQf zgZxcGFt!R5A1v(QAzHCivTE`3 zrfI&6Mx*hIi;G{yV)1Ri-~Tioj{yL-Z9~^}*tQMZw*8*vy3jNYk|b?^PyEipJ;N|g zvf1qWYPEXSY&OrP)9KHLlO#z35&g5^@F%`BKK=jz002ovPDHLkV1i?QCl3Gs literal 0 HcmV?d00001 diff --git a/tester/Makefile.am b/tester/Makefile.am index 4388ac483..ba8432bfa 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -23,11 +23,11 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi -LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) +LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) AM_LDFLAGS=$(CUNIT_LIBS) -AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) +AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) test: liblinphone_tester ./liblinphone_tester --config $(abs_srcdir) From e022b0d3ff20d7115c366d8b31f90fb402fbeab8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:34:03 +0100 Subject: [PATCH 03/32] Add Android wrapper for RFC3994. --- build/android/Android.mk | 3 ++- coreapi/linphonecore_jni.cc | 22 +++++++++++++++++++ .../org/linphone/core/LinphoneChatRoom.java | 11 ++++++++++ .../linphone/core/LinphoneCoreListener.java | 7 ++++++ .../linphone/core/LinphoneChatRoomImpl.java | 10 +++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index e9c9fa1f6..9263f748f 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -60,7 +60,8 @@ LOCAL_SRC_FILES := \ linphone_tunnel_config.c \ message_storage.c \ info.c \ - event.c + event.c \ + xml.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4dc3b6d04..a1f428b4a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -170,6 +170,7 @@ public: vTable.call_encryption_changed = callEncryptionChange; vTable.text_received = text_received; vTable.message_received = message_received; + vTable.is_composing_received = is_composing_received; vTable.dtmf_received = dtmf_received; vTable.new_subscription_requested = new_subscription_requested; vTable.notify_presence_received = notify_presence_received; @@ -225,6 +226,7 @@ public: /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); + isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V"); dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V"); @@ -307,6 +309,7 @@ public: jmethodID notifyPresenceReceivedId; jmethodID textReceivedId; jmethodID messageReceivedId; + jmethodID isComposingReceivedId; jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; jmethodID transferStateId; @@ -550,6 +553,19 @@ public: ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); } + static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->isComposingReceivedId + ,lcData->core + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)); + } static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); @@ -2311,6 +2327,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv ,jlong ptr) { linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_compose(JNIEnv *env, jobject thiz, jlong ptr) { + linphone_chat_room_compose((LinphoneChatRoom *)ptr); +} +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_isRemoteComposing(JNIEnv *env, jobject thiz, jlong ptr) { + return (jboolean)linphone_chat_room_is_remote_composing((LinphoneChatRoom *)ptr); +} extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env ,jobject thiz ,jlong room diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index 5c87f5647..e84538269 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -80,6 +80,17 @@ public interface LinphoneChatRoom { * Deletes all the messages associated with the peer of this chat room */ void deleteHistory(); + + /** + * Notify the destination of the chat message being composed that the user is typing a new message. + */ + void compose(); + + /** + * Tells whether the remote is currently composing a message. + * @return true if the remote is currently composing a message, false otherwise. + */ + boolean isRemoteComposing(); /** * Marks all the messages in this conversation as read diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 60e9e3d59..d01fa01a7 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -91,6 +91,13 @@ public interface LinphoneCoreListener { */ void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message); + /** + * invoked when a composing notification is received + * @param lc LinphoneCore + * @param room LinphoneChatRoom involved in the conversation. + */ + void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr); + /** * invoked when a new dtmf is received * @param lc LinphoneCore diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 7f4d684ee..c2021e379 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -31,6 +31,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native void destroy(long ptr); private native int getUnreadMessagesCount(long ptr); private native void deleteHistory(long ptr); + private native void compose(long ptr); + private native boolean isRemoteComposing(long ptr); private native void markAsRead(long ptr); private native void deleteMessage(long room, long message); private native void updateUrl(long room, long message); @@ -87,6 +89,14 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void deleteHistory() { deleteHistory(nativePtr); } + + public void compose() { + compose(nativePtr); + } + + public boolean isRemoteComposing() { + return isRemoteComposing(nativePtr); + } public void markAsRead() { markAsRead(nativePtr); From 452b004655fb9e7e4a4586896ee321121b9f1e57 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:01:11 +0100 Subject: [PATCH 04/32] Add CMakeLists.txt to compile using cmake. --- CMakeLists.txt | 57 ++++++++++++++++++++++ coreapi/CMakeLists.txt | 99 ++++++++++++++++++++++++++++++++++++++ share/CMakeLists.txt | 17 +++++++ share/rings/CMakeLists.txt | 4 ++ 4 files changed, 177 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 coreapi/CMakeLists.txt create mode 100644 share/CMakeLists.txt create mode 100644 share/rings/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7af5d50ac --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 2.6) +project(LINPHONE C) + +if(NOT ORTP_ROOT_DIR) + set(ORTP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/oRTP) +endif() +if(NOT ORTP_INCLUDE_DIR) + set(ORTP_INCLUDE_DIR ${ORTP_ROOT_DIR}/include) +endif() +if(NOT MS2_ROOT_DIR) + set(MS2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mediastreamer2) +endif() +if(NOT MS2_INCLUDE_DIR) + set(MS2_INCLUDE_DIR ${MS2_ROOT_DIR}/include) +endif() +if(NOT LIBXML2_ROOT_DIR) + set(LIBXML2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libxml2) +endif() +if(NOT LIBXML2_INCLUDE_DIR) + set(LIBXML2_INCLUDE_DIR ${LIBXML2_ROOT_DIR}/include) +endif() +if(NOT BELLESIP_ROOT_DIR) + set(BELLESIP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../belle-sip) +endif() +if(NOT BELLESIP_INCLUDE_DIR) + set(BELLESIP_INCLUDE_DIR ${BELLESIP_ROOT_DIR}/include) +endif() + +include_directories( + include/ + coreapi/ + ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ +) + +if(USE_INSTALLED_COMPONENTS) + include_directories( + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/libxml2 + ) +else() + include_directories( + ${ORTP_INCLUDE_DIR} + ${MS2_INCLUDE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${BELLESIP_INCLUDE_DIR} + ) + if(WIN32) + include_directories(${ORTP_ROOT_DIR}/build/vsx/oRTP/oRTP/) + endif(WIN32) +endif() + +add_subdirectory(coreapi) +add_subdirectory(share) + +if(INSTALL_COMPONENT_IN_POSTBUILD) + add_install_target(INSTALL_liblinphone COMP_liblinphone liblinphone) +endif() diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt new file mode 100644 index 000000000..a007317c5 --- /dev/null +++ b/coreapi/CMakeLists.txt @@ -0,0 +1,99 @@ +set(SOURCE_FILES + address.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 + callbacks.c + chat.c + conference.c + ec-calibrator.c + enum.c + event.c + friend.c + info.c + linphonecall.c + linphonecore.c + #linphone_tunnel.cc + linphone_tunnel_stubs.c + linphone_tunnel_config.c + lpconfig.c + lsd.c + message_storage.c + misc.c + offeranswer.c + presence.c + proxy.c + sal.c + siplogin.c + sipsetup.c + #TunnelManager.cc + bellesip_sal/sal_impl.h + enum.h + event.h + linphonecore.h + linphonecore_utils.h + linphonefriend.h + linphone_tunnel.h + lpconfig.h + offeranswer.h + private.h + sipsetup.h +) + +add_definitions( + -D_TRUE_TIME + -DIN_LINPHONE + -DUSE_BELLESIP + #-DTUNNEL_ENABLED + #-DVIDEO_ENABLED + -DLINPHONE_PACKAGE_NAME="linphone" + -DLINPHONE_VERSION="Devel" + -DLIBLINPHONE_EXPORTS + -DLINPHONE_PLUGINS_DIR="" +) + +if(WIN32) +add_definitions( + -DWINDOW_NATIVE +) + +set(LIBS ws2_32) +endif(WIN32) +set(LIBS ${LIBS} libortp libmediastreamer_base libmediastreamer_voip libbellesip libxml2) + +add_library(liblinphone SHARED ${SOURCE_FILES}) +set_target_properties(liblinphone PROPERTIES VERSION 3.6.99 SOVERSION 5) + +target_link_libraries(liblinphone ${LIBS}) + +install(TARGETS liblinphone + COMPONENT COMP_liblinphone + DESTINATION ${LIB_INSTALL_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +if(USE_INSTALLED_COMPONENTS) + add_dependencies(liblinphone + INSTALL_libortp + INSTALL_libmediastreamer2 + INSTALL_libbellesip + INSTALL_libxml2) +endif() + + + +file(GLOB HEADER_FILES "*.h") + +install(FILES ${HEADER_FILES} + COMPONENT COMP_liblinphone + DESTINATION include/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt new file mode 100644 index 000000000..8d15a6f5c --- /dev/null +++ b/share/CMakeLists.txt @@ -0,0 +1,17 @@ +install(FILES archived-rootca.pem + RENAME rootca.pem + COMPONENT COMP_liblinphone + DESTINATION share/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +install(FILES ringback.wav + COMPONENT COMP_liblinphone + DESTINATION share/sounds/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +add_subdirectory(rings) + +install(FILES ../mediastreamer2/src/voip/nowebcamCIF.jpg + COMPONENT COMP_liblinphone + DESTINATION share/images + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) diff --git a/share/rings/CMakeLists.txt b/share/rings/CMakeLists.txt new file mode 100644 index 000000000..cf359bb4e --- /dev/null +++ b/share/rings/CMakeLists.txt @@ -0,0 +1,4 @@ +install(FILES oldphone.wav toy-mono.wav + COMPONENT COMP_liblinphone + DESTINATION share/sounds/linphone/rings + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) From d57e2b3cb7e69e44eb32e9a60dfe6a5f6237120e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:27:55 +0100 Subject: [PATCH 05/32] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4103f0b1d..cd4838bc3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4103f0b1d7757558d06e6e32b657308bb2556c9b +Subproject commit cd4838bc3ec1921ddab8e25b8101c53bedbef00c diff --git a/oRTP b/oRTP index 37b81a118..db393f57c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 37b81a118760caa22a5a89d56945acea9aa52523 +Subproject commit db393f57ca12744f783b9e51776ea8897ba242d1 From d43eb3788e66f2007368e6f72f88db9a208c920f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Jan 2014 17:32:42 +0100 Subject: [PATCH 06/32] Fix liblinphone wp8 build --- build/vsx/LibLinphone/LibLinphone.vcxproj | 5 +++-- coreapi/linphonecall.c | 9 ++++++++- coreapi/linphonecore.h | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index c2d421126..9bc9aadf9 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -117,7 +117,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) false Default NotUsing @@ -147,7 +147,7 @@ Level4 $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) true true Default @@ -207,6 +207,7 @@ + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4510ef12f..aa19496ce 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2572,6 +2572,13 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } +AudioStream* linphone_call_get_audiostream(LinphoneCall* call) { + return call->audiostream; +} + +VideoStream* linphone_call_get_videostream(LinphoneCall* call) { + return call->videostream; +} /** * Perform a zoom of the video displayed during a call. @@ -2688,4 +2695,4 @@ void linphone_call_set_contact_op(LinphoneCall* call) { sal_op_set_contact(call->op, contact); linphone_address_destroy(contact); } -} +} \ No newline at end of file diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4aa4d0942..4b97eaf88 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "ortp/payloadtype.h" #include "mediastreamer2/mscommon.h" #include "mediastreamer2/msvideo.h" +#include "mediastreamer2/mediastream.h" #ifdef IN_LINPHONE #include "sipsetup.h" @@ -580,7 +581,6 @@ struct _LinphoneCallStats { LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); - /** Callback prototype */ typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); @@ -652,6 +652,9 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); +LINPHONE_PUBLIC AudioStream * linphone_call_get_audiostream(LinphoneCall *call); +LINPHONE_PUBLIC VideoStream * linphone_call_get_videostream(LinphoneCall *call); + /** * Return TRUE if this call is currently part of a conference * @param call #LinphoneCall From be96cb432e8ec0f821b9bc45402b34a001a97d21 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Jan 2014 11:48:27 +0100 Subject: [PATCH 07/32] Reverted previous commit and added call stats functions to linphone API --- coreapi/linphonecall.c | 113 ++++++++++++++++++++++++++++++++++++++--- coreapi/linphonecore.h | 7 ++- 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index aa19496ce..17d8a8ede 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2247,6 +2247,111 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } +float linphone_call_stats_update_sender_loss_rate(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; + return 100.0 * report_block_get_fraction_lost(srb) / 256.0; +} + +float linphone_call_stats_update_receiver_loss_rate(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_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) + return 0.0; + return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; +} + +float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *srb = NULL; + + if (!stats || !call || !stats->sent_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + 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->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; +} + +float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *rrb = NULL; + + if (!stats || !call || !stats->received_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + 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->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; +} + +uint64_t linphone_call_stats_update_late_packets_cumulative_number(LinphoneCallStats *stats, LinphoneCall *call) { + rtp_stats_t rtp_stats; + + if (!stats || !call) + return 0; + memset(&rtp_stats, 0, sizeof(rtp_stats)); + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats); +#ifdef VIDEO_ENABLED + else + video_stream_get_local_rtp_stats(call->videostream, &rtp_stats); +#endif + return rtp_stats.outoftime; +} + /** * Enable recording of the call (voice-only). * This function must be used before the call parameters are assigned to the call. @@ -2572,14 +2677,6 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } -AudioStream* linphone_call_get_audiostream(LinphoneCall* call) { - return call->audiostream; -} - -VideoStream* linphone_call_get_videostream(LinphoneCall* call) { - return call->videostream; -} - /** * Perform a zoom of the video displayed during a call. * @param call the call. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4b97eaf88..83fa35994 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -580,6 +580,11 @@ struct _LinphoneCallStats { LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call); /** Callback prototype */ typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); @@ -652,8 +657,6 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); -LINPHONE_PUBLIC AudioStream * linphone_call_get_audiostream(LinphoneCall *call); -LINPHONE_PUBLIC VideoStream * linphone_call_get_videostream(LinphoneCall *call); /** * Return TRUE if this call is currently part of a conference From 58d9e149cd939795c17f184b11af2281cebc5155 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:08:56 +0100 Subject: [PATCH 08/32] Fix compilation with cmake. --- coreapi/CMakeLists.txt | 1 + mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index a007317c5..74e80dfc0 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -37,6 +37,7 @@ set(SOURCE_FILES siplogin.c sipsetup.c #TunnelManager.cc + xml.c bellesip_sal/sal_impl.h enum.h event.h diff --git a/mediastreamer2 b/mediastreamer2 index cd4838bc3..7451aeb8a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit cd4838bc3ec1921ddab8e25b8101c53bedbef00c +Subproject commit 7451aeb8a2ff0d709949b671a06a8ebd287c81b5 From a3f096723623378248160c045f9c7af40779fb46 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:42:34 +0100 Subject: [PATCH 09/32] Add missing is_composing_received callback when a text message is received. --- coreapi/chat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index ddb6ba262..186aa111f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -198,7 +198,10 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, //legacy API if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message); if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg); - + if (cr->lc->vtable.is_composing_received != NULL) { + cr->remote_is_composing = LinphoneIsComposingIdle; + cr->lc->vtable.is_composing_received(cr->lc, cr); + } } /** From aeb99d09d9a963e9c4f669b1dbf0f2c86e0088c6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:45:21 +0100 Subject: [PATCH 10/32] Fix compilation (missing const keywords). --- coreapi/linphonecall.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 17d8a8ede..19d4eaa96 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2247,7 +2247,7 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } -float linphone_call_stats_update_sender_loss_rate(LinphoneCallStats *stats) { +float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats) { const report_block_t *srb = NULL; if (!stats || !stats->sent_rtcp) @@ -2264,7 +2264,7 @@ float linphone_call_stats_update_sender_loss_rate(LinphoneCallStats *stats) { return 100.0 * report_block_get_fraction_lost(srb) / 256.0; } -float linphone_call_stats_update_receiver_loss_rate(LinphoneCallStats *stats) { +float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats) { const report_block_t *rrb = NULL; if (!stats || !stats->received_rtcp) @@ -2281,7 +2281,7 @@ float linphone_call_stats_update_receiver_loss_rate(LinphoneCallStats *stats) { return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; } -float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { +float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *srb = NULL; @@ -2309,7 +2309,7 @@ float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *s return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; } -float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { +float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *rrb = NULL; @@ -2337,7 +2337,7 @@ float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; } -uint64_t linphone_call_stats_update_late_packets_cumulative_number(LinphoneCallStats *stats, LinphoneCall *call) { +uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) { rtp_stats_t rtp_stats; if (!stats || !call) From 13ac82f0663e2c9054852971481a3fe92f26868e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Jan 2014 16:18:58 +0100 Subject: [PATCH 11/32] Fixed tutorials for android --- .../org/linphone/core/tutorials/TutorialBuddyStatus.java | 6 ++++++ .../org/linphone/core/tutorials/TutorialChatRoom.java | 8 ++++++++ .../org/linphone/core/tutorials/TutorialHelloWorld.java | 6 ++++++ .../org/linphone/core/tutorials/TutorialRegistration.java | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index 53b9331fb..c41ca2933 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -280,5 +280,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 371b9af8e..3278c990d 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -202,5 +202,13 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + if (cr.isRemoteComposing()) + write("Remote is writing a message"); + else + write("Remote has stop writing"); + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index e8ba341ad..763e18f12 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -206,5 +206,11 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 93aa87d04..8384ed16e 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -237,6 +237,12 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // TODO Auto-generated method stub + + } + } From 95246f5161d047163e1afd2e967244da6725b9a1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 6 Jan 2014 16:34:19 +0100 Subject: [PATCH 12/32] fix problem with media encryption not set in params for incoming calls --- coreapi/linphonecall.c | 39 +++++++++++---------------------------- coreapi/linphonecore.c | 22 +++++++++++++--------- coreapi/private.h | 1 + 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 19d4eaa96..755260efe 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -595,9 +595,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro 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, srtp . + */ /*set privacy*/ call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); - + /*set video support */ md=sal_call_get_remote_media_description(op); call->params.has_video &= !!lc->video_policy.automatically_accept; if (md) { @@ -605,6 +610,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } + /*Init encryption support*/ + if (call->params.media_encryption==LinphoneMediaEncryptionSRTP && md){ + if (!linphone_core_media_description_has_srtp(md)) call->params.media_encryption=LinphoneMediaEncryptionNone; + } + switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: call->ice_session = ice_session_new(); @@ -2712,28 +2722,16 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } -#ifndef USE_BELLESIP -static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#else static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#endif LinphoneAddress *ctt=NULL; -#ifdef USE_BELLESIP LinphoneAddress *ret=NULL; -#else - char* ret; -#endif 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)); - #ifdef USE_BELLESIP ret=ctt; - #else - ret=linphone_address_as_string(ctt); - #endif } else if (call->op && sal_op_get_contact(call->op)!=NULL){ /* if already choosed, don't change it */ return NULL; @@ -2741,19 +2739,11 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , /* 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*/); -#ifdef USE_BELLESIP ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; -#else - ret=ms_strdup(sal_op_get_contact(call->ping_op)); -#endif } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(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*/); -#ifdef USE_BELLESIP ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); -#else - ret=ms_strdup(sal_op_get_contact(dest_proxy->op)); -#endif } else { ctt=linphone_core_get_primary_contact_parsed(lc); if (ctt!=NULL){ @@ -2761,16 +2751,9 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , linphone_address_set_domain(ctt,localip); linphone_address_set_port(ctt,linphone_core_get_sip_port(lc)); ms_message("Contact has been fixed using local ip"/* to %s",ret*/); -#ifdef USE_BELLESIP ret=ctt; -#else - ret=linphone_address_as_string_uri_only(ctt); -#endif } } -#ifndef USE_BELLESIP - if (ctt) linphone_address_destroy(ctt); -#endif return ret; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f4773e111..4bebd832a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2873,17 +2873,21 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } -bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ - if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ - int i; - for(i=0;in_active_streams;i++){ - SalStreamDescription *sd=&md->streams[i]; - if (sd->proto!=SalProtoRtpSavp){ - return TRUE; - } +bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){ + int i; + if (md->n_active_streams==0) return FALSE; + + for(i=0;in_active_streams;i++){ + const SalStreamDescription *sd=&md->streams[i]; + if (sd->proto!=SalProtoRtpSavp){ + return FALSE; } } - return FALSE; + return TRUE; +} + +bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ + return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !linphone_core_media_description_has_srtp(md); } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ diff --git a/coreapi/private.h b/coreapi/private.h index 012484c1d..3ce58499f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -320,6 +320,7 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call); void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); +bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); From 041e20edfb01f56bbbd03aef184822590455c9f4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 6 Jan 2014 23:24:00 +0100 Subject: [PATCH 13/32] * fix incorrect behavior when the body of an INVITE cannot be understood or parsed. Previously it was answering 200Ok. * do not send 415 but 488 in case of incompatible codecs, which is more correct according to the RFC. 415 should be replied if the body cannot be understood (for example: is not application/sdp) --- coreapi/bellesip_sal/sal_op_call.c | 86 ++++++++++++++++++++++-------- coreapi/bellesip_sal/sal_op_impl.c | 6 +-- coreapi/callbacks.c | 3 +- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 5 +- coreapi/misc.c | 16 +++--- coreapi/sal.c | 2 +- include/sal/sal.h | 6 +-- tester/call_tester.c | 44 +++++++++++++-- tester/liblinphone_tester.c | 2 + 10 files changed, 125 insertions(+), 47 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index a286001b2..024cf5313 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" +static int extract_sdp(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){ @@ -84,8 +86,8 @@ static void sdp_process(SalOp *h){ } } } - } + 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; @@ -159,10 +161,13 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - if (op->base.local_media) sdp_process(op); + SalReason reason; + if (extract_sdp(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 (op->base.local_media) sdp_process(op); + }/*if no sdp in response, what can we do ?*/ } } @@ -322,15 +327,46 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio return; } -static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { +/* + * 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(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { + belle_sip_header_content_type_t* 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(belle_sip_message_get_body(message)); + 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 process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { belle_sdp_session_description_t* sdp; - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) { - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - belle_sip_object_unref(sdp); - }else - op->sdp_offering=TRUE; + SalReason reason; + if (extract_sdp(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); + belle_sip_object_unref(sdp); + }else op->sdp_offering=TRUE; /*INVITE without SDP*/ + return 0; + }else{ + sal_call_decline(op,reason,NULL); + return -1; + } } static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { @@ -415,13 +451,18 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t /*great ACK received*/ if (strcmp("ACK",belle_sip_request_get_method(req))==0) { if (op->sdp_offering){ - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))){ - 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); + SalReason reason; + if (extract_sdp(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."); + } } } /*FIXME @@ -445,9 +486,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_media_description_unref(op->result); op->result=NULL; } - process_sdp_for_invite(op,req); - - op->base.root->callbacks.call_updating(op); + if (process_sdp_for_invite(op,req)==0) + op->base.root->callbacks.call_updating(op); } else if (strcmp("INFO",belle_sip_request_get_method(req))==0){ if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 47958ac6e..51dec9b01 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -334,7 +334,7 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonForbidden: ret=403; break; - case SalReasonMedia: + case SalReasonUnsupportedContent: ret=415; break; case SalReasonNotFound: @@ -356,7 +356,7 @@ SalReason sal_reason_to_sip_code(SalReason r){ ret=401; break; case SalReasonNotAcceptable: - ret=488; + ret=488; /*or maybe 606 Not Acceptable ?*/ break; case SalReasonNoMatch: ret=481; @@ -385,7 +385,7 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal break; case 415: *sal_err=SalErrorFailure; - *sal_reason=SalReasonMedia; + *sal_reason=SalReasonUnsupportedContent; break; case 422: ms_error ("422 not implemented yet");; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 3ebce7488..c2c382114 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -612,7 +612,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.display_status) lc->vtable.display_status(lc,msg600); break; - case SalReasonMedia: + case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && !linphone_core_is_media_encryption_mandatory(lc)) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4bebd832a..a378f8366 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2903,7 +2903,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ md=sal_call_get_final_media_description(call->op); if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ - sal_call_decline(call->op,SalReasonMedia,NULL); + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); linphone_call_stop_media_streams(call); linphone_core_del_call(lc,call); linphone_call_unref(call); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 83fa35994..7358159a9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -167,7 +167,7 @@ enum _LinphoneReason{ LinphoneReasonNotFound, /**lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); - /*flexisip will retain the 415 until the "urgent reply" timeout arrives.*/ + /*flexisip will retain the 488 until the "urgent reply" timeout arrives.*/ CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,6000)); - CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonMedia); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); linphone_call_unref(out_call); @@ -1387,6 +1387,41 @@ static void call_established_with_rejected_reinvite(void) { linphone_core_manager_destroy(pauline); } +static void call_established_with_rejected_incoming_reinvite(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + /*wait for ACK to be transmitted before going to reINVITE*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + linphone_core_update_call(marie->lc + ,linphone_core_get_current_call(marie->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(marie->lc)),LinphoneReasonNotAcceptable); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_established_with_rejected_reinvite_with_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1399,8 +1434,8 @@ static void call_established_with_rejected_reinvite_with_error(void) { sal_enable_unconditional_answer(marie->lc->sal,TRUE); linphone_core_update_call( pauline->lc - ,linphone_core_get_current_call(pauline->lc) - ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -1460,6 +1495,7 @@ test_t call_tests[] = { { "Call with custom headers",call_with_custom_headers}, { "Call established with rejected INFO",call_established_with_rejected_info}, { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, + { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error} }; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 910cb43b3..a5be38d65 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -136,9 +136,11 @@ bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int va ms_list_free(lcs); return result; } + bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { return wait_for_until(lc_1, lc_2,counter,value,3000); } + bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; MSList* iterator; From dbc88dbbdf31016bac49092aaf8328448c0f2726 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 10:31:37 +0100 Subject: [PATCH 14/32] fix make distcheck --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 8f1c5d3a6..96893ed99 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -27,6 +27,7 @@ gtk/loginframe.c [type: gettext/glade]gtk/call_statistics.ui [type: gettext/glade]gtk/tunnel_config.ui [type: gettext/glade]gtk/keypad.ui +[type: gettext/glade]gtk/ldap.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c From abb7c2d50c948f4ef8715b6d58f0e8eeb43e7845 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Jan 2014 11:45:01 +0100 Subject: [PATCH 15/32] Improved composing_received to prevent loosing the information if the chatroom doesn't exists --- coreapi/chat.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 186aa111f..ee6d66d3c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -336,14 +336,10 @@ static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const c } void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { - LinphoneChatRoom *cr = NULL; - LinphoneAddress *addr = linphone_address_new(is_composing->from); - linphone_address_clean(addr); - cr = linphone_core_get_chat_room(lc, addr); + LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from); if (cr != NULL) { linphone_chat_room_notify_is_composing(cr, is_composing->text); } - linphone_address_destroy(addr); } bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { From fa421af04a2ff4f25f86bef28c3a82ca8062aa1c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 14:40:54 +0100 Subject: [PATCH 16/32] fix problem with SRTP proposed during pauses (by GTK app, due to the use of linphone_core_accept_call_with_params()). --- coreapi/linphonecall.c | 35 +++++++++++++++-------------------- coreapi/linphonecore.c | 1 + 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 755260efe..b386a3e33 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -598,7 +598,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /* * 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, srtp . + * end apparently does not support. This features are: privacy, video */ /*set privacy*/ call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); @@ -610,10 +610,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } - /*Init encryption support*/ - if (call->params.media_encryption==LinphoneMediaEncryptionSRTP && md){ - if (!linphone_core_media_description_has_srtp(md)) call->params.media_encryption=LinphoneMediaEncryptionNone; - } switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: @@ -1770,21 +1766,20 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna /* valid local tags are > 0 */ if (stream->proto == SalProtoRtpSavp) { - local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalAudio); - crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); - if (crypto_idx >= 0) { - audio_stream_enable_srtp( - call->audiostream, - stream->crypto[0].algo, - local_st_desc->crypto[crypto_idx].master_key, - stream->crypto[0].master_key); - call->audiostream_encrypted=TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - call->audiostream_encrypted=FALSE; - } + if (crypto_idx >= 0) { + audio_stream_enable_srtp( + call->audiostream, + stream->crypto[0].algo, + local_st_desc->crypto[crypto_idx].master_key, + stream->crypto[0].master_key); + call->audiostream_encrypted=TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); + call->audiostream_encrypted=FALSE; + } }else call->audiostream_encrypted=FALSE; if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ @@ -1939,7 +1934,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut params.zid_file=lc->zrtp_secrets_cache; audio_stream_enable_zrtp(call->audiostream,¶ms); - }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){ + }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a378f8366..9f90061ec 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3329,6 +3329,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, linphone_call_set_state(call,LinphoneCallConnected,"Connected"); new_md=sal_call_get_final_media_description(call->op); linphone_core_update_streams(lc, call, new_md); + linphone_call_fix_call_parameters(call); if (new_md){ linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); }else call->media_pending=TRUE; From c2ca9f8c089b1b6ed8e7bc1f2bfa8d5a5defc524 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 16:17:07 +0100 Subject: [PATCH 17/32] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 7451aeb8a..2307fb760 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7451aeb8a2ff0d709949b671a06a8ebd287c81b5 +Subproject commit 2307fb7601299bb4f5c74b0984385eaf60a86b3e From 4e82aa626b4b54adc12d493b9ac5adb08ce5c39c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 8 Jan 2014 12:06:36 +0100 Subject: [PATCH 18/32] better checking of incoming SDP, in order to avoid accept things we cannot support. --- coreapi/bellesip_sal/sal_op_call.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 024cf5313..e6c7229f4 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -352,21 +352,36 @@ static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_descriptio return 0; } +static int is_media_description_acceptable(SalMediaDescription *md){ + if (md->n_total_streams==0){ + ms_warning("Media description does not define any stream."); + return FALSE; + } + return TRUE; +} + static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { belle_sdp_session_description_t* sdp; + int err=0; SalReason reason; if (extract_sdp(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)){ + err=-1; + reason=SalReasonNotAcceptable; + } belle_sip_object_unref(sdp); }else op->sdp_offering=TRUE; /*INVITE without SDP*/ - return 0; - }else{ + }else err=-1; + + if (err==-1){ sal_call_decline(op,reason,NULL); - return -1; } + return err; } static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { From e7edbcd8e803fd114548f6c3a6d9a33967a21607 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Jan 2014 12:39:09 +0100 Subject: [PATCH 19/32] Add LinphoneTransportType enum documentation to the linphone_address group. --- coreapi/linphonecore.h | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7358159a9..14d4ff057 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -95,6 +95,7 @@ typedef struct _LCSipTransports{ /** * Enum describing transport type for LinphoneAddress. + * @ingroup linphone_address **/ enum _LinphoneTransportType{ LinphoneTransportUdp, From ac4348f800acfd1923624febd1055228b11a5b49 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 8 Jan 2014 17:42:39 +0100 Subject: [PATCH 20/32] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2307fb760..98c240f78 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2307fb7601299bb4f5c74b0984385eaf60a86b3e +Subproject commit 98c240f782a04db0cca32656635f5674eb933fd7 From ae6948ded397324c5c5194e0d91d2f27c8f96c55 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 9 Jan 2014 09:36:33 +0100 Subject: [PATCH 21/32] Moved belle sip object includes into private.h --- coreapi/contact_providers_priv.h | 2 +- coreapi/contactprovider.c | 3 +-- coreapi/linphonecore.h | 15 -------------- coreapi/private.h | 34 ++++++++++++++++++++++---------- gtk/main.c | 2 +- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/coreapi/contact_providers_priv.h b/coreapi/contact_providers_priv.h index 41b7bd327..b3d667df6 100644 --- a/coreapi/contact_providers_priv.h +++ b/coreapi/contact_providers_priv.h @@ -17,7 +17,7 @@ #ifndef CONTACT_PROVIDERS_PRIV_H #define CONTACT_PROVIDERS_PRIV_H -#include +#include "private.h" #include "linphonecore.h" /* Base for contact search and contact provider */ diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index cd40887b1..2ee037c78 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -59,7 +59,7 @@ int linphone_contact_search_compare(const void* a, const void* b) { return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise } -LinphoneContactSearch*linphone_ldap_contact_search_ref(void* obj) +LinphoneContactSearch*linphone_contact_search_ref(void* obj) { return LINPHONE_CONTACT_SEARCH(belle_sip_object_ref(obj)); } @@ -136,4 +136,3 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider) NULL, /* begin_search -> pure virtual */ NULL /* cancel_search -> pure virtual */ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END - diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 14d4ff057..b6532e2f2 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -33,9 +33,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" -#include -#include - #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 @@ -2235,18 +2232,6 @@ LINPHONE_PUBLIC int linphone_core_get_video_dscp(const LinphoneCore *lc); LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername); - -/** Belle Sip-based objects need unique ids - */ - -BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) -BELLE_SIP_TYPE_ID(LinphoneContactSearch), -BELLE_SIP_TYPE_ID(LinphoneContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) -BELLE_SIP_DECLARE_TYPES_END - - /** Contact Providers */ diff --git a/coreapi/private.h b/coreapi/private.h index 3ce58499f..297535c34 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -34,6 +34,9 @@ extern "C" { #include "sal/sal.h" #include "sipsetup.h" +#include +#include + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -201,22 +204,22 @@ struct _LinphoneCall 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; - + bool_t refer_pending; bool_t media_pending; 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 owns_call_log; bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/ - + bool_t videostream_encrypted; bool_t audiostream_encrypted; bool_t auth_token_verified; bool_t defer_update; - + bool_t was_automatically_paused; bool_t ping_replied; bool_t record_active; @@ -381,9 +384,9 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); static const int linphone_proxy_config_magic=0x7979; -/*chat*/ +/*chat*/ void linphone_chat_message_destroy(LinphoneChatMessage* msg); -/**/ +/**/ struct _LinphoneProxyConfig { @@ -447,7 +450,7 @@ struct _LinphoneChatRoom{ }; - + struct _LinphoneFriend{ LinphoneAddress *uri; SalOp *insub; @@ -499,7 +502,7 @@ typedef struct rtp_config int nortp_timeout; int disable_upnp; bool_t rtp_no_xmit_on_audio_mute; - /* stop rtp xmit when audio muted */ + /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; bool_t video_adaptive_jitt_comp_enabled; bool_t pad; @@ -645,12 +648,12 @@ struct _LinphoneCore 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 network_reachable; bool_t use_preview_window; - + time_t network_last_check; bool_t network_last_status; @@ -829,6 +832,17 @@ void linphone_free_xml_text_content(const char *text); xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +/** Belle Sip-based objects need unique ids + */ + +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_TYPES_END + + #ifdef __cplusplus } #endif diff --git a/gtk/main.c b/gtk/main.c index e47af7f3a..a7de9323b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -847,7 +847,7 @@ static gboolean launch_contact_provider_search(void *userdata) ); if(search) - belle_sip_object_ref(search); + linphone_contact_search_ref(search); } return FALSE; } From 996a6a0d0f8c48f60bf33cfa6866af2ddd79f0d5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Jan 2014 11:13:36 +0100 Subject: [PATCH 22/32] Add LinphoneTransportType typedef documentation to the linphone_address group. --- coreapi/linphonecore.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b6532e2f2..0ad6030da 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -102,6 +102,10 @@ enum _LinphoneTransportType{ }; /*this enum MUST be kept in sync with the SalTransport from sal.h*/ +/** + * Typedef for transport type enum. + * @ingroup linphone_address +**/ typedef enum _LinphoneTransportType LinphoneTransportType; /** From 71e654ad95ee593d802682f00391642d795900af Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 9 Jan 2014 19:00:17 +0100 Subject: [PATCH 23/32] change default dscp for video, because it is problematic on some routers to have two streams in parallel using the same dscp value. --- coreapi/linphonecore.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9f90061ec..f21f9af6e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6272,7 +6272,7 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ * **/ int linphone_core_get_video_dscp(const LinphoneCore *lc){ - return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e); + return lp_config_get_int(lc->config,"rtp","video_dscp",0); } diff --git a/mediastreamer2 b/mediastreamer2 index 98c240f78..f17f45205 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 98c240f782a04db0cca32656635f5674eb933fd7 +Subproject commit f17f4520583843757237214b54ce8770886f7752 From d124b030e271261bcd62f9e77ad1aca6c00f5ee5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 10 Jan 2014 09:35:26 +0100 Subject: [PATCH 24/32] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f17f45205..0b5210a28 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f17f4520583843757237214b54ce8770886f7752 +Subproject commit 0b5210a283397b0deacf81bf0f80fc910cfc940b From 3e09aff60514d6946e6d74b9d8e42fd87ecc5ec4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Jan 2014 11:26:39 +0100 Subject: [PATCH 25/32] Add unit test for RFC3994: is-composing notification. --- coreapi/chat.c | 15 +++++++++------ tester/liblinphone_tester.c | 1 + tester/liblinphone_tester.h | 4 +++- tester/marie_rc | 1 + tester/message_tester.c | 30 +++++++++++++++++++++++++++++- tester/pauline_rc | 1 + 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index ee6d66d3c..6dc8ae57a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -284,7 +284,7 @@ static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsin xmlXPathObjectPtr iscomposing_object; const char *state_str = NULL; const char *refresh_str = NULL; - int refresh_duration = COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT; + int refresh_duration = lp_config_get_int(cr->lc->config, "sip", "composing_remote_refresh_timeout", COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT); int i; LinphoneIsComposingState state = LinphoneIsComposingIdle; @@ -475,7 +475,8 @@ static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) { } if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) { char refresh_str[4] = { 0 }; - snprintf(refresh_str, sizeof(refresh_str), "%u", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + snprintf(refresh_str, sizeof(refresh_str), "%u", refresh_timeout); err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str); } if (err >= 0) { @@ -547,19 +548,21 @@ static int linphone_chat_room_refresh_composing(void *data, unsigned int revents } void linphone_chat_room_compose(LinphoneChatRoom *cr) { + int idle_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_idle_timeout", COMPOSING_DEFAULT_IDLE_TIMEOUT); + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); if (cr->is_composing == LinphoneIsComposingIdle) { cr->is_composing = LinphoneIsComposingActive; linphone_chat_room_send_is_composing_notification(cr); if (!cr->composing_refresh_timer) { - cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000, "composing refresh timeout"); + cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, refresh_timeout * 1000, "composing refresh timeout"); } else { - belle_sip_source_set_timeout(cr->composing_refresh_timer, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000); + belle_sip_source_set_timeout(cr->composing_refresh_timer, refresh_timeout * 1000); } if (!cr->composing_idle_timer) { - cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000, "composing idle timeout"); + cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, idle_timeout * 1000, "composing idle timeout"); } } - belle_sip_source_set_timeout(cr->composing_idle_timer, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000); + belle_sip_source_set_timeout(cr->composing_idle_timer, idle_timeout * 1000); } /** diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a5be38d65..dbbba9a46 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -191,6 +191,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; mgr->v_table.message_received=message_received; + mgr->v_table.is_composing_received=is_composing_received; mgr->v_table.new_subscription_requested=new_subscription_requested; mgr->v_table.notify_presence_received=notify_presence_received; mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 2a8e33af0..93bde611a 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -117,7 +117,8 @@ typedef struct _stats { int number_of_LinphoneMessageInProgress; int number_of_LinphoneMessageDelivered; int number_of_LinphoneMessageNotDelivered; - + int number_of_LinphoneIsComposingActiveReceived; + int number_of_LinphoneIsComposingIdleReceived; int number_of_IframeDecoded; @@ -194,6 +195,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); +void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); diff --git a/tester/marie_rc b/tester/marie_rc index d5b7d7c87..a8365e91e 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -5,6 +5,7 @@ sip_tls_port=5083 default_proxy=0 ping_with_options=0 register_only_when_network_is_up=0 +composing_idle_timeout=1 [auth_info_0] username=marie diff --git a/tester/message_tester.c b/tester/message_tester.c index c3001c226..ef0901c93 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -44,6 +44,15 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess } } +void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + stats *counters = get_stats(lc); + if (room->remote_is_composing == LinphoneIsComposingActive) { + counters->number_of_LinphoneIsComposingActiveReceived++; + } else { + counters->number_of_LinphoneIsComposingIdleReceived++; + } +} + void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { LinphoneCore* lc=(LinphoneCore*)ud; stats* counters = get_stats(lc); @@ -264,6 +273,24 @@ static void info_message_with_body(){ info_message_with_args(TRUE); } +static void is_composing_notification(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc, to); + int dummy = 0; + + ms_free(to); + linphone_chat_room_compose(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 message"); + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingActiveReceived, 1)); + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingIdleReceived, 2)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t message_tests[] = { { "Text message", text_message }, { "Text message with privacy", text_message_with_privacy }, @@ -272,7 +299,8 @@ test_t message_tests[] = { { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, { "Info message", info_message }, - { "Info message with body", info_message_with_body } + { "Info message with body", info_message_with_body }, + { "IsComposing notification", is_composing_notification } }; test_suite_t message_test_suite = { diff --git a/tester/pauline_rc b/tester/pauline_rc index 204486f66..4d01058fe 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -5,6 +5,7 @@ sip_tls_port=5073 default_proxy=0 ping_with_options=0 register_only_when_network_is_up=0 +composing_idle_timeout=1 [auth_info_0] username=pauline From 638671275f9a74e8bc2bf1ced7327e60e69c36a8 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 13 Jan 2014 16:36:51 +0100 Subject: [PATCH 26/32] Update ms2 for iOS orientation fix --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0b5210a28..d1ef7469d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0b5210a283397b0deacf81bf0f80fc910cfc940b +Subproject commit d1ef7469d0d5baf73926fb3280141f225af5de60 From e756795dceda0b10b912edd872c08b30769f4cff Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 24 Dec 2013 21:57:49 +0100 Subject: [PATCH 27/32] RPM for redhat Linphone for redhat documentaton --- build/redhat/INSTALL | 13 +++++++++++ build/redhat/README | 51 ++++++++++++++++++++++++++++++++++++++++++++ gtk/ldap.ui | 2 +- linphone.spec.in | 2 +- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 build/redhat/INSTALL create mode 100644 build/redhat/README diff --git a/build/redhat/INSTALL b/build/redhat/INSTALL new file mode 100644 index 000000000..0b43a5b51 --- /dev/null +++ b/build/redhat/INSTALL @@ -0,0 +1,13 @@ +INSTALL : + +Download and install the repo rpmforge : + http://repoforge.org/use/ + + $ sudo rpm -Uvh + +Download the linphone-release rpm + $ sudo rpm -Uvh + + $ sudo yum install linphone + + diff --git a/build/redhat/README b/build/redhat/README new file mode 100644 index 000000000..37e09e4d4 --- /dev/null +++ b/build/redhat/README @@ -0,0 +1,51 @@ +********************************** +* Compiling linphone on RedHat * +********************************** + +Download and install the repo rpmforge : + http://repoforge.org/use/ + + $ sudo rpm -Uhv + $ yum -y update + +- Install build time dependencies + $ sudo yum install libtool intltool + +- Install others dependencies + $ sudo yum install gtk2-devel + $ sudo yum install ffmpeg-devel + $ sudo yum install openldap-devel + +- Download and install packages + $ sudo rpm -Uhv ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-1.3.2-1.el6.x86_64.rpm + $ sudo rpm -Uvh ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-devel-1.3.2-1.el6.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-3.2-14.fc15.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-devel-3.2-14.fc15.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm + +- Compile Belle-sip / oRTP / mediastreamer + $ ./autogen.sh + $ ./configure + $ make && make rpm + $ sudo rpm -Uvh + +- Compile Linphone + $ ./autogen.sh + $ ./configure + $ make && make rpm + + +-Create yum repo : + $ cd rpmbuild/RPMS/*arch*/ + $ createrepo . + + Create a file "linphone-release.repo" in /etc/yum.repos.d/ with : + + [linphone-release] + name = Linphone for redhat + baseurl = file/// *path to the new repo* + enabled = 1 + gpgcheck = 0 + + $ sudo yum install linphone diff --git a/gtk/ldap.ui b/gtk/ldap.ui index ba3bf7163..a5df241d1 100644 --- a/gtk/ldap.ui +++ b/gtk/ldap.ui @@ -1,6 +1,6 @@ - + False diff --git a/linphone.spec.in b/linphone.spec.in index e8e7b68a6..728ad5151 100644 --- a/linphone.spec.in +++ b/linphone.spec.in @@ -53,7 +53,7 @@ Libraries and headers required to develop software with linphone. %if !%{video} --disable-video \ %endif - --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp + --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp --enable-ldap %__make %{?_smp_mflags} From e4dcb70b9549b53821c10bd2c6ce85471064ce4f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:07:12 +0100 Subject: [PATCH 28/32] Add generation of linphone_gitversion.h when using cmake. --- CMakeLists.txt | 1 + coreapi/CMakeLists.txt | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7af5d50ac..bc8718c0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ endif() include_directories( include/ coreapi/ + ${CMAKE_CURRENT_BINARY_DIR}/coreapi/ ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ ) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 74e80dfc0..ab83c3ce7 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -1,3 +1,38 @@ +find_program(GIT git) + +set(GIT_VERSION "unknown") +if(GIT) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} describe --always + OUTPUT_VARIABLE GIT_DESCRIBE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} describe --abbrev=0 + OUTPUT_VARIABLE GIT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} rev-parse HEAD + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(GIT_DESCRIBE) + set(GIT_VERSION ${GIT_DESCRIBE}) + else(GIT_DESCRIBE) + if(GIT_REVISION) + set(GIT_VERSION ${GIT_REVISION}) + endif(GIT_REVISION) + endif(GIT_DESCRIBE) +endif(GIT) +execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#define LIBLINPHONE_GIT_VERSION \"${GIT_VERSION}\"" + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/liblinphone_gitversion.h +) + set(SOURCE_FILES address.c authentication.c @@ -66,6 +101,7 @@ add_definitions( if(WIN32) add_definitions( -DWINDOW_NATIVE + /FIliblinphone_gitversion.h ) set(LIBS ws2_32) From 932837c3654eb73cbd0bb18b0d0f4321341a7ee8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:07:43 +0100 Subject: [PATCH 29/32] Add option to enable video when compiling using cmake. --- CMakeLists.txt | 2 ++ coreapi/CMakeLists.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8718c0d..5dea97796 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 2.6) project(LINPHONE C) +option(LINPHONE_ENABLE_VIDEO "Build linphone with video support." ON) + if(NOT ORTP_ROOT_DIR) set(ORTP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/oRTP) endif() diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index ab83c3ce7..628695414 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -98,6 +98,10 @@ add_definitions( -DLINPHONE_PLUGINS_DIR="" ) +if(LINPHONE_ENABLE_VIDEO) + add_definitions(-DVIDEO_ENABLED) +endif(LINPHONE_ENABLE_VIDEO) + if(WIN32) add_definitions( -DWINDOW_NATIVE From 69407718da449015bc7886ab831ec5ca47e56f8f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:09:54 +0100 Subject: [PATCH 30/32] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index d1ef7469d..ce1127bbf 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d1ef7469d0d5baf73926fb3280141f225af5de60 +Subproject commit ce1127bbf74a1bc1113a048195db3cf2ed49c946 diff --git a/oRTP b/oRTP index db393f57c..d42419299 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit db393f57ca12744f783b9e51776ea8897ba242d1 +Subproject commit d4241929983c8f0114f8de04dca6ecbc42b9607e From e3ab99b672b2653fabf7ecbd65b1a3dfd601d9e9 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 24 Dec 2013 23:39:06 +0100 Subject: [PATCH 31/32] Add git clone in the README --- build/redhat/README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/redhat/README b/build/redhat/README index 37e09e4d4..7831df9c8 100644 --- a/build/redhat/README +++ b/build/redhat/README @@ -24,6 +24,12 @@ Download and install the repo rpmforge : $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm +- Git repository + + Belle-sip : git clone git://git.linphone.org/belle-sip.git + oRTP : git clone git://git.linphone.org/ortp.git + Mediastreamer : git clone git://git.linphone.org/mediastreamer2.git + - Compile Belle-sip / oRTP / mediastreamer $ ./autogen.sh $ ./configure From aeb09dfcedc3b568a0ba051100389ba659aa1d28 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 14 Jan 2014 13:06:12 +0100 Subject: [PATCH 32/32] fix README --- README | 9 ++--- README.zrtp | 94 ----------------------------------------------------- 2 files changed, 5 insertions(+), 98 deletions(-) delete mode 100644 README.zrtp diff --git a/README b/README index 8913f1205..1e3e0ced0 100644 --- a/README +++ b/README @@ -44,11 +44,12 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. $ sudo make install + Install zrtpcpp (optional), for unbreakable call encryption - $ sudo apt-get install cmake libssl-dev - $ git clone git://git.linphone.org/zrtpcpp.git - $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make + $ sudo apt-get install cmake + $ git clone https://github.com/wernerd/ZRTPCPP.git + $ cd ZRTPCPP + $ cmake -DCORE_LIB=true -DSDES=false . && make $ sudo make install - + If you get this error: "cc1plus: error: unrecognized command line option ‘-std=c++11’", edit CMakeLists.txt and replace c++11 by c++0x . - Compile linphone diff --git a/README.zrtp b/README.zrtp deleted file mode 100644 index c71c8d2d7..000000000 --- a/README.zrtp +++ /dev/null @@ -1,94 +0,0 @@ -ZRTP guide - -== Downloads == -- SRTP -http://sourceforge.net/projects/srtp/ -or "apt-get source libsrtp0" on Debian - -- ZRTP (libzrtpcpp-2.0) -http://www.gnutelephony.org/index.php/GNU_ZRTP - - -== Patch libzrtpcpp == -Index: src/ZIDFile.cpp -=================================================================== ---- src/ZIDFile.cpp (révision 754) -+++ src/ZIDFile.cpp (copie de travail) -@@ -78,10 +78,11 @@ - - // create save file name, rename and re-open - // if rename fails, just unlink old ZID file and create a brand new file -- // just a little inconnvenience for the user, need to verify new SAS -+ // just a little inconvenience for the user, need to verify new SAS - std::string fn = std::string(name) + std::string(".save"); - if (rename(name, fn.c_str()) < 0) { -- unlink(name); -+ // unlink(name); - createZIDFile(name); - return; - } -Index: src/libzrtpcpp/ZrtpCallback.h -=================================================================== ---- src/libzrtpcpp/ZrtpCallback.h (révision 754) -+++ src/libzrtpcpp/ZrtpCallback.h (copie de travail) -@@ -27,7 +27,7 @@ - - #include - #include --#include -+//#include - #include - - /** -Index: src/libzrtpcpp/ZIDRecord.h -=================================================================== ---- src/libzrtpcpp/ZIDRecord.h (révision 754) -+++ src/libzrtpcpp/ZIDRecord.h (copie de travail) -@@ -33,7 +33,7 @@ - - #include - #include --#include -+//#include - - #define IDENTIFIER_LEN 12 - #define RS_LENGTH 32 -Index: CMakeLists.txt -=================================================================== ---- CMakeLists.txt (révision 754) -+++ CMakeLists.txt (copie de travail) -@@ -124,11 +124,15 @@ - if(CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-Wno-long-long -Wno-char-subscripts) - add_definitions(-Wall -ansi -pedantic) -+ add_definitions(-DNEW_STDCPP) - endif() - - add_subdirectory(src) --add_subdirectory(demo) - -+if (enable_ccrtp) -+ add_subdirectory(demo) -+endif() -+ - if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/package/) - MESSAGE(STATUS "package dir not found") - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/) - - - -== Create simlinks or move folders == -submodules/external/srtp -> path_to_your_srtp_source -submodules/external/libzrtpcpp -> path_to_your_patched_zrtpcpp_source - - - -== Compilation for Android == -ndk-build BUILD_GPLV3_ZRTP=1 -j5 - - -== Compilation for Desktop version == -First ortp: ./autogen.sh && ./configure --enable-zrtp && make -j5 && sudo make install -Then mediastreamer2: ./autogen.sh && ./configure && make -j5 && sudo make install -Finally linphone: ./autogen.sh && ./configure --enable-external-ortp && make -j5 && sudo make install -