Commit c10b5f65 authored by johan's avatar johan
Browse files

File transfer implemented following RCS5.1 recommendation

- memory leaks to be fixed
parent 49e8c4f9
......@@ -55,6 +55,11 @@ 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;
}
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;
......@@ -69,7 +74,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) {
}
static void add_message_accept(belle_sip_message_t *msg){
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml"));
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, application/vnd.gsma.rcs-ft-http+xml"));
}
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
......@@ -85,11 +90,13 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve
char* from;
bool_t plain_text=FALSE;
bool_t external_body=FALSE;
bool_t rcs_filetransfer=FALSE;
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
if (content_type && ((plain_text=is_plain_text(content_type))
|| (external_body=is_external_body(content_type)))) {
|| (external_body=is_external_body(content_type))
|| (rcs_filetransfer=is_rcs_filetransfer(content_type)))) {
SalMessage salmsg;
char message_id[256]={0};
......@@ -104,8 +111,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?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
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 */
salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml";
}
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 "*/
......
......@@ -25,6 +25,7 @@
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
#include "belle-sip/belle-sip.h"
#include <libxml/xmlwriter.h>
......@@ -32,6 +33,135 @@
#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60
#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120
static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg);
#define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449"
#define MULTIPART_HEADER_1 "--" MULTIPART_BOUNDARY "\r\n" \
"Content-Disposition: form-data; name=\"File\"; filename=\""
#define MULTIPART_HEADER_2 "\"\r\n" \
"Content-Type: "
#define MULTIPART_HEADER_3 "\r\n\r\n"
#define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n"
const char *multipart_boundary=MULTIPART_BOUNDARY;
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);
}
static void process_io_error(void *data, const belle_sip_io_error_event_t *event){
printf("We have a response io error!\n");
}
static void process_auth_requested(void *data, belle_sip_auth_event_t *event){
printf("We have a auth requested!\n");
}
/**
* Callback called during upload or download of a file from server
* It is just forwarding the call and some parameters to the vtable defined callback
*/
static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total){
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* call back given by application level */
if (lc->vtable.file_transfer_progress_indication != NULL) {
lc->vtable.file_transfer_progress_indication(lc, chatMsg, chatMsg->file_transfer_information, (size_t)(((double)offset/(double)total)*100.0));
}
return;
}
/**
* Callback called when posting a file to server (following rcs5.1 recommendation)
*
* @param bh the body handler
* @param msg the belle sip message
* @param data the user data associated to the handler, contains the linphoneChatMessage we're working on
* @param offset current position in the input buffer
* @param buffer the ouput buffer we to copy the data to be uploaded
* @param size size in byte of the data requested, as output it will contain the effective copied size
*
*/
static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, void *buffer, size_t *size){
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype);
size_t end_of_file=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size;
if (offset==0){
int partlen=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type);
memcpy(buffer,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1));
buffer += strlen(MULTIPART_HEADER_1);
memcpy(buffer,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name));
buffer += strlen(chatMsg->file_transfer_information->name);
memcpy(buffer,MULTIPART_HEADER_2,strlen(MULTIPART_HEADER_2));
buffer += strlen(MULTIPART_HEADER_2);
memcpy(buffer,content_type,strlen(content_type));
buffer += strlen(content_type);
memcpy(buffer,MULTIPART_HEADER_3,strlen(MULTIPART_HEADER_3));
*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);
}else{
*size=strlen(MULTIPART_END);
strncpy(buffer,MULTIPART_END,*size);
}
belle_sip_free(content_type);
return BELLE_SIP_CONTINUE;
}
/**
* Callback function called when we have a response from server during a file upload to server (rcs5.1 recommandation)
* Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server
* to upoad the file. The server response to this second post is processed by this same function
*
* @param data the user define pointer associated with the request, it contains the linphoneChatMessage we're trying to send
* @param event the response from server
*/
static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
/* check the answer code */
if (event->response){
int code=belle_http_response_get_status_code(event->response);
if (code == 204) { /* this is the reply to the first post to the server - an empty message */
/* start uploading the file */
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
char *content_type=belle_sip_strdup_printf("%s/%s", msg->file_transfer_information->type, msg->file_transfer_information->subtype);
belle_sip_user_body_handler_t *bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_multipart_header_size(msg->file_transfer_information->name, content_type)+strlen(MULTIPART_END), linphone_chat_message_file_transfer_on_progress, NULL, linphone_chat_message_file_transfer_on_send_body, msg);
belle_sip_free(content_type);
content_type=belle_sip_strdup_printf("multipart/form-data; boundary=%s",multipart_boundary);
uri=belle_generic_uri_parse(msg->chat_room->lc->file_transfer_server);
req=belle_http_request_create("POST",
uri,
belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION),
belle_sip_header_create("Content-type",content_type),
NULL);
belle_sip_free(content_type);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req),BELLE_SIP_BODY_HANDLER(bh));
cbs.process_response=linphone_chat_message_process_response_from_post_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg);
belle_http_provider_send_request(msg->chat_room->lc->http_provider,req,l);
}
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);
msg->file_transfer_information = NULL;
msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
_linphone_chat_room_send_message(msg->chat_room, msg);
}
}
}
static void _linphone_chat_message_destroy(LinphoneChatMessage* msg);
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage);
......@@ -178,6 +308,30 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
const char *identity=NULL;
time_t t=time(NULL);
/* Check if we shall upload a file to a server */
if (msg->file_transfer_information != NULL) {
/* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
uri=belle_generic_uri_parse(cr->lc->file_transfer_server);
req=belle_http_request_create("POST",
uri,
NULL,
NULL,
NULL);
cbs.process_response=linphone_chat_message_process_response_from_post_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */
belle_http_provider_send_request(cr->lc->http_provider,req,l);
return;
}
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
......@@ -207,7 +361,11 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
sal_message_send(op,identity,cr->peer,content_type, NULL);
ms_free(content_type);
} else {
sal_text_send(op, identity, cr->peer,msg->message);
if (msg->content_type == NULL) {
sal_text_send(op, identity, cr->peer,msg->message);
} else {
sal_message_send(op, identity, cr->peer, msg->content_type, msg->message);
}
}
msg->dir=LinphoneChatMessageOutgoing;
msg->from=linphone_address_new(identity);
......@@ -280,7 +438,65 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
msg = linphone_chat_room_create_message(cr, sal_msg->text);
if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer bu twe shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */
msg = linphone_chat_room_create_message(cr, NULL); /* create a message 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 = (LinphoneContent *)malloc(sizeof(LinphoneContent));
memset(msg->file_transfer_information, 0, sizeof(*(msg->file_transfer_information)));
xmlChar *file_url = NULL;
/* parse the message body to get all informations from it */
xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text);
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 */
cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
while (cur!=NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) {
xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
msg->file_transfer_information->size = strtol((const char*)fileSizeString, NULL, 10);
xmlFree(fileSizeString);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) {
msg->file_transfer_information->name = (char *)xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) {
xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
int contentTypeIndex = 0;
while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') {
contentTypeIndex++;
}
msg->file_transfer_information->type = strndup((char *)contentType, contentTypeIndex);
msg->file_transfer_information->subtype = strdup(((char *)contentType+contentTypeIndex+1));
xmlFree(contentType);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
file_url = xmlGetProp(cur, (const xmlChar *)"url");
}
cur=cur->next;
}
xmlFree(typeAttribute);
break;
}
xmlFree(typeAttribute);
}
cur = cur->next;
}
}
xmlFreeDoc(xmlMessageBody);
linphone_chat_message_set_external_body_url(msg, (const char *)file_url);
xmlFree(file_url);
} else { /* message is not rcs file transfer, create it with provided sal_msg->text as ->message */
msg = linphone_chat_room_create_message(cr, sal_msg->text);
}
linphone_chat_message_set_from(msg, cr->peer_url);
{
......@@ -299,6 +515,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
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);
linphone_chat_room_message_received(cr,lc,msg);
......@@ -426,6 +643,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message=message?ms_strdup(message):NULL;
msg->is_read=TRUE;
msg->content_type = NULL; /* this property is used only when transfering file */
return msg;
}
......@@ -452,6 +670,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2(
msg->time=time;
msg->state=state;
msg->is_read=is_read;
msg->content_type = NULL; /* this property is used only when transfering file */
if (is_incoming) {
msg->dir=LinphoneChatMessageIncoming;
linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr));
......@@ -668,6 +887,87 @@ void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,co
message->external_body_url=url?ms_strdup(url):NULL;
}
/**
* Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer)
*
* @param message #LinphoneChatMessage
* @return a pointer to the LinphoneContent structure or NULL if not present.
*/
const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage*message) {
return message->file_transfer_information;
}
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);
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);
}
return;
/* feed the callback with the received data */
}
static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event){
if (event->response){
/*we are receiving a response, set a specific body handler to acquire the response.
* if not done, belle-sip will create a memory body handler, the default*/
LinphoneChatMessage *message=belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message");
belle_sip_message_set_body_handler(
(belle_sip_message_t*)event->response,
(belle_sip_body_handler_t*)belle_sip_user_body_handler_new(message->file_transfer_information->size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message)
);
}
}
static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event){
//LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
/* check the answer code */
if (event->response){
int code=belle_http_response_get_status_code(event->response);
if (code==200) {
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* 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);
}
}
}
}
/**
* Start the download of the file from remote server
*
* @param message #LinphoneChatMessage
*/
void linphone_chat_message_start_file_download(const LinphoneChatMessage *message) {
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
belle_http_request_t *req;
const char *url=message->external_body_url;
uri=belle_generic_uri_parse(url);
req=belle_http_request_create("GET",
uri,
belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION),
NULL);
cbs.process_response_headers=linphone_chat_process_response_headers_from_get_file;
cbs.process_response=linphone_chat_process_response_from_get_file;
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs, (void *)message);
belle_sip_object_data_set(BELLE_SIP_OBJECT(req),"message",(void *)message,NULL);
belle_http_provider_send_request(message->chat_room->lc->http_provider,req,l);
}
/**
* Set origin of the message
*@param message #LinphoneChatMessage obj
......@@ -834,6 +1134,7 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->from) linphone_address_destroy(msg->from);
if (msg->to) linphone_address_destroy(msg->to);
if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);
if (msg->content_type) ms_free(msg->content_type);
}
......@@ -868,6 +1169,27 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) {
return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg));
}
/**
* Create a message attached to a dedicated chat room with a particular content. Use #linphone_chat_room_send_message2 to initiate the transfer
* @param cr the chat room.
* @param a #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if #LinphoneContent.data is NULL.
* @return a new #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content) {
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message = NULL;
msg->file_transfer_information = initial_content;
msg->dir=LinphoneChatMessageOutgoing;
linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr));
linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc)));
msg->content_type=NULL; /* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */
return msg;
}
/**
* @}
*/
......
......@@ -79,6 +79,8 @@ notify_LDADD=$(helloworld_LDADD)
filetransfer_SOURCES=filetransfer.c
LINPHONE_TUTOS+=$(filetransfer_SOURCES)
filetransfer_LDADD=$(helloworld_LDADD)
AM_CFLAGS=\
-I$(top_srcdir)/coreapi \
$(STRICT_OPTIONS) \
......
......@@ -52,7 +52,7 @@ static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMess
const LinphoneAddress* from_address = linphone_chat_message_get_from(message);
const LinphoneAddress* to_address = linphone_chat_message_get_to(message);
char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address);
printf(" File transfer [%i&] %s of type [%s/%s] %s [%s] \n", (int)(content->size/progress)*100
printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)progress
,(linphone_chat_message_is_outgoing(message)?"sent":"received")
, content->type
, content->subtype
......@@ -73,31 +73,32 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag
, from);
if (!linphone_chat_message_get_user_data(message)) {
/*first chunk, creating file*/
file = open("receive_file.dump",O_WRONLY);
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)linphone_chat_message_get_user_data(message);
file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
}
/*store content on a file*/
write(file,buff,size);
if (size==0) {
printf("File transfert completed");
printf("File transfert completed\n");
close(file);
} /*else wait for next chunk*/
running=FALSE;
} else { /* store content on a file*/
write(file,buff,size);
}
free(from);
}
char big_file [128000];
/*
* function call when is file transfer is initiated. file content should be feed into object LinphoneContent
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
* */
static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){
const LinphoneAddress* to_address = linphone_chat_message_get_to(message);
char *to = linphone_address_as_string(to_address);
//const LinphoneAddress* to_address = linphone_chat_message_get_to(message);
//char *to = linphone_address_as_string(to_address);
int offset=-1;
/*content->size can be feed*/
......@@ -106,7 +107,7 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message,
offset=0;
} else {
/*subsequent chunk*/
offset = (int)linphone_chat_message_get_user_data(message);
offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF);
}
*size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/
......@@ -119,11 +120,22 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message,
printf(" File transfer sending [%i] bytes of type [%s/%s] from [%s] \n" , (int)*size
, content->type
, content->subtype
, to);
, "pipo");
/*store offset for next chunk*/
linphone_chat_message_set_user_data(message,(void*)(offset+*size));
free(to);
//free(to);
}
/*
* Call back called when a message is received
*/
static void message_received(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
const LinphoneContent *file_transfer_info = linphone_chat_message_get_file_transfer_information(msg);
printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", file_transfer_info->name, file_transfer_info->size);
linphone_chat_message_start_file_download(msg);
}
/*
......@@ -137,21 +149,21 @@ static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,Linpho
free(to);
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable={0};
char* dest_friend=NULL;
const char* dest_friend=NULL;
int i;
const char* big_file_content="big file";
/*seting dummy file content to something*/
for (i=0;i<sizeof(big_file)/strlen(big_file_content);i++)
sprintf(big_file+i,"%s",big_file_content);
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";
/* takes sip uri identity from the command line arguments */
if (argc>1){
dest_friend=argv[1];
}
signal(SIGINT,stop);
//#define DEBUG
#ifdef DEBUG
......@@ -166,20 +178,24 @@ int main(int argc, char *argv[]){
vtable.file_transfer_received=file_transfer_received;
vtable.file_transfer_send=file_transfer_send;
vtable.file_transfer_progress_indication=file_transfer_progress_indication;
vtable.message_received=message_received;
/*
Instantiate a LinphoneCore object given the LinphoneCoreVTable
*/
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
dest_friend = linphone_core_get_primary_contact(lc);
printf("Send message to me : %s\n", dest_friend);
/**
* Globally configure an http file transfer server.
*/
linphone_core_set_file_transfer_server(lc,"http://sharing.linphone.org/upload.php");
linphone_core_set_file_transfer_server(lc,"http://npasc.al/lft.php");
//linphone_core_set_file_transfer_server(lc,"https://www.linphone.org:444/upload.php");
/*Next step is to create a chat root*/
/*Next step is to create a chat room*/
LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend);
LinphoneContent content;
......@@ -187,13 +203,16 @@ int main(int argc, char *argv[]){
content.type="text";
content.subtype="plain";
content.size=sizeof(big_file); /*total size to be transfered*/
content.name = "bigfile.txt";