diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 2f161c2a6..833ca8c9f 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -18,6 +18,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sal_impl.h" +#include "linphonecore.h" +#include "private.h" +#include "lime.h" +#include + static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed); @@ -59,6 +64,11 @@ static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; } + +static bool_t is_cipher_xml(belle_sip_header_content_type_t* content_type) { + return strcmp("xml",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("cipher",belle_sip_header_content_type_get_subtype(content_type))==0; +} 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; @@ -69,7 +79,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { } static void add_message_accept(belle_sip_message_t *msg){ - belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml")); + belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cipher")); } void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ @@ -85,11 +95,58 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve char* from; bool_t plain_text=FALSE; bool_t external_body=FALSE; + bool_t cipher_xml=FALSE; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + /* check if we have a xml/cipher message to be decrypted */ + uint8_t *decryptedMessage = NULL; + if (content_type && (cipher_xml=is_cipher_xml(content_type))) { + /* access the zrtp cache to get keys needed to decipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to decrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + free(cacheString); + int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage); + if (retval != 0) { + ms_warning("JOHAN: Unable to decrypt message, reason %x", retval); + free(decryptedMessage); + xmlFreeDoc(cacheXml); + resp = belle_sip_response_create_from_request(req,488); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; + } else { + ms_warning("JOHAN : Yes we did decrypt the message and it is %s", decryptedMessage); + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + } + + xmlFreeDoc(cacheXml); + } + + } if (content_type && ((plain_text=is_plain_text(content_type)) - || (external_body=is_external_body(content_type)))) { + || (external_body=is_external_body(content_type)) + || decryptedMessage!=NULL)) { SalMessage salmsg; char message_id[256]={0}; @@ -104,7 +161,7 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve ,belle_sip_header_call_id_get_call_id(call_id) ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; - salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):(cipher_xml?(char *)decryptedMessage:NULL); salmsg.url=NULL; if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); @@ -143,11 +200,12 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_process_incoming_message(op,event); } -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime=time(NULL); + uint8_t *multipartEncryptedMessage = NULL; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ @@ -165,11 +223,56 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } } + + /* shall we try to encrypt the message?*/ + if (strcmp(content_type, "xml/cipher") == 0) { + /* access the zrtp cache to get keys needed to cipher the message */ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "r+"); + ms_message("Cache file is %s", lc->zrtp_secrets_cache); + if (CACHEFD == NULL) { + ms_warning("Unable to access ZRTP ZID cache to encrypt message"); + } else { + fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ + int cacheSize = ftell(CACHEFD); /* Get file length */ + rewind(CACHEFD); /* Back to start of file */ + uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ + fread(cacheString, 1, cacheSize, CACHEFD); + cacheString[cacheSize] = '\0'; + cacheSize += 1; + fclose(CACHEFD); + xmlDocPtr cacheXml = xmlParseDoc(cacheString); + free(cacheString); + int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); + if (retval != 0) { + ms_warning("Unable to encrypt message to %s error %x", peer_uri, retval); + xmlFreeDoc(cacheXml); + free(multipartEncryptedMessage); + sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + return 0; + } else { + ms_warning("Succes in encrypting message for %s to %s", to, peer_uri); + /* dump updated cache to a string */ + xmlChar *xmlStringOutput; + int xmlStringLength; + xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); + /* write it to the cache file */ + CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); + fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); + xmlFree(xmlStringOutput); + fclose(CACHEFD); + content_length = strlen((const char *)multipartEncryptedMessage); + } + xmlFreeDoc(cacheXml); + } + } + snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); - belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); return sal_op_send_request(op,req); } @@ -186,7 +289,7 @@ int sal_message_reply(SalOp *op, SalReason reason){ } int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { - return sal_message_send(op,from,to,"text/plain",msg); + return sal_message_send(op,from,to,"text/plain",msg, NULL); } static belle_sip_listener_callbacks_t op_message_callbacks={0}; diff --git a/coreapi/chat.c b/coreapi/chat.c index 0f48e9dd4..bb231f97b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -26,10 +26,6 @@ #include "private.h" #include "lpconfig.h" -#include - -#include "lime.h" - #define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 #define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 @@ -203,54 +199,21 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0)); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ } + + if (msg->external_body_url) { content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url); - sal_message_send(op,identity,cr->peer,content_type, NULL); + sal_message_send(op,identity,cr->peer,content_type, NULL, NULL); ms_free(content_type); } else { - uint8_t *multipartEncryptedMessage = NULL; - /* shall we try to encrypt the message?*/ - if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ - /* get the zrtp cache and parse it into an xml doc */ - FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", cr->lc->zrtp_secrets_cache); - if (CACHEFD == NULL) { - ms_warning("Unable to access ZRTP ZID cache to encrypt message"); - } else { - fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ - rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ - fread(cacheString, 1, cacheSize, CACHEFD); - cacheString[cacheSize] = '\0'; - cacheSize += 1; - fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); - int retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg->message, (uint8_t *)linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), &multipartEncryptedMessage); - if (retval != 0) { - ms_warning("Unable to encrypt message to %s error %x", linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)), retval); - } - /* dump updated cache to a string */ - xmlChar *xmlStringOutput; - int xmlStringLength; - xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); - /* write it to the cache file */ - CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "w+"); - fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); - xmlFree(xmlStringOutput); - fclose(CACHEFD); - - - xmlFreeDoc(cacheXml); - } - } - if (multipartEncryptedMessage!=NULL) { - sal_text_send(op, identity, cr->peer,(const char *)multipartEncryptedMessage); - free(multipartEncryptedMessage); + if (cr->lc->lime == 1) { /* shall we try to encrypt messages? */ + linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */ + sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr))); } else { sal_text_send(op, identity, cr->peer,msg->message); } } + msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); msg->storage_id=linphone_chat_message_store(msg); @@ -306,7 +269,6 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag LinphoneChatRoom *cr=NULL; LinphoneAddress *addr; char *cleanfrom; - char *from; LinphoneChatMessage* msg; const SalCustomHeader *ch; @@ -314,53 +276,12 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag linphone_address_clean(addr); cr=linphone_core_get_chat_room(lc,addr); cleanfrom=linphone_address_as_string(addr); - from=linphone_address_as_string_uri_only(addr); if (cr==NULL){ /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - /* shall we try to decrypt the message */ - uint8_t *decryptedMessage = NULL; - if (1) { /* TODO : set a flag for message encryption into LinphoneChatRoom structure */ - /* get the zrtp cache and parse it into an xml doc */ - FILE *CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "r+"); - ms_message("Cache file is %s", lc->zrtp_secrets_cache); - if (CACHEFD == NULL) { - ms_warning("Unable to access ZRTP ZID cache to decrypt message"); - } else { - fseek(CACHEFD, 0L, SEEK_END); /* Position to end of file */ - int cacheSize = ftell(CACHEFD); /* Get file length */ - rewind(CACHEFD); /* Back to start of file */ - uint8_t *cacheString = (uint8_t *)malloc(cacheSize*sizeof(uint8_t)+1); /* string must be null terminated */ - fread(cacheString, 1, cacheSize, CACHEFD); - cacheString[cacheSize] = '\0'; - cacheSize += 1; - fclose(CACHEFD); - xmlDocPtr cacheXml = xmlParseDoc(cacheString); - int retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)(sal_msg->text), &decryptedMessage); - if (retval != 0) { - ms_warning("Unable to decrypt message error %x", retval); - } - /* dump updated cache to a string */ - xmlChar *xmlStringOutput; - int xmlStringLength; - xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); - /* write it to the cache file */ - CACHEFD = fopen(lc->zrtp_secrets_cache, "w+"); - fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD); - xmlFree(xmlStringOutput); - fclose(CACHEFD); - - xmlFreeDoc(cacheXml); - } - } - - if (decryptedMessage == NULL) { - msg = linphone_chat_room_create_message(cr, sal_msg->text); - } else { - msg = linphone_chat_room_create_message(cr, (const char *)decryptedMessage); - } + msg = linphone_chat_room_create_message(cr, sal_msg->text); linphone_chat_message_set_from(msg, cr->peer_url); @@ -384,7 +305,6 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->storage_id=linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); - ms_free(from); } static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { @@ -646,7 +566,7 @@ static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom * } content = linphone_chat_room_create_is_composing_xml(cr); if (content != NULL) { - sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content); + sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content, NULL); ms_free(content); } } diff --git a/coreapi/lime.c b/coreapi/lime.c index 7967c3ce6..0e1f90031 100644 --- a/coreapi/lime.c +++ b/coreapi/lime.c @@ -557,6 +557,11 @@ int lime_createMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t } int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_t **output) { + int retval; + + if (cacheBuffer == NULL) { + return LIME_INVALID_CACHE; + } /* retrieve selfZIDHex from cache(return a 24 char hexa string + null termination) */ uint8_t selfZidHex[25]; if (lime_getSelfZid(cacheBuffer, selfZidHex) != 0) { @@ -566,7 +571,14 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ lime_strToUint8(selfZid, selfZidHex, 24); /* parse the message into an xml doc */ - xmlDocPtr xmlEncryptedMessage = xmlParseDoc(message); + /* make sure we have a valid xml message before trying to parse it */ + if (memcmp(message, "", 38) != 0 ) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } + xmlDocPtr xmlEncryptedMessage = xmlParseDoc((const xmlChar *)message); + if (xmlEncryptedMessage == NULL) { + return LIME_INVALID_ENCRYPTED_MESSAGE; + } /* retrieve the sender ZID which is the first child of root */ limeKey_t associatedKey; @@ -588,7 +600,7 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ if (peerZidHex != NULL) { /* get from cache the matching key */ - int retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); + retval = lime_getCachedRcvKeyByZid(cacheBuffer, &associatedKey); if (retval == 0) { /* retrieve the portion of message which is encrypted with our key */ @@ -633,15 +645,34 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_ } /* shall we derive our key before going for decryption */ - if (usedSessionIndex>associatedKey.sessionIndex) { - /* TODO */ + if (usedSessionIndex < associatedKey.sessionIndex) { + /* something wen't wrong with the cache, this shall never happend */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) { + /* we missed to many messages, ask for a cache reset via a ZRTP call */ + free(encryptedMessage); + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + + while (usedSessionIndex>associatedKey.sessionIndex) { + lime_deriveKey(&associatedKey); } /* decrypt the message */ *output = (uint8_t *)malloc(encryptedMessageLength - 16 +1); /* plain message is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */ - lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + retval = lime_decryptMessage(&associatedKey, encryptedMessage, encryptedMessageLength, selfZid, *output); + free(encryptedMessage); + if (retval!=0 ) { + free(*output); + *output = NULL; + return LIME_UNABLE_TO_DECRYPT_MESSAGE; + } + /* update used key */ lime_deriveKey(&associatedKey); lime_setCachedKey(cacheBuffer, &associatedKey, LIME_RECEIVER); diff --git a/coreapi/lime.h b/coreapi/lime.h index 0dc5c075a..455c80c6c 100644 --- a/coreapi/lime.h +++ b/coreapi/lime.h @@ -6,6 +6,10 @@ #define LIME_UNABLE_TO_ENCRYPT_MESSAGE 0x1004 #define LIME_UNABLE_TO_DECRYPT_MESSAGE 0x1008 #define LIME_NO_KEY_FOUND_FOR_PEER 0x1010 +#define LIME_INVALID_ENCRYPTED_MESSAGE 0x1020 + +/* this define the maximum key derivation number allowed to get the caches back in sync in case of missed messages */ +#define MAX_DERIVATION_NUMBER 100 #define LIME_SENDER 0x01 #define LIME_RECEIVER 0x02 diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d6b3f842c..b3b94cc6d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -697,6 +697,8 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); + tmp=lp_config_get_int(lc->config,"sip","lime",0); + linphone_core_set_lime(lc,tmp); tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); linphone_core_set_inc_timeout(lc,tmp); @@ -1585,6 +1587,15 @@ bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){ return lc->sip_conf.guess_hostname; } +/** + * Tells to LinphoneCore to use Linphone Instant Messaging encryption + * + */ +void linphone_core_set_lime(LinphoneCore *lc, bool_t val){ + lc->lime=val; + lp_config_set_int(lc->config,"sip","lime",val); +} + /** * Same as linphone_core_get_primary_contact() but the result is a LinphoneAddress object * instead of const char* diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7448341aa..6c16aae40 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1498,6 +1498,8 @@ LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); LINPHONE_PUBLIC bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_lime(LinphoneCore *lc, bool_t val); + LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); diff --git a/coreapi/private.h b/coreapi/private.h index 69ca8c728..2c67af176 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -691,6 +691,7 @@ struct _LinphoneCore belle_tls_verify_policy_t *http_verify_policy; MSList *tones; LinphoneReason chat_deny_code; + bool_t lime; }; diff --git a/include/sal/sal.h b/include/sal/sal.h index 1dba31f90..9054a8f44 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -618,7 +618,7 @@ int sal_unregister(SalOp *h); /*Messaging */ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text); -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg); +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri); int sal_message_reply(SalOp *op, SalReason reason); /*presence Subscribe/notify*/ diff --git a/oRTP b/oRTP index beee1f20d..ebd87c21d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit beee1f20d69af3d04cd27fcc00b3830620066367 +Subproject commit ebd87c21d3d5c8b4775ef08af18e27c4bf4fa3ac