Commit 6bdc6496 authored by johan's avatar johan

Add encrypted file transfer message

+ test for the encrypted text message
+ fix bug introduced in last merge
parent b302a87c
......@@ -61,8 +61,8 @@ static void process_response_event(void *op_base, const belle_sip_response_event
}
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;
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) {
......@@ -71,8 +71,11 @@ static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) {
}
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;
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
......@@ -84,7 +87,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) {
}
static void add_message_accept(belle_sip_message_t *msg){
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cioher, application/vnd.gsma.rcs-ft-http+xml"));
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, xml/cipher, application/vnd.gsma.rcs-ft-http+xml, application/cipher.vnd.gsma.rcs-ft-http+xml"));
}
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
......@@ -148,10 +151,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
}
}
rcs_filetransfer=is_rcs_filetransfer(content_type);
if (content_type && ((plain_text=is_plain_text(content_type))
|| (external_body=is_external_body(content_type))
|| (decryptedMessage!=NULL)
|| (rcs_filetransfer=is_rcs_filetransfer(content_type)))) {
|| rcs_filetransfer)) {
SalMessage salmsg;
char message_id[256]={0};
......@@ -166,8 +171,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
,belle_sip_header_call_id_get_call_id(call_id)
,belle_sip_header_cseq_get_seq_number(cseq));
salmsg.from=from;
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):(cipher_xml?(char *)decryptedMessage:NULL);
salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
/* 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.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 */
......@@ -235,7 +244,7 @@ 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) {
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, "r+");
......
......@@ -26,6 +26,8 @@
#include "private.h"
#include "lpconfig.h"
#include "belle-sip/belle-sip.h"
#include "lime.h"
#include "ortp/b64.h"
#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15
#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60
......@@ -42,6 +44,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
#define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n"
const char *multipart_boundary=MULTIPART_BOUNDARY;
#define FILE_TRANSFER_KEY_SIZE 32
static size_t linphone_chat_message_compute_multipart_header_size(const char *filename, const char *content_type) {
return strlen(MULTIPART_HEADER_1)+strlen(filename)+strlen(MULTIPART_HEADER_2)+strlen(content_type)+strlen(MULTIPART_HEADER_3);
}
......@@ -98,12 +101,34 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
*size=partlen;
}else if (offset<end_of_file){
/* get data from call back */
lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size);
if (chatMsg->file_transfer_information->key != NULL) { /* if we have a key to cipher the message, use it! */
/* get data from callback to a plainBuffer */
/* if this chunk is not the last one, the lenght must be a multiple of block cipher size(16 bytes)*/
if (offset+*size<end_of_file) {
*size -=(*size%16);
}
char *plainBuffer = (char *)malloc(*size);
lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size);
lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, *size, plainBuffer, buffer);
free(plainBuffer);
} else {
/* get data from call back directly to the output buffer */
lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size);
}
/* DEBUG DEBUG : THIS SHALL NEVER HAPPEND */
if (*size == 0) {
exit(1);
}
}else{
/* conclude the file ciphering if needed */
if (chatMsg->file_transfer_information->key != NULL) {
lime_encryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL);
}
*size=strlen(MULTIPART_END);
strncpy(buffer,MULTIPART_END,*size);
}
belle_sip_free(content_type);
return BELLE_SIP_CONTINUE;
}
......@@ -123,6 +148,12 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co
if (event->response){
int code=belle_http_response_get_status_code(event->response);
if (code == 204) { /* this is the reply to the first post to the server - an empty message */
/* shall we encrypt the file */
if (msg->chat_room->lc->lime == 1) {
/* generate a random 192 bits key + 64 bits of initial vector and store it into the file_transfer_information->key field of the message */
msg->file_transfer_information->key = (unsigned char *)malloc(FILE_TRANSFER_KEY_SIZE);
sal_get_random_bytes(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE);
}
/* start uploading the file */
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
......@@ -150,7 +181,46 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co
}
if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
msg->message = ms_strdup(body);
/* if we have an encryption key for the file, we must insert it into the message */
if (msg->file_transfer_information->key != NULL) {
/* parse the message body */
xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body);
xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody);
if (cur != NULL) {
cur = cur->xmlChildrenNode;
while (cur!=NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */
xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for : add a file-key children node */
/* convert key to base64 */
int b64Size = b64_encode(NULL, FILE_TRANSFER_KEY_SIZE, NULL, 0);
char *keyb64 = (char *)malloc(b64Size+1);
b64Size = b64_encode(msg->file_transfer_information->key, FILE_TRANSFER_KEY_SIZE, keyb64, b64Size);
keyb64[b64Size] = '\0'; /* libxml need a null terminated string */
/* add the node containing the key to the file-info node */
xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64);
xmlFree(typeAttribute);
/* dump the xml into msg->message */
int xmlStringLength;
xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength, "UTF-8", 0);
break;
}
xmlFree(typeAttribute);
}
cur = cur->next;
}
}
xmlFreeDoc(xmlMessageBody);
} else { /* no encryption key, transfer in plain, just copy the message sent by server */
msg->message = ms_strdup(body);
}
linphone_content_uninit(msg->file_transfer_information);
ms_free(msg->file_transfer_information);
msg->file_transfer_information = NULL;
......@@ -365,7 +435,12 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
} else {
if (cr->lc->lime == 1) { /* shall we try to encrypt messages? */
linphone_chat_message_ref(msg); /* ref the message or it may be destroyed by callback if the encryption failed */
sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)));
msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
if (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*/
sal_message_send(op, identity, cr->peer, "application/cipher.vnd.gsma.rcs-ft-http+xml", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)));
} else {
sal_message_send(op, identity, cr->peer, "xml/cipher", msg->message, linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)));
}
} else {
if (msg->content_type == NULL) {
sal_text_send(op, identity, cr->peer,msg->message);
......@@ -487,6 +562,15 @@ 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 message: file has been encrypted */
/* convert the key from base 64 */
xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
int keyLength = b64_decode((char *)keyb64, strlen((char *)keyb64), NULL, 0);
msg->file_transfer_information->key = (uint8_t *)malloc(keyLength);
b64_decode((char *)keyb64, strlen((char *)keyb64), msg->file_transfer_information->key, keyLength);
xmlFree(keyb64);
}
cur=cur->next;
}
xmlFree(typeAttribute);
......@@ -944,12 +1028,27 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const
}
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const void *buffer, size_t size){
//printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer);
/* first call may be with a zero size, ignore it */
if (size == 0) {
return;
}
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* call back given by application level */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size);
if (chatMsg->file_transfer_information->key != NULL) { /* we have a key, we must decrypt the file */
/* get data from callback to a plainBuffer */
char *plainBuffer = (char *)malloc(size);
lime_decryptFile(&(chatMsg->file_transfer_information->cryptoContext), chatMsg->file_transfer_information->key, size, plainBuffer, (char *)buffer);
/* call back given by application level */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, plainBuffer, size);
}
free(plainBuffer);
} else { /* regular file, no deciphering */
/* call back given by application level */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size);
}
}
return;
......@@ -979,6 +1078,10 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
if (code==200) {
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* if we the file was encrypted, finish the decryption and free context */
if (chatMsg->file_transfer_information->key) {
lime_decryptFile(&(chatMsg->file_transfer_information->cryptoContext), NULL, 0, NULL, NULL);
}
/* file downloaded succesfully, call again the callback with size at zero */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0);
......
......@@ -69,20 +69,19 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag
/*first chunk, creating file*/
file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/
} else {
/*next chunk*/
file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
if (size==0) {
printf("File transfert completed\n");
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
close(file);
running=FALSE;
} else { /* store content on a file*/
write(file,buff,size);
}
}
/*next chunk*/
file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
if (size==0) {
printf("File transfert completed\n");
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
close(file);
running=FALSE;
} else { /* store content on a file*/
write(file,buff,size);
}
}
......@@ -192,9 +191,6 @@ int main(int argc, char *argv[]){
/*now create a chat message with custom content*/
LinphoneChatMessage* chat_message = linphone_chat_room_create_file_transfer_message(chat_room,&content);
if (chat_message == NULL) {
printf("returned message is null\n");
}
/*initiating file transfer*/
linphone_chat_room_send_message2(chat_room, chat_message, linphone_file_transfer_state_changed, NULL);
......
......@@ -47,6 +47,14 @@ void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){
SET_STRING(obj,subtype,ref->subtype);
SET_STRING(obj,encoding,ref->encoding);
SET_STRING(obj,name,ref->name);
if (obj->key) {
ms_free(obj->key);
obj->key=NULL;
}
if (ref->key) {
obj->key = (unsigned char *)ms_strdup((const char *)ref->key);
}
if (obj->data) {
ms_free(obj->data);
obj->data=NULL;
......@@ -65,6 +73,7 @@ void linphone_content_uninit(LinphoneContent * obj){
if (obj->data) ms_free(obj->data);
if (obj->encoding) ms_free(obj->encoding);
if (obj->name) ms_free(obj->name);
if (obj->key) ms_free(obj->key);
}
LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){
......@@ -81,6 +90,8 @@ LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const
((char*)obj->data)[ref->size]='\0';
}
obj->size=ref->size;
obj->name = NULL;
obj->key = NULL;
return obj;
}
......@@ -91,6 +102,8 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons
obj->data=(void*)ref->data;
obj->encoding=(char*)ref->encoding;
obj->size=ref->size;
obj->name = NULL;
obj->key = NULL;
return obj;
}
return NULL;
......
......@@ -436,6 +436,56 @@ int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageL
return 0;
}
int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
gcm_context *gcmContext;
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
gcmContext = (gcm_context *)malloc(sizeof(gcm_context));
*cryptoContext = (void *)gcmContext;
gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192);
gcm_starts(gcmContext, GCM_ENCRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */
} else { /* this is not the first call, get the context */
gcmContext = (gcm_context *)*cryptoContext;
}
if (length != 0) {
gcm_update(gcmContext, length, (const unsigned char *)plain, (unsigned char *)cipher);
} else { /* lenght is 0, finish the stream */
gcm_finish(gcmContext, NULL, 0); /* do not generate tag */
gcm_free(gcmContext);
free(*cryptoContext);
*cryptoContext = NULL;
}
return 0;
}
int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
gcm_context *gcmContext;
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
gcmContext = (gcm_context *)malloc(sizeof(gcm_context));
*cryptoContext = (void *)gcmContext;
gcm_init(gcmContext, POLARSSL_CIPHER_ID_AES, key, 192);
gcm_starts(gcmContext, GCM_DECRYPT, key+24, 8, NULL, 0); /* key contains 192bits of key || 64 bits of Initialisation Vector */
} else { /* this is not the first call, get the context */
gcmContext = (gcm_context *)*cryptoContext;
}
if (length != 0) {
gcm_update(gcmContext, length, (const unsigned char *)cipher, (unsigned char *)plain);
} else { /* lenght is 0, finish the stream */
gcm_finish(gcmContext, NULL, 0); /* do not generate tag */
gcm_free(gcmContext);
free(*cryptoContext);
*cryptoContext = NULL;
}
return 0;
}
int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
/* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */
uint8_t authenticatedData[28];
......
......@@ -113,6 +113,34 @@ __attribute__ ((visibility ("default"))) int lime_deriveKey(limeKey_t *key);
*/
__attribute__ ((visibility ("default"))) int lime_encryptMessage(limeKey_t *key, uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage);
/**
* @brief Encrypt a file before transfering it to the server, encryption is done in several call, first one will be done with cryptoContext null, last one with length = 0
*
* @param[in/out] cryptoContext The context used to encrypt the file using AES-GCM. Is created at first call(if null)
* @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector
* @param[in] length Length of data to be encrypted, if 0 it will conclude the encryption
* @param[in] plain Plain data to be encrypted (length bytes)
* @param[out] cipher Output to a buffer allocated by caller, at least length bytes available
*
* @return 0 on success, error code otherwise
*
*/
__attribute__ ((visibility ("default"))) int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher);
/**
* @brief Decrypt a file retrieved from server, decryption is done in several call, first one will be done with cryptoContext null, last one with length = 0
*
* @param[in/out] cryptoContext The context used to decrypt the file using AES-GCM. Is created at first call(if null)
* @param[in] key 256 bits : 192 bits of key || 64 bits of Initial Vector
* @param[in] length Length of data to be decrypted, if 0 it will conclude the decryption
* @param[out] plain Output to a buffer allocated by caller, at least length bytes available
* @param[in] cipher Cipher text to be decrypted(length bytes)
*
* @return 0 on success, error code otherwise
*
*/
__attribute__ ((visibility ("default"))) int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher);
/**
* @brief decrypt and authentify a message with the given key
*
......
......@@ -138,6 +138,8 @@ struct _LinphoneContent{
When provided by callback #LinphoneCoreFileTransferSendCb or #LinphoneCoreFileTransferReceiveCb, it states the total number of bytes of the transfered file*/
char *encoding; /**<The encoding of the data buffer, for example "gzip"*/
char *name; /**< used by RCS File transfer messages to store the original filename of the file to be downloaded from server */
unsigned char *key; /**< used by RCS File transfer messages to store the key to encrypt file if needed */
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
};
/**
......
<?xml version="1.0" encoding="UTF-8"?>
<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>f6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4</sndKey><rcvKey>bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000074</sndIndex><rcvIndex>000001a2</rcvIndex></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>b438386ce7d91f0c3341315ff58ce14826a119f36d91650ca26fa7fde2f16012</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>0000000c</sndIndex><rcvIndex>00000000</rcvIndex></peer></cache>
<cache><selfZID>ef7692d0792a67491ae2d44e</selfZID><peer><ZID>005dbe0399643d953a2202dd</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd159</sndKey><rcvKey>5b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c3</rcvKey><sndSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000077</sndIndex><rcvIndex>000001c6</rcvIndex></peer><peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:pauline@sip.example.org</uri><sndKey>72d80ab1cad243cf45634980c1d02cfb2df81ce0dd5dfcf1ebeacfc5345a9176</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>0000000f</sndIndex><rcvIndex>00000000</rcvIndex></peer></cache>
<?xml version="1.0" encoding="UTF-8"?>
<cache><selfZID>005dbe0399643d953a2202dd</selfZID>
<peer><ZID>ef7692d0792a67491ae2d44e</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><rcvKey>f6e5c94feabbe348f25a528cc990b7ec0f3390286314eb70cf2a9a852afb2df4</rcvKey><sndKey>bfd9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</sndKey><rcvSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvIndex>00000074</rcvIndex><sndIndex>000001a2</sndIndex></peer>
<peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>pipo1@pipo.com</uri><sndKey>123456789012345678901234567890123456765431262068d2df23e8f9b77193</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000001</sndIndex><rcvIndex>00000000</rcvIndex></peer></cache>
<peer><ZID>ef7692d0792a67491ae2d44e</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:marie@sip.example.org</uri><rcvKey>6cac6d8e4453ccf70749674c421b7ca434d300ca30265a9a86b2979c32bdd159</rcvKey><sndKey>5b91adffd91fcfa5b9cc6907a7d59bd5c21ffe8d508b4d6c536cb73329c914c3</sndKey><rcvSId>5f9aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndSId>bcffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvIndex>00000077</rcvIndex><sndIndex>000001c6</sndIndex></peer>
<peer><ZID>1234567889643d953a2202ee</ZID><rs1>9b5c8f06f3b6c2c695f2dfc3c26f31f5fef8661f8c5fe7c95aeb5c5b0435b045</rs1><aux>f8324dd18ea905171ec2be89f879d01d5994132048d92ea020778cbdf31c605e</aux><rs2>2fdcef69380937c2cf221f7d11526f286c39f49641452ba9012521c705094899</rs2><uri>sip:marie@sip.example.org</uri><sndKey>21397a0d145badd58b3073ba0f537cab1bc97ca7de1f0d2db9a57fc3f63b74b7</sndKey><rcvKey>25d9ac653a83c4559cb0ae7394e7cd3b2d3c57bb28e62068d2df23e8f9b77193</rcvKey><sndSId>f69aa1e5e4c7ec88fa389a9f6b8879b42d3c57bb28e62068d2df23e8f9b77193</sndSId><rcvSId>22ffd51e7316a6c6f53a50fcf01b01bf2d3c57bb28e62068d2df23e8f9b77193</rcvSId><sndIndex>00000025</sndIndex><rcvIndex>00000000</rcvIndex></peer></cache>
......@@ -62,27 +62,26 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess
* */
void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){
int file=-1;
/* first chunk, creating file */
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk, creating file*/
file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/
} else {
/*next chunk*/
file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
if (size==0) { /* tranfer complerte */
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
stats* counters = get_stats(lc);
counters->number_of_LinphoneMessageExtBodyReceived++;
close(file);
} else { /* store content on a file*/
write(file,buff,size);
}
}
file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
if (size==0) { /* tranfer complete */
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
stats* counters = get_stats(lc);
counters->number_of_LinphoneMessageExtBodyReceived++;
close(file);
} else { /* store content on a file*/
write(file,buff,size);
}
}
static char big_file [128000]; /* a buffer to simulate a big file for the file transfer message test */
char big_file[128000]; /* a buffer to simulate a big file for the file transfer message test */
/*
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
......@@ -364,9 +363,13 @@ static void file_transfer_message(void) {
int i;
/* setting dummy file content to something */
const char* big_file_content="big file";
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
for (i=0;i<=sizeof(big_file)-strlen(big_file_content);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
if (i<sizeof(big_file)) {
memcpy(big_file+i, big_file_content, sizeof(big_file)-i);
}
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
......@@ -404,6 +407,55 @@ static void file_transfer_message(void) {
linphone_core_manager_destroy(pauline);
}
static void lime_file_transfer_message(void) {
int i;
/* setting dummy file content to something */
const char* big_file_content="big file";
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
/* make sure lime is enabled */
linphone_core_set_lime(marie->lc, 1);
linphone_core_set_lime(pauline->lc, 1);
/* set the zid caches files */
linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml");
linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml");
/* 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 */
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
/* create a file transfer message */
LinphoneContent content;
memset(&content,0,sizeof(content));
content.type="text";
content.subtype="plain";
content.size=sizeof(big_file); /*total size to be transfered*/
content.name = "bigfile.txt";
LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chat_room, &content);
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void text_message_with_send_error(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
......@@ -567,7 +619,7 @@ void printHex(char *title, uint8_t *data, uint32_t length) {
printf ("\n");
}
static void lime(void) {
static void lime_unit(void) {
int retval;
/* Load Alice cache file */
FILE *CACHE = fopen("ZIDCacheAlice.xml", "r+");
......@@ -599,7 +651,7 @@ static void lime(void) {
/* encrypt a message */
uint8_t *multipartMessage = NULL;
retval = lime_createMultipartMessage(cacheBufferAlice, (uint8_t *)"Bonjour les petits lapins,ca va? éh oui oui", (uint8_t *)"pipo1@pipo.com", &multipartMessage);
retval = lime_createMultipartMessage(cacheBufferAlice, (uint8_t *)"Bonjour les petits lapins,ca va? éh oui oui", (uint8_t *)"sip:pauline@sip.example.org", &multipartMessage);
printf("create message return %d\n", retval);
if (retval == 0) {
......@@ -720,6 +772,34 @@ static void lime(void) {
xmlFreeDoc(cacheBuffer);
}
static void lime_text_message(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
/* make sure lime is enabled */
linphone_core_set_lime(marie->lc, 1);
linphone_core_set_lime(pauline->lc, 1);
/* set the zid caches files */
linphone_core_set_zrtp_secrets_file(marie->lc, "ZIDCacheAlice.xml");
linphone_core_set_zrtp_secrets_file(pauline->lc, "ZIDCacheBob.xml");
char* to = linphone_address_as_string(marie->identity);
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to);
ms_free(to);
linphone_chat_room_send_message(chat_room,"Bla bla bla bla");
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1));
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1);
CU_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity));
/* TODO : check the message arrived correctly deciphered */
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#ifdef MSG_STORAGE_ENABLED
/*
......@@ -813,11 +893,13 @@ test_t message_tests[] = {
{ "Text message with send error", text_message_with_send_error },
{ "Text message with external body", text_message_with_external_body },
{ "File transfer message", file_transfer_message },
{ "Lime File transfer message", lime_file_transfer_message },
{ "Text message denied", text_message_denied },
{ "Info message", info_message },
{ "Info message with body", info_message_with_body },
{ "IsComposing notification", is_composing_notification },
{ "Lime", lime }
{ "Lime Unitary", lime_unit },
{ "Lime Text Message", lime_text_message }
#ifdef MSG_STORAGE_ENABLED
,{ "Database migration", message_storage_migration }
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment