mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-05-06 21:33:08 +00:00
Merge remote-tracking branch 'private/dev_im_encryption_engine'
This commit is contained in:
commit
9a26b72164
16 changed files with 1152 additions and 433 deletions
|
|
@ -37,6 +37,7 @@ set(LINPHONE_PRIVATE_HEADER_FILES
|
|||
contact_providers_priv.h
|
||||
enum.h
|
||||
lime.h
|
||||
im_encryption_engine.h
|
||||
lpc2xml.h
|
||||
offeranswer.h
|
||||
private.h
|
||||
|
|
@ -82,6 +83,7 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
info.c
|
||||
ldapprovider.c
|
||||
lime.c
|
||||
im_encryption_engine.c
|
||||
linphonecall.c
|
||||
linphonecore.c
|
||||
linphone_tunnel_config.c
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ liblinphone_la_SOURCES=\
|
|||
localplayer.c \
|
||||
lpc2xml.c lpc2xml.h \
|
||||
lime.c lime.h\
|
||||
im_encryption_engine.c \
|
||||
lpconfig.c \
|
||||
lsd.c \
|
||||
message_storage.c \
|
||||
|
|
|
|||
|
|
@ -993,6 +993,14 @@ const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name) {
|
||||
belle_sip_message_t *msg=(belle_sip_message_t*)ch;
|
||||
if (msg==NULL) return NULL;
|
||||
|
||||
belle_sip_message_remove_header(msg, name);
|
||||
return (SalCustomHeader*)msg;
|
||||
}
|
||||
|
||||
void sal_custom_header_free(SalCustomHeader *ch){
|
||||
if (ch==NULL) return;
|
||||
belle_sip_object_unref((belle_sip_message_t*)ch);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
#include "linphone/core.h"
|
||||
#include "private.h"
|
||||
#include "lime.h"
|
||||
#include <libxml/xmlwriter.h>
|
||||
|
||||
static void process_error( SalOp* op) {
|
||||
|
|
@ -60,23 +59,6 @@ static void process_response_event(void *op_base, const belle_sip_response_event
|
|||
op->base.root->callbacks.text_delivery_update(op,status);
|
||||
}
|
||||
|
||||
static bool_t is_rcs_filetransfer(belle_sip_header_content_type_t* content_type) {
|
||||
return (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0)
|
||||
&& ((strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0) || (strcmp("cipher.vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0));
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|| (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
|
||||
&& strcmp("cipher.vnd.gsma.rcs-ft-http+xml",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;
|
||||
|
|
@ -97,79 +79,34 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
|
|||
belle_sip_header_from_t* from_header;
|
||||
belle_sip_header_content_type_t* content_type;
|
||||
belle_sip_response_t* resp;
|
||||
int errcode=500;
|
||||
int errcode = 500;
|
||||
belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t);
|
||||
belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
|
||||
belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t);
|
||||
char* from;
|
||||
bool_t plain_text=FALSE;
|
||||
bool_t external_body=FALSE;
|
||||
bool_t cipher_xml=FALSE;
|
||||
bool_t rcs_filetransfer=FALSE;
|
||||
uint8_t *decryptedMessage = NULL;
|
||||
|
||||
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
|
||||
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
|
||||
|
||||
if (content_type){
|
||||
|
||||
/* check if we have a xml/cipher message to be decrypted */
|
||||
if ((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 = NULL;
|
||||
if (lc->zrtp_secrets_cache != NULL) CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
} else {
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
int retval;
|
||||
xmlDocPtr cacheXml;
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
goto error;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)), &decryptedMessage);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to decrypt message, reason : %s - op [%p]", lime_error_code_to_string(retval), op);
|
||||
free(decryptedMessage);
|
||||
xmlFreeDoc(cacheXml);
|
||||
errcode = 488;
|
||||
goto error;
|
||||
} else {
|
||||
/* 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, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Fail to write cache");
|
||||
}
|
||||
xmlFree(xmlStringOutput);
|
||||
fclose(CACHEFD);
|
||||
}
|
||||
|
||||
xmlFreeDoc(cacheXml);
|
||||
}
|
||||
|
||||
}
|
||||
external_body=is_external_body(content_type);
|
||||
plain_text=is_plain_text(content_type);
|
||||
rcs_filetransfer = is_rcs_filetransfer(content_type);
|
||||
|
||||
if (external_body || plain_text || rcs_filetransfer || decryptedMessage!=NULL) {
|
||||
if (content_type) {
|
||||
if (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);
|
||||
resp = belle_sip_response_create_from_request(req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
} else {
|
||||
SalMessage salmsg;
|
||||
char message_id[256]={0};
|
||||
|
||||
external_body=is_external_body(content_type);
|
||||
|
||||
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
|
||||
op->pending_server_trans=server_transaction;
|
||||
|
|
@ -183,16 +120,9 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
|
|||
,belle_sip_header_cseq_get_seq_number(cseq));
|
||||
salmsg.from=from;
|
||||
/* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/
|
||||
if (cipher_xml) {
|
||||
salmsg.text = (char *)decryptedMessage;
|
||||
} else { /* message body wasn't ciphered */
|
||||
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
|
||||
}
|
||||
salmsg.text=(!external_body)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
|
||||
salmsg.url=NULL;
|
||||
salmsg.content_type = NULL;
|
||||
if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */
|
||||
salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
|
||||
}
|
||||
salmsg.content_type = ms_strdup_printf("%s/%s", belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type));
|
||||
if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
|
||||
size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
|
||||
salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
|
||||
|
|
@ -202,28 +132,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
|
|||
salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
|
||||
op->base.root->callbacks.text_received(op,&salmsg);
|
||||
|
||||
free(decryptedMessage);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
if (salmsg.url) ms_free((char*)salmsg.url);
|
||||
} else if (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);
|
||||
resp = belle_sip_response_create_from_request(req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
}else{
|
||||
ms_error("Unsupported MESSAGE (content-type not recognized)");
|
||||
errcode = 415;
|
||||
goto error;
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
ms_error("Unsupported MESSAGE (no Content-Type)");
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -245,7 +158,6 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
char content_type_raw[256];
|
||||
size_t content_length = msg?strlen(msg):0;
|
||||
time_t curtime = ms_time(NULL);
|
||||
uint8_t *multipartEncryptedMessage = NULL;
|
||||
const char *body;
|
||||
int retval;
|
||||
|
||||
|
|
@ -269,71 +181,16 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
}
|
||||
}
|
||||
|
||||
/* shall we try to encrypt the message?*/
|
||||
if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 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, "rb+");
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to encrypt message");
|
||||
/*probably not a good idea to do this:*/
|
||||
sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL);
|
||||
op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed);
|
||||
return -1;
|
||||
} else {
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
xmlDocPtr cacheXml;
|
||||
int retval;
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to encrypt message");
|
||||
return -1;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op);
|
||||
xmlFreeDoc(cacheXml);
|
||||
free(multipartEncryptedMessage);
|
||||
/*probably not a good idea to do this:*/
|
||||
sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL);
|
||||
op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed);
|
||||
return -1;
|
||||
} else {
|
||||
/* 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, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Unable to write zid cache");
|
||||
}
|
||||
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)));
|
||||
body = (multipartEncryptedMessage==NULL) ? msg : (char*) multipartEncryptedMessage;
|
||||
body = msg;
|
||||
if (body){
|
||||
/*don't call set_body() with null argument because it resets content type and content length*/
|
||||
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), body, content_length);
|
||||
}
|
||||
retval = sal_op_send_request(op,req);
|
||||
free(multipartEncryptedMessage);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1159,10 +1159,11 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
|
|||
static void text_received(SalOp *op, const SalMessage *msg){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){
|
||||
linphone_core_message_received(lc,op,msg);
|
||||
LinphoneReason reason = lc->chat_deny_code;
|
||||
if (reason == LinphoneReasonNone && is_duplicate_msg(lc, msg->message_id) == FALSE) {
|
||||
reason = linphone_core_message_received(lc, op, msg);
|
||||
}
|
||||
sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code));
|
||||
sal_message_reply(op,linphone_reason_to_sal(reason));
|
||||
if (!call) sal_op_release(op);
|
||||
}
|
||||
|
||||
|
|
|
|||
182
coreapi/chat.c
182
coreapi/chat.c
|
|
@ -27,7 +27,6 @@
|
|||
#include "linphone/lpconfig.h"
|
||||
#include "belle-sip/belle-sip.h"
|
||||
#include "ortp/b64.h"
|
||||
#include "lime.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
|
@ -265,50 +264,6 @@ LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const c
|
|||
return _linphone_core_get_or_create_chat_room(lc, to);
|
||||
}
|
||||
|
||||
bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
|
||||
if (cr) {
|
||||
switch (linphone_core_lime_enabled(cr->lc)) {
|
||||
case LinphoneLimeDisabled: return FALSE;
|
||||
case LinphoneLimeMandatory: return TRUE;
|
||||
case LinphoneLimePreferred: {
|
||||
FILE *CACHEFD = NULL;
|
||||
if (cr->lc->zrtp_secrets_cache != NULL) {
|
||||
CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD) {
|
||||
size_t cacheSize;
|
||||
xmlDocPtr cacheXml;
|
||||
char *cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
return FALSE;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
if (cacheXml) {
|
||||
bool_t res;
|
||||
limeURIKeys_t associatedKeys;
|
||||
/* retrieve keys associated to the peer URI */
|
||||
associatedKeys.peerURI = (uint8_t *)malloc(strlen(cr->peer)+1);
|
||||
strcpy((char *)(associatedKeys.peerURI), cr->peer);
|
||||
associatedKeys.associatedZIDNumber = 0;
|
||||
associatedKeys.peerKeys = NULL;
|
||||
|
||||
res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0 && associatedKeys.associatedZIDNumber != 0);
|
||||
lime_freeKeys(&associatedKeys);
|
||||
xmlFreeDoc(cacheXml);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) {
|
||||
if (cr->composing_idle_timer) {
|
||||
if (cr->lc && cr->lc->sal)
|
||||
|
|
@ -366,6 +321,10 @@ void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void *ud) {
|
|||
}
|
||||
|
||||
void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
|
||||
int retval = -1;
|
||||
LinphoneCore *lc = cr->lc;
|
||||
LinphoneImEncryptionEngine *imee = lc->im_encryption_engine;
|
||||
|
||||
/*stubed rtt text*/
|
||||
if (cr->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(cr->call))) {
|
||||
uint32_t new_line = 0x2028;
|
||||
|
|
@ -406,6 +365,15 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineOutgoingMessageCb cb_process_outgoing_message = linphone_im_encryption_engine_cbs_get_process_outgoing_message(imee_cbs);
|
||||
if (cb_process_outgoing_message) {
|
||||
retval = cb_process_outgoing_message(lc, cr, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (op == NULL) {
|
||||
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
|
||||
if (proxy) {
|
||||
|
|
@ -418,6 +386,13 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage
|
|||
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 (retval > 0) {
|
||||
sal_error_info_set((SalErrorInfo *)sal_op_get_error_info(op), SalReasonNotAcceptable, retval, "Unable to encrypt IM", NULL);
|
||||
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
|
||||
linphone_chat_message_unref(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->external_body_url) {
|
||||
content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->external_body_url);
|
||||
|
|
@ -425,21 +400,7 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage
|
|||
ms_free(content_type);
|
||||
} else {
|
||||
char *peer_uri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
|
||||
const char *content_type;
|
||||
|
||||
if (linphone_chat_room_lime_available(cr)) {
|
||||
/* ref the msg or it may be destroyed by callback if the encryption failed */
|
||||
if (msg->content_type && strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) {
|
||||
/* it's a file transfer, content type shall be set to
|
||||
application/cipher.vnd.gsma.rcs-ft-http+xml*/
|
||||
content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml";
|
||||
} else {
|
||||
content_type = "xml/cipher";
|
||||
}
|
||||
} else {
|
||||
content_type = msg->content_type;
|
||||
}
|
||||
|
||||
const char *content_type = msg->content_type;
|
||||
if (content_type == NULL) {
|
||||
sal_text_send(op, identity, cr->peer, msg->message);
|
||||
} else {
|
||||
|
|
@ -509,30 +470,68 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc,
|
|||
linphone_core_notify_is_composing_received(cr->lc, cr);
|
||||
}
|
||||
|
||||
void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) {
|
||||
LinphoneReason linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg) {
|
||||
LinphoneChatRoom *cr = NULL;
|
||||
LinphoneAddress *addr;
|
||||
LinphoneAddress *to;
|
||||
LinphoneChatMessage *msg;
|
||||
LinphoneImEncryptionEngine *imee = lc->im_encryption_engine;
|
||||
const SalCustomHeader *ch;
|
||||
LinphoneReason reason = LinphoneReasonNone;
|
||||
int retval = -1;
|
||||
|
||||
addr = linphone_address_new(sal_msg->from);
|
||||
linphone_address_clean(addr);
|
||||
cr = linphone_core_get_chat_room(lc, addr);
|
||||
|
||||
if (sal_msg->content_type !=
|
||||
NULL) { /* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with
|
||||
"application/vnd.gsma.rcs-ft-http+xml" */
|
||||
msg = linphone_chat_room_create_message(cr, sal_msg->text); /* create a msg with empty body */
|
||||
msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */
|
||||
linphone_chat_message_set_from(msg, cr->peer_url);
|
||||
|
||||
to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(lc));
|
||||
msg->to = to;
|
||||
|
||||
msg->time = sal_msg->time;
|
||||
msg->state = LinphoneChatMessageStateDelivered;
|
||||
msg->is_read = FALSE;
|
||||
msg->dir = LinphoneChatMessageIncoming;
|
||||
|
||||
ch = sal_op_get_recv_custom_header(op);
|
||||
if (ch) {
|
||||
msg->custom_headers = sal_custom_header_clone(ch);
|
||||
}
|
||||
|
||||
if (sal_msg->url) {
|
||||
linphone_chat_message_set_external_body_url(msg, sal_msg->url);
|
||||
}
|
||||
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineIncomingMessageCb cb_process_incoming_message = linphone_im_encryption_engine_cbs_get_process_incoming_message(imee_cbs);
|
||||
if (cb_process_incoming_message) {
|
||||
retval = cb_process_incoming_message(lc, cr, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0 && strcmp("text/plain", msg->content_type) != 0 && strcmp("message/external-body", msg->content_type) != 0
|
||||
&& strcmp("application/vnd.gsma.rcs-ft-http+xml", msg->content_type) != 0) {
|
||||
retval = 415;
|
||||
ms_error("Unsupported MESSAGE (content-type %s not recognized)", msg->content_type);
|
||||
}
|
||||
|
||||
if (retval > 0) {
|
||||
reason = linphone_error_code_to_reason(retval);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp("application/vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) {
|
||||
xmlChar *file_url = NULL;
|
||||
xmlDocPtr xmlMessageBody;
|
||||
xmlNodePtr cur;
|
||||
|
||||
msg = linphone_chat_room_create_message(cr, NULL); /* create a msg with empty body */
|
||||
msg->content_type =
|
||||
ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */
|
||||
msg->file_transfer_information = linphone_content_new();
|
||||
|
||||
/* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */
|
||||
/* parse the msg body to get all informations from it */
|
||||
xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text);
|
||||
xmlMessageBody = xmlParseDoc((const xmlChar *)msg->message);
|
||||
msg->file_transfer_information = linphone_content_new();
|
||||
|
||||
cur = xmlDocGetRootElement(xmlMessageBody);
|
||||
if (cur != NULL) {
|
||||
|
|
@ -579,18 +578,16 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
|
|||
file_url = xmlGetProp(cur, (const xmlChar *)"url");
|
||||
}
|
||||
|
||||
if (!xmlStrcmp(cur->name,
|
||||
(const xmlChar *)"file-key")) { /* there is a key in the msg: file has
|
||||
been encrypted */
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) {
|
||||
/* there is a key in the msg: file has been encrypted */
|
||||
/* convert the key from base 64 */
|
||||
xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
|
||||
size_t keyLength = b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0);
|
||||
uint8_t *keyBuffer = (uint8_t *)malloc(keyLength);
|
||||
/* decode the key into local key buffer */
|
||||
b64_decode((char *)keyb64, strlen((char *)keyb64), keyBuffer, keyLength);
|
||||
linphone_content_set_key(
|
||||
msg->file_transfer_information, (char *)keyBuffer,
|
||||
strlen((char *)keyBuffer)); /* duplicate key value into the linphone content private structure */
|
||||
linphone_content_set_key(msg->file_transfer_information, (char *)keyBuffer, keyLength);
|
||||
/* duplicate key value into the linphone content private structure */
|
||||
xmlFree(keyb64);
|
||||
free(keyBuffer);
|
||||
}
|
||||
|
|
@ -609,31 +606,8 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
|
|||
|
||||
linphone_chat_message_set_external_body_url(msg, (const char *)file_url);
|
||||
xmlFree(file_url);
|
||||
} else { /* msg is not rcs file transfer, create it with provided sal_msg->text as ->msg */
|
||||
msg = linphone_chat_room_create_message(cr, sal_msg->text);
|
||||
}
|
||||
linphone_chat_message_set_from(msg, cr->peer_url);
|
||||
|
||||
{
|
||||
LinphoneAddress *to;
|
||||
to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op))
|
||||
: linphone_address_new(linphone_core_get_identity(lc));
|
||||
msg->to = to;
|
||||
}
|
||||
|
||||
msg->time = sal_msg->time;
|
||||
msg->state = LinphoneChatMessageStateDelivered;
|
||||
msg->is_read = FALSE;
|
||||
msg->dir = LinphoneChatMessageIncoming;
|
||||
ch = sal_op_get_recv_custom_header(op);
|
||||
if (ch)
|
||||
msg->custom_headers = sal_custom_header_clone(ch);
|
||||
|
||||
if (sal_msg->url) {
|
||||
linphone_chat_message_set_external_body_url(msg, sal_msg->url);
|
||||
}
|
||||
|
||||
linphone_address_destroy(addr);
|
||||
msg->storage_id = linphone_chat_message_store(msg);
|
||||
|
||||
if (cr->unread_count < 0)
|
||||
|
|
@ -642,7 +616,11 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
|
|||
cr->unread_count++;
|
||||
|
||||
linphone_chat_room_message_received(cr, lc, msg);
|
||||
|
||||
end:
|
||||
linphone_address_destroy(addr);
|
||||
linphone_chat_message_unref(msg);
|
||||
return reason;
|
||||
}
|
||||
|
||||
static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) {
|
||||
|
|
@ -1151,6 +1129,10 @@ const char *linphone_chat_message_get_custom_header(LinphoneChatMessage *msg, co
|
|||
return sal_custom_header_find(msg->custom_headers, header_name);
|
||||
}
|
||||
|
||||
void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name) {
|
||||
msg->custom_headers = sal_custom_header_remove(msg->custom_headers, header_name);
|
||||
}
|
||||
|
||||
bool_t linphone_chat_message_is_read(LinphoneChatMessage *msg) {
|
||||
return msg->is_read;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,8 @@
|
|||
|
||||
#include "linphone/core.h"
|
||||
#include "private.h"
|
||||
#include "lime.h"
|
||||
#include "ortp/b64.h"
|
||||
|
||||
#define FILE_TRANSFER_KEY_SIZE 32
|
||||
|
||||
static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) {
|
||||
return (msg->chat_room && msg->chat_room->lc && msg->http_request && !belle_http_request_is_cancelled(msg->http_request));
|
||||
}
|
||||
|
|
@ -94,11 +91,12 @@ static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handl
|
|||
}
|
||||
}
|
||||
|
||||
static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m,
|
||||
static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m,
|
||||
void *data, size_t offset, uint8_t *buffer, size_t *size) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
LinphoneCore *lc = NULL;
|
||||
char *buf = (char *)buffer;
|
||||
LinphoneImEncryptionEngine *imee = NULL;
|
||||
int retval = -1;
|
||||
|
||||
if (!file_transfer_in_progress_and_valid(msg)) {
|
||||
if (msg->http_request) {
|
||||
|
|
@ -109,52 +107,55 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
|
|||
}
|
||||
|
||||
lc = msg->chat_room->lc;
|
||||
/* if we've not reach the end of file yet, ask for more data*/
|
||||
/* if we've not reach the end of file yet, ask for more data */
|
||||
/* in case of file body handler, won't be called */
|
||||
if (offset < linphone_content_get_size(msg->file_transfer_information)) {
|
||||
char *plainBuffer = NULL;
|
||||
|
||||
if (linphone_content_get_key(msg->file_transfer_information) !=
|
||||
NULL) { /* if we have a key to cipher the msg, use it! */
|
||||
/* if this chunk is not the last one, the lenght must be a multiple of block cipher size(16 bytes)*/
|
||||
if (offset + *size < linphone_content_get_size(msg->file_transfer_information)) {
|
||||
*size -= (*size % 16);
|
||||
}
|
||||
plainBuffer = (char *)ms_malloc0(*size);
|
||||
}
|
||||
|
||||
/* get data from call back */
|
||||
if (linphone_chat_message_cbs_get_file_transfer_send(msg->callbacks)) {
|
||||
LinphoneBuffer *lb = linphone_chat_message_cbs_get_file_transfer_send(msg->callbacks)(
|
||||
msg, msg->file_transfer_information, offset, *size);
|
||||
LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->callbacks);
|
||||
if (file_transfer_send_cb) {
|
||||
LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size);
|
||||
if (lb == NULL) {
|
||||
*size = 0;
|
||||
} else {
|
||||
*size = linphone_buffer_get_size(lb);
|
||||
memcpy(plainBuffer ? plainBuffer : buf, linphone_buffer_get_content(lb), *size);
|
||||
memcpy(buffer, linphone_buffer_get_content(lb), *size);
|
||||
linphone_buffer_unref(lb);
|
||||
}
|
||||
} else {
|
||||
/* Legacy */
|
||||
linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information,
|
||||
plainBuffer ? plainBuffer : buf, size);
|
||||
linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size);
|
||||
}
|
||||
|
||||
if (linphone_content_get_key(msg->file_transfer_information) !=
|
||||
NULL) { /* if we have a key to cipher the msg, use it! */
|
||||
lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
|
||||
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size,
|
||||
plainBuffer, (char *)buffer);
|
||||
ms_free(plainBuffer);
|
||||
/* check if we reach the end of file */
|
||||
if (offset + *size >= linphone_content_get_size(msg->file_transfer_information)) {
|
||||
/* conclude file ciphering by calling it context with a zero size */
|
||||
lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
imee = linphone_core_get_im_encryption_engine(lc);
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs);
|
||||
if (cb_process_uploading_file) {
|
||||
char *encrypted_buffer = (char *)ms_malloc0(*size);
|
||||
retval = cb_process_uploading_file(lc, msg, offset, (char *)buffer, size, encrypted_buffer);
|
||||
if (retval == 0) {
|
||||
memcpy(buffer, encrypted_buffer, *size);
|
||||
}
|
||||
ms_free(encrypted_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return BELLE_SIP_CONTINUE;
|
||||
return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP;
|
||||
}
|
||||
|
||||
static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
LinphoneCore *lc = msg->chat_room->lc;
|
||||
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc);
|
||||
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs);
|
||||
if (cb_process_uploading_file) {
|
||||
cb_process_uploading_file(lc, msg, 0, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_chat_message_process_response_from_post_file(void *data,
|
||||
|
|
@ -176,21 +177,27 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
char *first_part_header;
|
||||
belle_sip_body_handler_t *first_part_bh;
|
||||
|
||||
bool_t is_file_encryption_enabled = FALSE;
|
||||
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(msg->chat_room->lc);
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb =
|
||||
linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs);
|
||||
if (is_encryption_enabled_for_file_transfer_cb) {
|
||||
is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(msg->chat_room->lc, msg->chat_room);
|
||||
}
|
||||
}
|
||||
/* shall we encrypt the file */
|
||||
if (linphone_chat_room_lime_available(msg->chat_room) &&
|
||||
linphone_core_lime_for_file_sharing_enabled(msg->chat_room->lc)) {
|
||||
char keyBuffer
|
||||
[FILE_TRANSFER_KEY_SIZE]; /* temporary storage of generated key: 192 bits of key + 64 bits of
|
||||
initial vector */
|
||||
/* generate a random 192 bits key + 64 bits of initial vector and store it into the
|
||||
* file_transfer_information->key field of the msg */
|
||||
sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE);
|
||||
linphone_content_set_key(
|
||||
msg->file_transfer_information, keyBuffer,
|
||||
FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
|
||||
if (is_file_encryption_enabled) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineGenerateFileTransferKeyCb generate_file_transfer_key_cb =
|
||||
linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs);
|
||||
if (generate_file_transfer_key_cb) {
|
||||
generate_file_transfer_key_cb(msg->chat_room->lc, msg->chat_room, msg);
|
||||
}
|
||||
/* temporary storage for the Content-disposition header value : use a generic filename to not leak it
|
||||
* Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg
|
||||
* sended to the */
|
||||
* Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg
|
||||
* sended to the */
|
||||
first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\"");
|
||||
} else {
|
||||
/* temporary storage for the Content-disposition header value */
|
||||
|
|
@ -200,18 +207,21 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
|
||||
/* create a user body handler to take care of the file and add the content disposition and content-type
|
||||
* headers */
|
||||
first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(
|
||||
linphone_content_get_size(msg->file_transfer_information),
|
||||
linphone_chat_message_file_transfer_on_progress, NULL, NULL,
|
||||
on_send_body, on_send_end, msg);
|
||||
if (msg->file_transfer_filepath != NULL) {
|
||||
first_part_bh =
|
||||
(belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath, NULL, msg);
|
||||
belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh;
|
||||
first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath,
|
||||
linphone_chat_message_file_transfer_on_progress, msg);
|
||||
belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler);
|
||||
} else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) {
|
||||
first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer(
|
||||
linphone_content_get_buffer(msg->file_transfer_information),
|
||||
linphone_content_get_size(msg->file_transfer_information), NULL, msg);
|
||||
} else {
|
||||
first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(
|
||||
linphone_content_get_size(msg->file_transfer_information), NULL, NULL,
|
||||
linphone_chat_message_file_transfer_on_send_body, msg);
|
||||
linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg);
|
||||
}
|
||||
|
||||
belle_sip_body_handler_add_header(first_part_bh,
|
||||
belle_sip_header_create("Content-disposition", first_part_header));
|
||||
belle_sip_free(first_part_header);
|
||||
|
|
@ -233,7 +243,9 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
if (body && strlen(body) > 0) {
|
||||
/* if we have an encryption key for the file, we must insert it into the msg and restore the correct
|
||||
* filename */
|
||||
if (linphone_content_get_key(msg->file_transfer_information) != NULL) {
|
||||
const char *content_key = linphone_content_get_key(msg->file_transfer_information);
|
||||
size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information);
|
||||
if (content_key != NULL) {
|
||||
/* parse the msg body */
|
||||
xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body);
|
||||
|
||||
|
|
@ -252,12 +264,11 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
->xmlChildrenNode; /* need to parse the children node to update the file-name
|
||||
one */
|
||||
/* convert key to base64 */
|
||||
size_t b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0);
|
||||
size_t b64Size = b64_encode(NULL, content_key_size, NULL, 0);
|
||||
char *keyb64 = (char *)ms_malloc0(b64Size + 1);
|
||||
int xmlStringLength;
|
||||
|
||||
b64Size = b64_encode(linphone_content_get_key(msg->file_transfer_information),
|
||||
FILE_TRANSFER_KEY_SIZE, keyb64, b64Size);
|
||||
b64Size = b64_encode(content_key, content_key_size, keyb64, b64Size);
|
||||
keyb64[b64Size] = '\0'; /* libxml need a null terminated string */
|
||||
|
||||
/* add the node containing the key to the file-info node */
|
||||
|
|
@ -320,10 +331,12 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const
|
|||
return msg->file_transfer_information;
|
||||
}
|
||||
|
||||
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset,
|
||||
const uint8_t *buffer, size_t size) {
|
||||
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
LinphoneCore *lc;
|
||||
LinphoneCore *lc = NULL;
|
||||
LinphoneImEncryptionEngine *imee = NULL;
|
||||
int retval = -1;
|
||||
char *decrypted_buffer = NULL;
|
||||
|
||||
if (!msg->chat_room) {
|
||||
linphone_chat_message_cancel_file_transfer(msg);
|
||||
|
|
@ -344,37 +357,68 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t
|
|||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (linphone_content_get_key(msg->file_transfer_information) !=
|
||||
NULL) { /* we have a key, we must decrypt the file */
|
||||
/* get data from callback to a plainBuffer */
|
||||
char *plainBuffer = (char *)ms_malloc0(size);
|
||||
lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
|
||||
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, plainBuffer,
|
||||
(char *)buffer);
|
||||
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
|
||||
LinphoneBuffer *lb = linphone_buffer_new_from_data((unsigned char *)plainBuffer, size);
|
||||
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
|
||||
linphone_buffer_unref(lb);
|
||||
} else {
|
||||
/* legacy: call back given by application level */
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, plainBuffer, size);
|
||||
|
||||
decrypted_buffer = (char *)ms_malloc0(size);
|
||||
imee = linphone_core_get_im_encryption_engine(lc);
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs);
|
||||
if (cb_process_downloading_file) {
|
||||
retval = cb_process_downloading_file(lc, msg, (const char *)buffer, size, decrypted_buffer);
|
||||
if (retval == 0) {
|
||||
memcpy(buffer, decrypted_buffer, size);
|
||||
}
|
||||
}
|
||||
ms_free(plainBuffer);
|
||||
} else { /* regular file, no deciphering */
|
||||
}
|
||||
ms_free(decrypted_buffer);
|
||||
|
||||
if (retval <= 0) {
|
||||
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
|
||||
LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size);
|
||||
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
|
||||
linphone_buffer_unref(lb);
|
||||
} else {
|
||||
/* Legacy: call back given by application level */
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (char *)buffer, size);
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size);
|
||||
}
|
||||
} else {
|
||||
ms_warning("File transfer decrypt failed with code %d", (int)retval);
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) {
|
||||
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
|
||||
LinphoneCore *lc = msg->chat_room->lc;
|
||||
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc);
|
||||
int retval = -1;
|
||||
|
||||
if (imee) {
|
||||
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
LinphoneImEncryptionEngineDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs);
|
||||
if (cb_process_downloading_file) {
|
||||
retval = cb_process_downloading_file(lc, msg, NULL, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval <= 0) {
|
||||
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
|
||||
LinphoneBuffer *lb = linphone_buffer_new();
|
||||
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
|
||||
linphone_buffer_unref(lb);
|
||||
} else {
|
||||
/* Legacy: call back given by application level */
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) {
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone);
|
||||
}
|
||||
}
|
||||
|
||||
static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) {
|
||||
LinphoneContent *content = linphone_content_new();
|
||||
|
||||
|
|
@ -410,6 +454,7 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con
|
|||
/*we are receiving a response, set a specific body handler to acquire the response.
|
||||
* if not done, belle-sip will create a memory body handler, the default*/
|
||||
belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response);
|
||||
belle_sip_body_handler_t *body_handler = NULL;
|
||||
size_t body_size = 0;
|
||||
|
||||
if (msg->file_transfer_information == NULL) {
|
||||
|
|
@ -421,21 +466,20 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con
|
|||
body_size = linphone_content_get_size(msg->file_transfer_information);
|
||||
}
|
||||
|
||||
if (msg->file_transfer_filepath == NULL) {
|
||||
belle_sip_message_set_body_handler(
|
||||
(belle_sip_message_t *)event->response,
|
||||
(belle_sip_body_handler_t *)belle_sip_user_body_handler_new(
|
||||
body_size, linphone_chat_message_file_transfer_on_progress, on_recv_body, NULL, msg));
|
||||
} else {
|
||||
belle_sip_body_handler_t *bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(
|
||||
|
||||
body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg);
|
||||
if (msg->file_transfer_filepath != NULL) {
|
||||
belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler;
|
||||
body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(
|
||||
msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg);
|
||||
if (belle_sip_body_handler_get_size(bh) == 0) {
|
||||
if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) {
|
||||
/* If the size of the body has not been initialized from the file stat, use the one from the
|
||||
* file_transfer_information. */
|
||||
belle_sip_body_handler_set_size(bh, body_size);
|
||||
belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size);
|
||||
}
|
||||
belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, bh);
|
||||
belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh);
|
||||
}
|
||||
belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -444,47 +488,10 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
|
|||
/* check the answer code */
|
||||
if (event->response) {
|
||||
int code = belle_http_response_get_status_code(event->response);
|
||||
if (code == 200) {
|
||||
LinphoneCore *lc = msg->chat_room->lc;
|
||||
if (msg->file_transfer_filepath == NULL) {
|
||||
/* if the file was encrypted, finish the decryption and free context */
|
||||
if (linphone_content_get_key(msg->file_transfer_information) != NULL) {
|
||||
lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
|
||||
}
|
||||
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
|
||||
LinphoneBuffer *lb = linphone_buffer_new();
|
||||
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
|
||||
linphone_buffer_unref(lb);
|
||||
} else {
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0);
|
||||
}
|
||||
} else {
|
||||
if (linphone_content_get_key(msg->file_transfer_information) != NULL) {
|
||||
bctbx_vfs_t *vfs = bctbx_vfs_get_default();
|
||||
bctbx_vfs_file_t *decrypted_file;
|
||||
bctbx_vfs_file_t *encrypted_file = bctbx_file_open(vfs, msg->file_transfer_filepath, "r");
|
||||
size_t encrypted_file_size = (size_t)bctbx_file_size(encrypted_file);
|
||||
char *encrypted_content = bctbx_malloc(encrypted_file_size);
|
||||
char *decrypted_content = bctbx_malloc(encrypted_file_size);
|
||||
bctbx_file_read(encrypted_file, encrypted_content, encrypted_file_size, 0);
|
||||
bctbx_file_close(encrypted_file);
|
||||
lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
|
||||
(unsigned char *)linphone_content_get_key(msg->file_transfer_information),
|
||||
encrypted_file_size, decrypted_content, encrypted_content);
|
||||
lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
|
||||
decrypted_file = bctbx_file_open(vfs, msg->file_transfer_filepath, "w");
|
||||
bctbx_file_write(decrypted_file, decrypted_content, encrypted_file_size, 0);
|
||||
bctbx_file_close(decrypted_file);
|
||||
bctbx_free(encrypted_content);
|
||||
bctbx_free(decrypted_content);
|
||||
}
|
||||
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0);
|
||||
}
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone);
|
||||
} else if (code >= 400 && code < 500) {
|
||||
if (code >= 400 && code < 500) {
|
||||
ms_warning("File transfer failed with code %d", code);
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError);
|
||||
} else {
|
||||
} else if (code != 200) {
|
||||
ms_warning("Unhandled HTTP code response %d for file transfer", code);
|
||||
}
|
||||
_release_http_request(msg);
|
||||
|
|
|
|||
124
coreapi/im_encryption_engine.c
Normal file
124
coreapi/im_encryption_engine.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
ImEncryptionEgine.c
|
||||
Copyright (C) 2016 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "linphone/core.h"
|
||||
#include "im_encryption_engine.h"
|
||||
|
||||
struct _LinphoneImEncryptionEngineCbs {
|
||||
void *user_data;
|
||||
LinphoneImEncryptionEngineIncomingMessageCb process_incoming_message;
|
||||
LinphoneImEncryptionEngineOutgoingMessageCb process_outgoing_message;
|
||||
LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer;
|
||||
LinphoneImEncryptionEngineGenerateFileTransferKeyCb generate_file_transfer_key;
|
||||
LinphoneImEncryptionEngineDownloadingFileCb process_downlading_file;
|
||||
LinphoneImEncryptionEngineUploadingFileCb process_uploading_file;
|
||||
};
|
||||
|
||||
struct _LinphoneImEncryptionEngine {
|
||||
void *user_data;
|
||||
LinphoneImEncryptionEngineCbs *callbacks;
|
||||
};
|
||||
|
||||
LinphoneImEncryptionEngineCbs *linphone_im_encryption_engine_cbs_new(void) {
|
||||
LinphoneImEncryptionEngineCbs *cbs = ms_new0(LinphoneImEncryptionEngineCbs, 1);
|
||||
return cbs;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_destory(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
ms_free(cbs);
|
||||
}
|
||||
|
||||
void *linphone_im_encryption_engine_cbs_get_user_data(const LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->user_data;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImEncryptionEngineCbs *cbs, void *data) {
|
||||
cbs->user_data = data;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngine *linphone_im_encryption_engine_new(void) {
|
||||
LinphoneImEncryptionEngine *imee = ms_new0(LinphoneImEncryptionEngine, 1);
|
||||
imee->callbacks = linphone_im_encryption_engine_cbs_new();
|
||||
return imee;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_destory(LinphoneImEncryptionEngine *imee) {
|
||||
if (imee->callbacks) linphone_im_encryption_engine_cbs_destory(imee->callbacks);
|
||||
ms_free(imee);
|
||||
}
|
||||
|
||||
void *linphone_im_encryption_engine_get_user_data(const LinphoneImEncryptionEngine *imee) {
|
||||
return imee->user_data;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_set_user_data(LinphoneImEncryptionEngine *imee, void *data) {
|
||||
imee->user_data = data;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get_callbacks(const LinphoneImEncryptionEngine *imee) {
|
||||
return imee->callbacks;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineIncomingMessageCb linphone_im_encryption_engine_cbs_get_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->process_incoming_message;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIncomingMessageCb cb) {
|
||||
cbs->process_incoming_message = cb;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineOutgoingMessageCb linphone_im_encryption_engine_cbs_get_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->process_outgoing_message;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineOutgoingMessageCb cb) {
|
||||
cbs->process_outgoing_message = cb;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineDownloadingFileCb linphone_im_encryption_engine_cbs_get_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->process_downlading_file;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineDownloadingFileCb cb) {
|
||||
cbs->process_downlading_file = cb;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineUploadingFileCb linphone_im_encryption_engine_cbs_get_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->process_uploading_file;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineUploadingFileCb cb) {
|
||||
cbs->process_uploading_file = cb;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->is_encryption_enabled_for_file_transfer;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb cb) {
|
||||
cbs->is_encryption_enabled_for_file_transfer = cb;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngineGenerateFileTransferKeyCb linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs) {
|
||||
return cbs->generate_file_transfer_key;
|
||||
}
|
||||
|
||||
void linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineGenerateFileTransferKeyCb cb) {
|
||||
cbs->generate_file_transfer_key = cb;
|
||||
}
|
||||
242
coreapi/im_encryption_engine.h
Normal file
242
coreapi/im_encryption_engine.h
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
ImEncryptionEgine.h
|
||||
Copyright (C) 2016 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef IM_ENCRYPTION_ENGINE_H
|
||||
#define IM_ENCRYPTION_ENGINE_H
|
||||
|
||||
#include <mediastreamer2/mscommon.h>
|
||||
|
||||
#ifndef LINPHONE_PUBLIC
|
||||
#define LINPHONE_PUBLIC MS2_PUBLIC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Callback to decrypt incoming LinphoneChatMessage
|
||||
* @param lc the LinphoneCore object
|
||||
* @param room the LinphoneChatRoom object
|
||||
* @param msg the LinphoneChatMessage object
|
||||
* @return -1 if nothing to be done, 0 on success or an integer > 0 for error
|
||||
*/
|
||||
typedef int (*LinphoneImEncryptionEngineIncomingMessageCb)(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
/**
|
||||
* Callback to encrypt outging LinphoneChatMessage
|
||||
* @param lc the LinphoneCore object
|
||||
* @param room the LinphoneChatRoom object
|
||||
* @param msg the LinphoneChatMessage object
|
||||
* @return -1 if nothing to be done, 0 on success or an integer > 0 for error
|
||||
*/
|
||||
typedef int (*LinphoneImEncryptionEngineOutgoingMessageCb)(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
/**
|
||||
* Callback to know whether or not the engine will encrypt files before uploading them
|
||||
* @param lc the LinphoneCore object
|
||||
* @param room the LinphoneChatRoom object
|
||||
* @return TRUE if files will be encrypted, FALSE otherwise
|
||||
*/
|
||||
typedef bool_t (*LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb)(LinphoneCore *lc, LinphoneChatRoom *room);
|
||||
|
||||
/**
|
||||
* Callback to generate the key used to encrypt the files before uploading them
|
||||
* Key can be stored in the LinphoneContent object inside the LinphoneChatMessage using linphone_content_set_key
|
||||
* @param lc the LinphoneCore object
|
||||
* @param room the LinphoneChatRoom object
|
||||
* @param msg the LinphoneChatMessage object
|
||||
*/
|
||||
typedef void (*LinphoneImEncryptionEngineGenerateFileTransferKeyCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
/**
|
||||
* Callback to decrypt downloading file
|
||||
* @param lc the LinphoneCore object
|
||||
* @param msg the LinphoneChatMessage object
|
||||
* @param buffer the encrypted data buffer
|
||||
* @param size the size of the encrypted data buffer
|
||||
* @param decrypted_buffer the buffer in which to write the decrypted data
|
||||
* @return -1 if nothing to be done, 0 on success or an integer > 0 for error
|
||||
*/
|
||||
typedef int (*LinphoneImEncryptionEngineDownloadingFileCb)(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char *decrypted_buffer);
|
||||
|
||||
/**
|
||||
* Callback to encrypt uploading file
|
||||
* @param lc the LinphoneCore object
|
||||
* @param msg the LinphoneChatMessage object
|
||||
* @param buffer the encrypted data buffer
|
||||
* @param size the size of the plain data buffer and the size of the encrypted data buffer once encryption is done
|
||||
* @param encrypted_buffer the buffer in which to write the encrypted data
|
||||
* @return -1 if nothing to be done, 0 on success or an integer > 0 for error
|
||||
*/
|
||||
typedef int (*LinphoneImEncryptionEngineUploadingFileCb)(LinphoneCore *lc, LinphoneChatMessage *msg, size_t offset, const char *buffer, size_t *size, char *encrypted_buffer);
|
||||
|
||||
typedef struct _LinphoneImEncryptionEngineCbs LinphoneImEncryptionEngineCbs;
|
||||
|
||||
typedef struct _LinphoneImEncryptionEngine LinphoneImEncryptionEngine;
|
||||
|
||||
LinphoneImEncryptionEngineCbs *linphone_im_encryption_engine_cbs_new(void);
|
||||
|
||||
void linphone_im_encryption_engine_cbs_destory(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Gets the user data in the LinphoneImEncryptionEngineCbs object
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs
|
||||
* @return the user data
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void *linphone_im_encryption_engine_cbs_get_user_data(const LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the user data in the LinphoneImEncryptionEngineCbs object
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param data the user data
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_user_data(LinphoneImEncryptionEngineCbs *cbs, void *data);
|
||||
|
||||
/**
|
||||
* Creates a LinphoneImEncryptionEngine object
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngine *linphone_im_encryption_engine_new(void);
|
||||
|
||||
/**
|
||||
* Destroys the LinphoneImEncryptionEngine
|
||||
* @param imee the LinphoneImEncryptionEngine object
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_destory(LinphoneImEncryptionEngine *imee);
|
||||
|
||||
/**
|
||||
* Gets the user data in the LinphoneImEncryptionEngine object
|
||||
* @param imee the LinphoneImEncryptionEngine
|
||||
* @return the user data
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void *linphone_im_encryption_engine_get_user_data(const LinphoneImEncryptionEngine *imee);
|
||||
|
||||
/**
|
||||
* Sets the user data in the LinphoneImEncryptionEngine object
|
||||
* @param imee the LinphoneImEncryptionEngine object
|
||||
* @param data the user data
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_set_user_data(LinphoneImEncryptionEngine *imee, void *data);
|
||||
|
||||
/**
|
||||
* Gets the LinphoneImEncryptionEngineCbs object that holds the callbacks
|
||||
* @param imee the LinphoneImEncryptionEngine object
|
||||
* @return the LinphoneImEncryptionEngineCbs object
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineCbs* linphone_im_encryption_engine_get_callbacks(const LinphoneImEncryptionEngine *imee);
|
||||
|
||||
/**
|
||||
* Gets the callback that will decrypt the chat messages upon reception
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineIncomingMessageCb linphone_im_encryption_engine_cbs_get_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback that will decrypt the chat messages upon reception
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_incoming_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIncomingMessageCb cb);
|
||||
|
||||
/**
|
||||
* Gets the callback that will encrypt the chat messages before sending them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineOutgoingMessageCb linphone_im_encryption_engine_cbs_get_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback that will encrypt the chat messages before sending them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_outgoing_message(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineOutgoingMessageCb cb);
|
||||
|
||||
/**
|
||||
* Gets the callback that will decrypt the files while downloading them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineDownloadingFileCb linphone_im_encryption_engine_cbs_get_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback that will decrypt the files while downloading them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_downloading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineDownloadingFileCb cb);
|
||||
|
||||
/**
|
||||
* Gets the callback that will will encrypt the files while uploading them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineUploadingFileCb linphone_im_encryption_engine_cbs_get_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback that will encrypt the files while uploading them
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_process_uploading_file(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineUploadingFileCb cb);
|
||||
|
||||
/**
|
||||
* Gets the callback telling wheter or not to encrypt the files
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback telling wheter or not to encrypt the files
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineIsEncryptionEnabledForFileTransferCb cb);
|
||||
|
||||
/**
|
||||
* Gets the callback that will generate the key to encrypt the file before uploading it
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @return the callback
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngineGenerateFileTransferKeyCb linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs);
|
||||
|
||||
/**
|
||||
* Sets the callback that will generate the key to encrypt the file before uploading it
|
||||
* @param cbs the LinphoneImEncryptionEngineCbs object
|
||||
* @param cb the callback to call
|
||||
* @ingroup misc
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(LinphoneImEncryptionEngineCbs *cbs, LinphoneImEncryptionEngineGenerateFileTransferKeyCb cb);
|
||||
|
||||
#endif /* IM_ENCRYPTION_ENGINE_H */
|
||||
248
coreapi/lime.c
248
coreapi/lime.c
|
|
@ -23,9 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_LIME
|
||||
#include "linphone/core.h"
|
||||
#include "private.h"
|
||||
#include "bctoolbox/crypto.h"
|
||||
|
||||
#define FILE_TRANSFER_KEY_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief check at runtime if LIME is available
|
||||
*
|
||||
|
|
@ -812,6 +814,229 @@ int lime_decryptMultipartMessage(xmlDocPtr cacheBuffer, uint8_t *message, uint8_
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
|
||||
if (cr) {
|
||||
switch (linphone_core_lime_enabled(cr->lc)) {
|
||||
case LinphoneLimeDisabled: return FALSE;
|
||||
case LinphoneLimeMandatory: return TRUE;
|
||||
case LinphoneLimePreferred: {
|
||||
FILE *CACHEFD = NULL;
|
||||
if (cr->lc->zrtp_secrets_cache != NULL) {
|
||||
CACHEFD = fopen(cr->lc->zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD) {
|
||||
size_t cacheSize;
|
||||
xmlDocPtr cacheXml;
|
||||
char *cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
return FALSE;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
if (cacheXml) {
|
||||
bool_t res;
|
||||
limeURIKeys_t associatedKeys;
|
||||
/* retrieve keys associated to the peer URI */
|
||||
associatedKeys.peerURI = (uint8_t *)malloc(strlen(cr->peer)+1);
|
||||
strcpy((char *)(associatedKeys.peerURI), cr->peer);
|
||||
associatedKeys.associatedZIDNumber = 0;
|
||||
associatedKeys.peerKeys = NULL;
|
||||
|
||||
res = (lime_getCachedSndKeysByURI(cacheXml, &associatedKeys) == 0 && associatedKeys.associatedZIDNumber != 0);
|
||||
lime_freeKeys(&associatedKeys);
|
||||
xmlFreeDoc(cacheXml);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
int errcode = -1;
|
||||
/* check if we have a xml/cipher message to be decrypted */
|
||||
if (msg->content_type && (strcmp("xml/cipher", msg->content_type) == 0 || strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0)) {
|
||||
/* access the zrtp cache to get keys needed to decipher the message */
|
||||
FILE *CACHEFD = NULL;
|
||||
const char *zrtp_secrets_cache = linphone_core_get_zrtp_secrets_file(lc);
|
||||
errcode = 0;
|
||||
if (zrtp_secrets_cache != NULL) CACHEFD = fopen(zrtp_secrets_cache, "rb+");
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to decrypt message");
|
||||
errcode = 500;
|
||||
return errcode;
|
||||
} else {
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
int retval;
|
||||
xmlDocPtr cacheXml;
|
||||
uint8_t *decrypted_body = NULL;
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
|
||||
errcode = 500;
|
||||
return errcode;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_decryptMultipartMessage(cacheXml, (uint8_t *)msg->message, &decrypted_body);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval));
|
||||
if (decrypted_body) free(decrypted_body);
|
||||
xmlFreeDoc(cacheXml);
|
||||
errcode = 488;
|
||||
return errcode;
|
||||
} else {
|
||||
/* 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(zrtp_secrets_cache, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Fail to write cache");
|
||||
}
|
||||
xmlFree(xmlStringOutput);
|
||||
fclose(CACHEFD);
|
||||
if (msg->message) {
|
||||
ms_free(msg->message);
|
||||
}
|
||||
msg->message = (char *)decrypted_body;
|
||||
|
||||
if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) {
|
||||
ms_free(msg->content_type);
|
||||
msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
|
||||
} else {
|
||||
ms_free(msg->content_type);
|
||||
msg->content_type = ms_strdup("text/plain");
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeDoc(cacheXml);
|
||||
}
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
int errcode = -1;
|
||||
char *content_type = NULL;
|
||||
|
||||
if (linphone_chat_room_lime_available(room)) {
|
||||
if (msg->content_type && strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) {
|
||||
/* it's a file transfer, content type shall be set to
|
||||
application/cipher.vnd.gsma.rcs-ft-http+xml*/
|
||||
content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml";
|
||||
} else {
|
||||
content_type = "xml/cipher";
|
||||
}
|
||||
msg->content_type = ms_strdup(content_type);
|
||||
|
||||
|
||||
/* access the zrtp cache to get keys needed to cipher the message */
|
||||
const char *zrtp_secrets_cache = linphone_core_get_zrtp_secrets_file(lc);
|
||||
FILE *CACHEFD = fopen(zrtp_secrets_cache, "rb+");
|
||||
errcode = 0;
|
||||
if (CACHEFD == NULL) {
|
||||
ms_warning("Unable to access ZRTP ZID cache to encrypt message");
|
||||
errcode = 488;
|
||||
} else {
|
||||
size_t cacheSize;
|
||||
char *cacheString;
|
||||
xmlDocPtr cacheXml;
|
||||
int retval;
|
||||
uint8_t *crypted_body = NULL;
|
||||
char *peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room));
|
||||
|
||||
cacheString=ms_load_file_content(CACHEFD, &cacheSize);
|
||||
if (!cacheString){
|
||||
ms_warning("Unable to load content of ZRTP ZID cache to encrypt message");
|
||||
errcode = 500;
|
||||
return errcode;
|
||||
}
|
||||
cacheString[cacheSize] = '\0';
|
||||
cacheSize += 1;
|
||||
fclose(CACHEFD);
|
||||
cacheXml = xmlParseDoc((xmlChar*)cacheString);
|
||||
ms_free(cacheString);
|
||||
retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg->message, (uint8_t *)peer, &crypted_body);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to encrypt message for %s : %s", peer, lime_error_code_to_string(retval));
|
||||
if (crypted_body) free(crypted_body);
|
||||
errcode = 488;
|
||||
} else {
|
||||
/* 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(zrtp_secrets_cache, "wb+");
|
||||
if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){
|
||||
ms_warning("Unable to write zid cache");
|
||||
}
|
||||
xmlFree(xmlStringOutput);
|
||||
fclose(CACHEFD);
|
||||
if (msg->message) {
|
||||
ms_free(msg->message);
|
||||
}
|
||||
msg->message = (char *)crypted_body;
|
||||
}
|
||||
ms_free(peer);
|
||||
xmlFreeDoc(cacheXml);
|
||||
}
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int lime_im_encryption_engine_process_downloading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char *decrypted_buffer) {
|
||||
if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
|
||||
|
||||
if (buffer == NULL || size == 0) {
|
||||
return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
|
||||
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, decrypted_buffer,
|
||||
(char *)buffer);
|
||||
}
|
||||
|
||||
int lime_im_encryption_engine_process_uploading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, size_t offset, const char *buffer, size_t *size, char *encrypted_buffer) {
|
||||
if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
|
||||
|
||||
if (buffer == NULL || *size == 0) {
|
||||
return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
if (offset + *size < linphone_content_get_size(msg->file_transfer_information)) {
|
||||
*size -= (*size % 16);
|
||||
}
|
||||
|
||||
return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
|
||||
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size,
|
||||
(char *)buffer, encrypted_buffer);
|
||||
}
|
||||
|
||||
bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneCore *lc, LinphoneChatRoom *room) {
|
||||
return linphone_chat_room_lime_available(room) && linphone_core_lime_for_file_sharing_enabled(lc);
|
||||
}
|
||||
|
||||
void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
char keyBuffer [FILE_TRANSFER_KEY_SIZE]; /* temporary storage of generated key: 192 bits of key + 64 bits of initial vector */
|
||||
/* generate a random 192 bits key + 64 bits of initial vector and store it into the
|
||||
* file_transfer_information->key field of the msg */
|
||||
sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE);
|
||||
linphone_content_set_key(msg->file_transfer_information, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
|
||||
}
|
||||
|
||||
#else /* HAVE_LIME */
|
||||
|
||||
|
|
@ -836,6 +1061,27 @@ int lime_getCachedRcvKeyByZid(xmlDocPtr cacheBuffer, limeKey_t *associatedKey) {
|
|||
}
|
||||
int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
|
||||
return LIME_NOT_ENABLED;
|
||||
}
|
||||
bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
|
||||
return FALSE;
|
||||
}
|
||||
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
return 500;
|
||||
}
|
||||
int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
return 500;
|
||||
}
|
||||
int lime_im_encryption_engine_process_downloading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char *decrypted_buffer) {
|
||||
return 500;
|
||||
}
|
||||
int lime_im_encryption_engine_process_uploading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, size_t offset, const char *buffer, size_t *size, char *encrypted_buffer) {
|
||||
return 500;
|
||||
}
|
||||
bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneCore *lc, LinphoneChatRoom *room) {
|
||||
return FALSE;
|
||||
}
|
||||
void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
|
||||
|
||||
}
|
||||
#endif /* HAVE_LIME */
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
|
||||
#include "linphone/core.h"
|
||||
#include <mediastreamer2/mscommon.h>
|
||||
|
||||
#ifndef LINPHONE_PUBLIC
|
||||
|
|
@ -203,4 +204,17 @@ LINPHONE_PUBLIC char *lime_error_code_to_string(int errorCode);
|
|||
* @return TRUE if Lime is available, FALSE if not
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t lime_is_available(void);
|
||||
|
||||
int lime_im_encryption_engine_process_incoming_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneCore* lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
int lime_im_encryption_engine_process_downloading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, const char *buffer, size_t size, char *decrypted_buffer);
|
||||
|
||||
int lime_im_encryption_engine_process_uploading_file_cb(LinphoneCore *lc, LinphoneChatMessage *msg, size_t offset, const char *buffer, size_t *size, char *encrypted_buffer);
|
||||
|
||||
bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneCore *lc, LinphoneChatRoom *room);
|
||||
|
||||
void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
|
||||
#endif /* LIME_H */
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ static void process_response_from_post_file_log_collection(void *data, const bel
|
|||
first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information));
|
||||
|
||||
/* Create a user body handler to take care of the file and add the content disposition and content-type headers */
|
||||
first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, log_collection_upload_on_send_body, core);
|
||||
first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, NULL, log_collection_upload_on_send_body, NULL, core);
|
||||
belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header));
|
||||
belle_sip_free(first_part_header);
|
||||
belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh,
|
||||
|
|
@ -1963,6 +1963,23 @@ void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val){
|
|||
if (linphone_core_ready(lc)){
|
||||
lp_config_set_int(lc->config,"sip","lime",val);
|
||||
}
|
||||
|
||||
if (val != LinphoneLimeDisabled) {
|
||||
LinphoneImEncryptionEngine *imee = linphone_im_encryption_engine_new();
|
||||
LinphoneImEncryptionEngineCbs *cbs = linphone_im_encryption_engine_get_callbacks(imee);
|
||||
linphone_im_encryption_engine_cbs_set_process_incoming_message(cbs, lime_im_encryption_engine_process_incoming_message_cb);
|
||||
linphone_im_encryption_engine_cbs_set_process_outgoing_message(cbs, lime_im_encryption_engine_process_outgoing_message_cb);
|
||||
linphone_im_encryption_engine_cbs_set_process_downloading_file(cbs, lime_im_encryption_engine_process_downloading_file_cb);
|
||||
linphone_im_encryption_engine_cbs_set_process_uploading_file(cbs, lime_im_encryption_engine_process_uploading_file_cb);
|
||||
linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(cbs, lime_im_encryption_engine_is_file_encryption_enabled_cb);
|
||||
linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(cbs, lime_im_encryption_engine_generate_file_transfer_key_cb);
|
||||
lc->im_encryption_engine = imee;
|
||||
} else {
|
||||
if (lc->im_encryption_engine) {
|
||||
linphone_im_encryption_engine_destory(lc->im_encryption_engine);
|
||||
lc->im_encryption_engine = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool_t linphone_core_lime_available(const LinphoneCore *lc){
|
||||
|
|
@ -7199,6 +7216,49 @@ const char *linphone_reason_to_string(LinphoneReason err){
|
|||
return "unknown error";
|
||||
}
|
||||
|
||||
LinphoneReason linphone_error_code_to_reason(int err) {
|
||||
if (err == 200) {
|
||||
return LinphoneReasonNone;
|
||||
} else if (err == 503) {
|
||||
return LinphoneReasonIOError;
|
||||
} else if (err == 400) {
|
||||
return LinphoneReasonUnknown;
|
||||
} else if (err == 486) {
|
||||
return LinphoneReasonBusy;
|
||||
} else if (err == 603) {
|
||||
return LinphoneReasonDeclined;
|
||||
} else if (err == 600) {
|
||||
return LinphoneReasonDoNotDisturb;
|
||||
} else if (err == 403) {
|
||||
return LinphoneReasonForbidden;
|
||||
} else if (err == 415) {
|
||||
return LinphoneReasonUnsupportedContent;
|
||||
} else if (err == 404) {
|
||||
return LinphoneReasonNotFound;
|
||||
} else if (err == 480) {
|
||||
return LinphoneReasonTemporarilyUnavailable;
|
||||
} else if (err == 401) {
|
||||
return LinphoneReasonUnauthorized;
|
||||
} else if (err == 488) {
|
||||
return LinphoneReasonNotAcceptable;
|
||||
} else if (err == 481) {
|
||||
return LinphoneReasonNoMatch;
|
||||
} else if (err == 301) {
|
||||
return LinphoneReasonMovedPermanently;
|
||||
} else if (err == 410) {
|
||||
return LinphoneReasonGone;
|
||||
} else if (err == 484) {
|
||||
return LinphoneReasonAddressIncomplete;
|
||||
} else if (err == 501) {
|
||||
return LinphoneReasonNotImplemented;
|
||||
} else if (err == 504) {
|
||||
return LinphoneReasonServerTimeout;
|
||||
} else if (err == 502) {
|
||||
return LinphoneReasonBadGateway;
|
||||
}
|
||||
return LinphoneReasonUnknown;
|
||||
}
|
||||
|
||||
const char *linphone_error_to_string(LinphoneReason err){
|
||||
return linphone_reason_to_string(err);
|
||||
}
|
||||
|
|
@ -8025,3 +8085,11 @@ const char *linphone_core_get_tls_key_path(const LinphoneCore *lc) {
|
|||
const char *tls_key_path = lp_config_get_string(lc->config, "sip", "client_cert_key", NULL);
|
||||
return tls_key_path;
|
||||
}
|
||||
|
||||
void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee) {
|
||||
lc->im_encryption_engine = imee;
|
||||
}
|
||||
|
||||
LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const LinphoneCore *lc) {
|
||||
return lc->im_encryption_engine;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ LINPHONE_PUBLIC void linphone_core_get_local_ip(LinphoneCore *lc, int af, const
|
|||
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index);
|
||||
void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index);
|
||||
|
||||
void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg);
|
||||
LinphoneReason 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_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call);
|
||||
|
||||
|
|
@ -1072,6 +1072,8 @@ struct _LinphoneCore
|
|||
|
||||
/*default resource list server*/
|
||||
LinphoneAddress *default_rls_addr;
|
||||
|
||||
LinphoneImEncryptionEngine *im_encryption_engine;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#ifndef LINPHONECORE_H
|
||||
#define LINPHONECORE_H
|
||||
|
||||
#include "belle-sip/belle-sip.h"
|
||||
#include "ortp/ortp.h"
|
||||
#include "ortp/payloadtype.h"
|
||||
#include "mediastreamer2/mscommon.h"
|
||||
|
|
@ -206,6 +207,12 @@ typedef enum _LinphoneReason LinphoneReason;
|
|||
**/
|
||||
LINPHONE_PUBLIC const char *linphone_reason_to_string(LinphoneReason err);
|
||||
|
||||
/**
|
||||
* Converts a error code to a LinphoneReason.
|
||||
* @ingroup misc
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_error_code_to_reason(int err);
|
||||
|
||||
/**
|
||||
* Object representing full details about a signaling error or status.
|
||||
* All LinphoneErrorInfo object returned by the liblinphone API are readonly and transcients. For safety they must be used immediately
|
||||
|
|
@ -1509,7 +1516,7 @@ LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr)
|
|||
*
|
||||
* @return true if zrtp secrets have already been shared and ready to use
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Returns an list of chat rooms
|
||||
|
|
@ -1668,7 +1675,7 @@ LINPHONE_PUBLIC LinphoneAddress *linphone_chat_message_get_local_address(const L
|
|||
/**
|
||||
* Add custom headers to the message.
|
||||
* @param message the message
|
||||
* @param header_name name of the header_name
|
||||
* @param header_name name of the header
|
||||
* @param header_value header value
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value);
|
||||
|
|
@ -1678,6 +1685,12 @@ LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage
|
|||
* @param header_name header name searched
|
||||
**/
|
||||
LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name);
|
||||
/**
|
||||
* Removes a custom header from the message.
|
||||
* @param message the message
|
||||
* @param header_name name of the header to remove
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name);
|
||||
/**
|
||||
* Returns TRUE if the message has been read, otherwise returns FALSE.
|
||||
* @param message the message
|
||||
|
|
@ -4599,6 +4612,24 @@ LINPHONE_PUBLIC const char *linphone_core_get_tls_cert_path(const LinphoneCore *
|
|||
*/
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_tls_key_path(const LinphoneCore *lc);
|
||||
|
||||
#include "linphone/im_encryption_engine.h"
|
||||
|
||||
/**
|
||||
* @ingroup chatroom
|
||||
* Sets an IM Encryption Engine in the core
|
||||
* @param lc LinphoneCore object
|
||||
* @param imee LinphoneImEncryptionEngine object
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee);
|
||||
|
||||
/**
|
||||
* @ingroup chatroom
|
||||
* Gets the IM Encryption Engine in the core if possible
|
||||
* @param lc LinphoneCore object
|
||||
* @return the IM Encryption Engine in the core or NULL
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneImEncryptionEngine * linphone_core_get_im_encryption_engine(const LinphoneCore *lc);
|
||||
|
||||
#include "linphone/ringtoneplayer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -851,6 +851,7 @@ void sal_resolve_cancel(SalResolverContext *ctx);
|
|||
|
||||
SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value);
|
||||
const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name);
|
||||
SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name);
|
||||
void sal_custom_header_free(SalCustomHeader *ch);
|
||||
SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,25 +74,35 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess
|
|||
* */
|
||||
void file_transfer_received(LinphoneChatMessage *msg, const LinphoneContent* content, const LinphoneBuffer *buffer){
|
||||
FILE* file=NULL;
|
||||
char *receive_file = bc_tester_file("receive_file.dump");
|
||||
char *receive_file = NULL;
|
||||
LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg);
|
||||
LinphoneCore *lc = linphone_chat_room_get_core(cr);
|
||||
if (!linphone_chat_message_get_user_data(msg)) {
|
||||
/*first chunk, creating file*/
|
||||
file = fopen(receive_file,"wb");
|
||||
linphone_chat_message_set_user_data(msg,(void*)file); /*store fd for next chunks*/
|
||||
}
|
||||
bc_free(receive_file);
|
||||
file = (FILE*)linphone_chat_message_get_user_data(msg);
|
||||
BC_ASSERT_PTR_NOT_NULL(file);
|
||||
if (linphone_buffer_is_empty(buffer)) { /* tranfer complete */
|
||||
stats* counters = get_stats(lc);
|
||||
counters->number_of_LinphoneFileTransferDownloadSuccessful++;
|
||||
linphone_chat_message_set_user_data(msg, NULL);
|
||||
fclose(file);
|
||||
} else { /* store content on a file*/
|
||||
if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==0){
|
||||
ms_error("file_transfer_received(): write() failed: %s",strerror(errno));
|
||||
|
||||
if (linphone_chat_message_get_file_transfer_filepath(msg) != NULL) {
|
||||
if (linphone_buffer_is_empty(buffer)) {
|
||||
stats* counters = get_stats(lc);
|
||||
counters->number_of_LinphoneFileTransferDownloadSuccessful++;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
receive_file = bc_tester_file("receive_file.dump");
|
||||
if (!linphone_chat_message_get_user_data(msg)) {
|
||||
/*first chunk, creating file*/
|
||||
file = fopen(receive_file,"wb");
|
||||
linphone_chat_message_set_user_data(msg,(void*)file); /*store fd for next chunks*/
|
||||
}
|
||||
bc_free(receive_file);
|
||||
file = (FILE*)linphone_chat_message_get_user_data(msg);
|
||||
BC_ASSERT_PTR_NOT_NULL(file);
|
||||
if (linphone_buffer_is_empty(buffer)) { /* tranfer complete */
|
||||
stats* counters = get_stats(lc);
|
||||
counters->number_of_LinphoneFileTransferDownloadSuccessful++;
|
||||
linphone_chat_message_set_user_data(msg, NULL);
|
||||
fclose(file);
|
||||
} else { /* store content on a file*/
|
||||
if (fwrite(linphone_buffer_get_content(buffer),linphone_buffer_get_size(buffer),1,file)==0){
|
||||
ms_error("file_transfer_received(): write() failed: %s",strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -196,7 +206,7 @@ void compare_files(const char *path1, const char *path2) {
|
|||
buf2 = (uint8_t*)ms_load_path_content(path2, &size2);
|
||||
BC_ASSERT_PTR_NOT_NULL(buf1);
|
||||
BC_ASSERT_PTR_NOT_NULL(buf2);
|
||||
BC_ASSERT_EQUAL((uint8_t)size1, (uint8_t)size2, uint8_t, "%u");
|
||||
BC_ASSERT_EQUAL((uint8_t)size2, (uint8_t)size1, uint8_t, "%u");
|
||||
BC_ASSERT_EQUAL(memcmp(buf1, buf2, size1), 0, int, "%d");
|
||||
ms_free(buf1);
|
||||
ms_free(buf2);
|
||||
|
|
@ -234,6 +244,30 @@ LinphoneChatMessage* create_message_from_nowebcam(LinphoneChatRoom *chat_room) {
|
|||
return msg;
|
||||
}
|
||||
|
||||
LinphoneChatMessage* create_file_transfer_message_from_nowebcam(LinphoneChatRoom *chat_room) {
|
||||
LinphoneChatMessageCbs *cbs;
|
||||
LinphoneContent* content;
|
||||
LinphoneChatMessage* msg;
|
||||
char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg");
|
||||
|
||||
content = linphone_core_create_content(chat_room->lc);
|
||||
belle_sip_object_set_name(&content->base, "nowebcam content");
|
||||
linphone_content_set_type(content,"image");
|
||||
linphone_content_set_subtype(content,"jpeg");
|
||||
linphone_content_set_name(content,"nowebcamCIF.jpg");
|
||||
|
||||
|
||||
msg = linphone_chat_room_create_file_transfer_message(chat_room, content);
|
||||
linphone_chat_message_set_file_transfer_filepath(msg, send_filepath);
|
||||
cbs = linphone_chat_message_get_callbacks(msg);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed);
|
||||
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
|
||||
|
||||
linphone_content_unref(content);
|
||||
ms_free(send_filepath);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void text_message_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline) {
|
||||
LinphoneChatMessage* msg = linphone_chat_room_create_message(linphone_core_get_chat_room(pauline->lc,marie->identity),"Bli bli bli \n blu");
|
||||
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg);
|
||||
|
|
@ -411,20 +445,28 @@ static void text_message_with_external_body(void) {
|
|||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error) {
|
||||
void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download) {
|
||||
char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg");
|
||||
char *receive_filepath = bc_tester_file("receive_file.dump");
|
||||
LinphoneChatRoom* chat_room;
|
||||
LinphoneChatMessage* msg;
|
||||
LinphoneChatMessageCbs *cbs;
|
||||
|
||||
/* Remove any previously downloaded file */
|
||||
remove(receive_filepath);
|
||||
|
||||
/* Globally configure an http file transfer server. */
|
||||
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
|
||||
|
||||
/* create a chatroom on pauline's side */
|
||||
chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
|
||||
/* create a file transfer msg */
|
||||
msg = create_message_from_nowebcam(chat_room);
|
||||
if (use_file_body_handler_in_upload) {
|
||||
msg = create_file_transfer_message_from_nowebcam(chat_room);
|
||||
} else {
|
||||
msg = create_message_from_nowebcam(chat_room);
|
||||
}
|
||||
|
||||
linphone_chat_room_send_chat_message(chat_room,msg);
|
||||
|
||||
if (upload_error) {
|
||||
|
|
@ -448,6 +490,9 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau
|
|||
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
|
||||
linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received);
|
||||
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
|
||||
if (use_file_body_handler_in_download) {
|
||||
linphone_chat_message_set_file_transfer_filepath(marie->stat.last_received_chat_message, receive_filepath);
|
||||
}
|
||||
linphone_chat_message_download_file(marie->stat.last_received_chat_message);
|
||||
|
||||
if (download_error) {
|
||||
|
|
@ -471,25 +516,37 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau
|
|||
bc_free(receive_filepath);
|
||||
}
|
||||
|
||||
void transfer_message_base(bool_t upload_error, bool_t download_error) {
|
||||
void transfer_message_base(bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download) {
|
||||
if (transport_supported(LinphoneTransportTls)) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
transfer_message_base2(marie,pauline,upload_error,download_error);
|
||||
transfer_message_base2(marie,pauline,upload_error,download_error, use_file_body_handler_in_upload, use_file_body_handler_in_download);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(marie);
|
||||
}
|
||||
}
|
||||
static void transfer_message(void) {
|
||||
transfer_message_base(FALSE, FALSE);
|
||||
transfer_message_base(FALSE, FALSE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void transfer_message_2(void) {
|
||||
transfer_message_base(FALSE, FALSE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
static void transfer_message_3(void) {
|
||||
transfer_message_base(FALSE, FALSE, FALSE, TRUE);
|
||||
}
|
||||
|
||||
static void transfer_message_4(void) {
|
||||
transfer_message_base(FALSE, FALSE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void transfer_message_with_upload_io_error(void) {
|
||||
transfer_message_base(TRUE, FALSE);
|
||||
transfer_message_base(TRUE, FALSE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void transfer_message_with_download_io_error(void) {
|
||||
transfer_message_base(FALSE, TRUE);
|
||||
transfer_message_base(FALSE, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void transfer_message_upload_cancelled(void) {
|
||||
|
|
@ -604,6 +661,9 @@ static void file_transfer_2_messages_simultaneously(void) {
|
|||
char *receive_filepath = bc_tester_file("receive_file.dump");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
|
||||
/* Remove any previously downloaded file */
|
||||
remove(receive_filepath);
|
||||
|
||||
/* Globally configure an http file transfer server. */
|
||||
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
|
||||
|
||||
|
|
@ -809,6 +869,10 @@ static void lime_text_message(void) {
|
|||
linphone_chat_room_send_message(chat_room,"Bla bla bla bla");
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedLegacy,1));
|
||||
BC_ASSERT_PTR_NOT_NULL(marie->stat.last_received_chat_message);
|
||||
if (marie->stat.last_received_chat_message) {
|
||||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "Bla bla bla bla");
|
||||
}
|
||||
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity));
|
||||
/* TODO : check the msg arrived correctly deciphered */
|
||||
|
|
@ -853,14 +917,19 @@ end:
|
|||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_stored_msg) {
|
||||
void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_stored_msg, bool_t use_file_body_handler_in_upload, bool_t use_file_body_handler_in_download) {
|
||||
FILE *ZIDCacheMarieFD, *ZIDCachePaulineFD;
|
||||
LinphoneCoreManager *marie, *pauline;
|
||||
LinphoneChatMessage *msg;
|
||||
LinphoneChatMessageCbs *cbs;
|
||||
char *pauline_id, *marie_id;
|
||||
char *filepath;
|
||||
char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg");
|
||||
char *receive_filepath = bc_tester_file("receive_file.dump");
|
||||
MSList * msg_list = NULL;
|
||||
|
||||
/* Remove any previously downloaded file */
|
||||
remove(receive_filepath);
|
||||
|
||||
marie = linphone_core_manager_new( "marie_rc");
|
||||
pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
|
|
@ -901,7 +970,11 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st
|
|||
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
|
||||
|
||||
/* create a file transfer msg */
|
||||
msg = create_message_from_nowebcam(linphone_core_get_chat_room(pauline->lc, marie->identity));
|
||||
if (use_file_body_handler_in_upload) {
|
||||
msg = create_file_transfer_message_from_nowebcam(linphone_core_get_chat_room(pauline->lc, marie->identity));
|
||||
} else {
|
||||
msg = create_message_from_nowebcam(linphone_core_get_chat_room(pauline->lc, marie->identity));
|
||||
}
|
||||
|
||||
linphone_chat_room_send_chat_message(msg->chat_room, msg);
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1));
|
||||
|
|
@ -926,8 +999,13 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st
|
|||
BC_ASSERT_PTR_NOT_NULL(linphone_content_get_key(content));
|
||||
else
|
||||
BC_ASSERT_PTR_NULL(linphone_content_get_key(content));
|
||||
|
||||
if (use_file_body_handler_in_download) {
|
||||
linphone_chat_message_set_file_transfer_filepath(recv_msg, receive_filepath);
|
||||
}
|
||||
linphone_chat_message_download_file(recv_msg);
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1));
|
||||
compare_files(send_filepath, receive_filepath);
|
||||
bctbx_list_free_with_data(msg_list, (bctbx_list_free_func)linphone_chat_message_unref);
|
||||
}
|
||||
|
||||
|
|
@ -935,20 +1013,38 @@ void lime_transfer_message_base(bool_t encrypt_file,bool_t download_file_from_st
|
|||
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageDelivered,1, int, "%d");
|
||||
BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1, int, "%d");
|
||||
end:
|
||||
ms_free(send_filepath);
|
||||
bc_free(receive_filepath);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void lime_transfer_message(void) {
|
||||
lime_transfer_message_base(TRUE,FALSE);
|
||||
lime_transfer_message_base(TRUE, FALSE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_2(void) {
|
||||
lime_transfer_message_base(TRUE, FALSE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_3(void) {
|
||||
lime_transfer_message_base(TRUE, FALSE, FALSE, TRUE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_4(void) {
|
||||
lime_transfer_message_base(TRUE, FALSE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_from_history(void) {
|
||||
lime_transfer_message_base(TRUE,TRUE);
|
||||
lime_transfer_message_base(TRUE, TRUE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_without_encryption(void) {
|
||||
lime_transfer_message_base(FALSE,FALSE);
|
||||
lime_transfer_message_base(FALSE, FALSE, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void lime_transfer_message_without_encryption_2(void) {
|
||||
lime_transfer_message_base(FALSE, FALSE, TRUE, FALSE);
|
||||
}
|
||||
|
||||
static void printHex(char *title, uint8_t *data, size_t length) {
|
||||
|
|
@ -1818,12 +1914,41 @@ void file_transfer_with_http_proxy(void) {
|
|||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
linphone_core_set_http_proxy_host(marie->lc, "sip.linphone.org");
|
||||
transfer_message_base2(marie,pauline,FALSE,FALSE);
|
||||
transfer_message_base2(marie,pauline,FALSE,FALSE,FALSE,FALSE);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(marie);
|
||||
}
|
||||
}
|
||||
|
||||
void chat_message_custom_headers(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(pauline->lc, marie->identity);
|
||||
LinphoneChatMessage* msg = linphone_chat_room_create_message(chat_room, "Lorem Ipsum");
|
||||
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg);
|
||||
|
||||
linphone_chat_message_add_custom_header(msg, "Test1", "Value1");
|
||||
linphone_chat_message_add_custom_header(msg, "Test2", "Value2");
|
||||
linphone_chat_message_remove_custom_header(msg, "Test1");
|
||||
|
||||
linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed);
|
||||
linphone_chat_room_send_chat_message(chat_room,msg);
|
||||
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1));
|
||||
|
||||
if (marie->stat.last_received_chat_message) {
|
||||
const char *header = linphone_chat_message_get_custom_header(marie->stat.last_received_chat_message, "Test2");
|
||||
BC_ASSERT_STRING_EQUAL(header, "Value2");
|
||||
header = linphone_chat_message_get_custom_header(marie->stat.last_received_chat_message, "Test1");
|
||||
BC_ASSERT_PTR_NULL(header);
|
||||
BC_ASSERT_STRING_EQUAL(marie->stat.last_received_chat_message->message, "Lorem Ipsum");
|
||||
}
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
test_t message_tests[] = {
|
||||
TEST_NO_TAG("Text message", text_message),
|
||||
TEST_NO_TAG("Text message within call dialog", text_message_within_call_dialog),
|
||||
|
|
@ -1834,6 +1959,9 @@ test_t message_tests[] = {
|
|||
TEST_NO_TAG("Text message with send error", text_message_with_send_error),
|
||||
TEST_NO_TAG("Text message with external body", text_message_with_external_body),
|
||||
TEST_NO_TAG("Transfer message", transfer_message),
|
||||
TEST_NO_TAG("Transfer message 2", transfer_message_2),
|
||||
TEST_NO_TAG("Transfer message 3", transfer_message_3),
|
||||
TEST_NO_TAG("Transfer message 4", transfer_message_4),
|
||||
TEST_NO_TAG("Transfer message with http proxy", file_transfer_with_http_proxy),
|
||||
TEST_NO_TAG("Transfer message with upload io error", transfer_message_with_upload_io_error),
|
||||
TEST_NO_TAG("Transfer message with download io error", transfer_message_with_download_io_error),
|
||||
|
|
@ -1848,8 +1976,12 @@ test_t message_tests[] = {
|
|||
TEST_NO_TAG("Lime text message", lime_text_message),
|
||||
TEST_NO_TAG("Lime text message to non lime", lime_text_message_to_non_lime),
|
||||
TEST_NO_TAG("Lime transfer message", lime_transfer_message),
|
||||
TEST_NO_TAG("Lime transfer message 2", lime_transfer_message_2),
|
||||
TEST_NO_TAG("Lime transfer message 3", lime_transfer_message_3),
|
||||
TEST_NO_TAG("Lime transfer message 4", lime_transfer_message_4),
|
||||
TEST_NO_TAG("Lime transfer message from history", lime_transfer_message_from_history),
|
||||
TEST_NO_TAG("Lime transfer message without encryption", lime_transfer_message_without_encryption),
|
||||
TEST_NO_TAG("Lime transfer message without encryption 2", lime_transfer_message_without_encryption_2),
|
||||
TEST_NO_TAG("Lime unitary", lime_unit),
|
||||
#ifdef SQLITE_STORAGE_ENABLED
|
||||
TEST_NO_TAG("Database migration", database_migration),
|
||||
|
|
@ -1874,6 +2006,7 @@ test_t message_tests[] = {
|
|||
TEST_ONE_TAG("Real Time Text offer answer with different payload numbers (sender side)", real_time_text_message_different_text_codecs_payload_numbers_sender_side, "RTT"),
|
||||
TEST_ONE_TAG("Real Time Text offer answer with different payload numbers (receiver side)", real_time_text_message_different_text_codecs_payload_numbers_receiver_side, "RTT"),
|
||||
TEST_ONE_TAG("Real Time Text copy paste", real_time_text_copy_paste, "RTT"),
|
||||
TEST_NO_TAG("IM Encryption Engine custom headers", chat_message_custom_headers),
|
||||
};
|
||||
|
||||
test_suite_t message_test_suite = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue