diff --git a/build/android/Android.mk b/build/android/Android.mk
index adc78454c..9690877ee 100755
--- a/build/android/Android.mk
+++ b/build/android/Android.mk
@@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \
bellesip_sal/sal_op_publish.c \
bellesip_sal/sal_op_registration.c \
bellesip_sal/sal_sdp.c \
+ buffer.c \
callbacks.c \
call_log.c \
call_params.c \
diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj
index 6a3d8e034..7e692e325 100644
--- a/build/wp8/LibLinphone.vcxproj
+++ b/build/wp8/LibLinphone.vcxproj
@@ -110,6 +110,7 @@
+
@@ -145,6 +146,7 @@
+
diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt
index 92689dcb8..1a4f48665 100644
--- a/coreapi/CMakeLists.txt
+++ b/coreapi/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SOURCE_FILES
bellesip_sal/sal_op_publish.c
bellesip_sal/sal_op_registration.c
bellesip_sal/sal_sdp.c
+ buffer.c
callbacks.c
call_log.c
call_params.c
@@ -153,6 +154,7 @@ install(TARGETS linphone
set(HEADER_FILES
+ buffer.h
call_log.h
call_params.h
content.h
diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am
index f7d163749..160d0a420 100644
--- a/coreapi/Makefile.am
+++ b/coreapi/Makefile.am
@@ -25,6 +25,7 @@ CLEANFILES=$(GITVERSION_FILE)
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=\
+ buffer.h \
call_log.h \
call_params.h \
content.h \
@@ -44,6 +45,7 @@ lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES=\
address.c \
authentication.c \
+ buffer.c \
callbacks.c \
call_log.c \
call_params.c \
diff --git a/coreapi/buffer.c b/coreapi/buffer.c
new file mode 100644
index 000000000..8e44f832b
--- /dev/null
+++ b/coreapi/buffer.c
@@ -0,0 +1,105 @@
+/*
+linphone
+Copyright (C) 2010-2014 Belledonne Communications SARL
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "linphonecore.h"
+#include "private.h"
+
+
+
+static void linphone_buffer_destroy(LinphoneBuffer *buffer) {
+ if (buffer->content) belle_sip_free(buffer->content);
+}
+
+BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneBuffer);
+
+BELLE_SIP_INSTANCIATE_VPTR(LinphoneBuffer, belle_sip_object_t,
+ (belle_sip_object_destroy_t)linphone_buffer_destroy,
+ NULL, // clone
+ NULL, // marshal
+ TRUE
+);
+
+
+LinphoneBuffer * linphone_buffer_new(void) {
+ LinphoneBuffer *buffer = belle_sip_object_new(LinphoneBuffer);
+ belle_sip_object_ref(buffer);
+ return buffer;
+}
+
+LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size) {
+ LinphoneBuffer *buffer = linphone_buffer_new();
+ linphone_buffer_set_content(buffer, data, size);
+ return buffer;
+}
+
+LinphoneBuffer * linphone_buffer_new_from_string(const char *data) {
+ LinphoneBuffer *buffer = linphone_buffer_new();
+ linphone_buffer_set_string_content(buffer, data);
+ return buffer;
+}
+
+LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer) {
+ belle_sip_object_ref(buffer);
+ return buffer;
+}
+
+void linphone_buffer_unref(LinphoneBuffer *buffer) {
+ belle_sip_object_unref(buffer);
+}
+
+void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer) {
+ return buffer->user_data;
+}
+
+void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud) {
+ buffer->user_data = ud;
+}
+
+const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer) {
+ return buffer->content;
+}
+
+void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size) {
+ buffer->size = size;
+ if (buffer->content) belle_sip_free(buffer->content);
+ buffer->content = belle_sip_malloc(size);
+ memcpy(buffer->content, content, size);
+}
+
+const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer) {
+ return (const char *)buffer->content;
+}
+
+void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content) {
+ buffer->size = strlen(content);
+ if (buffer->content) belle_sip_free(buffer->content);
+ buffer->content = (uint8_t *)belle_sip_strdup(content);
+}
+
+size_t linphone_buffer_get_size(const LinphoneBuffer *buffer) {
+ return buffer->size;
+}
+
+void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size) {
+ buffer->size = size;
+}
+
+bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer) {
+ return (buffer->size == 0) ? TRUE : FALSE;
+}
diff --git a/coreapi/buffer.h b/coreapi/buffer.h
new file mode 100644
index 000000000..0d22e9ad2
--- /dev/null
+++ b/coreapi/buffer.h
@@ -0,0 +1,147 @@
+/*
+buffer.h
+Copyright (C) 2010-2014 Belledonne Communications SARL
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef LINPHONE_BUFFER_H_
+#define LINPHONE_BUFFER_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @addtogroup misc
+ * @{
+ */
+
+/**
+ * The LinphoneContent object representing a data buffer.
+**/
+typedef struct _LinphoneBuffer LinphoneBuffer;
+
+
+/**
+ * Create a new empty LinphoneBuffer object.
+ * @return A new LinphoneBuffer object.
+ */
+LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new(void);
+
+/**
+ * Create a new LinphoneBuffer object from existing data.
+ * @param[in] data The initial data to store in the LinphoneBuffer.
+ * @param[in] size The size of the initial data to stroe in the LinphoneBuffer.
+ * @return A new LinphoneBuffer object.
+ */
+LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size);
+
+/**
+ * Create a new LinphoneBuffer object from a string.
+ * @param[in] data The initial string content of the LinphoneBuffer.
+ * @return A new LinphoneBuffer object.
+ */
+LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_string(const char *data);
+
+/**
+ * Acquire a reference to the buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @return The same LinphoneBuffer object.
+**/
+LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer);
+
+/**
+ * Release reference to the buffer.
+ * @param[in] buffer LinphoneBuffer object.
+**/
+LINPHONE_PUBLIC void linphone_buffer_unref(LinphoneBuffer *buffer);
+
+/**
+ * Retrieve the user pointer associated with the buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @return The user pointer associated with the buffer.
+**/
+LINPHONE_PUBLIC void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer);
+
+/**
+ * Assign a user pointer to the buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @param[in] ud The user pointer to associate with the buffer.
+**/
+LINPHONE_PUBLIC void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud);
+
+/**
+ * Get the content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @return The content of the data buffer.
+ */
+LINPHONE_PUBLIC const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer);
+
+/**
+ * Set the content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @param[in] content The content of the data buffer.
+ * @param[in] size The size of the content of the data buffer.
+ */
+LINPHONE_PUBLIC void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size);
+
+/**
+ * Get the string content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object
+ * @return The string content of the data buffer.
+ */
+LINPHONE_PUBLIC const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer);
+
+/**
+ * Set the string content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @param[in] content The string content of the data buffer.
+ */
+LINPHONE_PUBLIC void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content);
+
+/**
+ * Get the size of the content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object.
+ * @return The size of the content of the data buffer.
+ */
+LINPHONE_PUBLIC size_t linphone_buffer_get_size(const LinphoneBuffer *buffer);
+
+/**
+ * Set the size of the content of the data buffer.
+ * @param[in] buffer LinphoneBuffer object
+ * @param[in] size The size of the content of the data buffer.
+ */
+LINPHONE_PUBLIC void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size);
+
+/**
+ * Tell whether the LinphoneBuffer is empty.
+ * @param[in] buffer LinphoneBuffer object
+ * @return A boolean value telling whether the LinphoneBuffer is empty or not.
+ */
+LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer);
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LINPHONE_CONTENT_H_ */
diff --git a/coreapi/chat.c b/coreapi/chat.c
index 7bec11b01..d80f133b1 100644
--- a/coreapi/chat.c
+++ b/coreapi/chat.c
@@ -246,7 +246,13 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
if (offsetfile_transfer_information)){
/* get data from call back */
if (linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)) {
- linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, buf, size);
+ LinphoneBuffer *lb = linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, offset, *size);
+ if (lb == NULL) *size = 0;
+ else {
+ *size = linphone_buffer_get_size(lb);
+ memcpy(buffer, linphone_buffer_get_content(lb), *size);
+ linphone_buffer_unref(lb);
+ }
} else {
/* Legacy */
linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size);
@@ -1205,7 +1211,9 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t
return;
}
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
- linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
+ LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size);
+ linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
+ linphone_buffer_unref(lb);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
@@ -1279,7 +1287,9 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
LinphoneCore *lc = chatMsg->chat_room->lc;
/* file downloaded succesfully, call again the callback with size at zero */
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
- linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, NULL, 0);
+ LinphoneBuffer *lb = linphone_buffer_new();
+ linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
+ linphone_buffer_unref(lb);
} else {
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0);
}
diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h
index 81d9e4ab0..5c24d14a7 100644
--- a/coreapi/linphonecore.h
+++ b/coreapi/linphonecore.h
@@ -366,12 +366,14 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#ifdef IN_LINPHONE
+#include "buffer.h"
#include "call_log.h"
#include "call_params.h"
#include "content.h"
#include "event.h"
#include "linphonefriend.h"
#else
+#include "linphone/buffer.h"
#include "linphone/call_log.h"
#include "linphone/call_params.h"
#include "linphone/content.h"
@@ -1350,30 +1352,24 @@ typedef void (*LinphoneChatMessageCbsMsgStateChangedCb)(LinphoneChatMessage* msg
/**
* File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file.
- *
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
- * @param buff pointer to the received data
- * @param size number of bytes to be read from buff. 0 means end of file.
- *
+ * @param buffer #LinphoneBuffer holding the received data. Empty buffer means end of file.
*/
-typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size);
+typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer);
/**
- * File transfer send callback prototype. This function is called by the core upon an outgoing File transfer is started. This function is called until size is set to 0.
- *
a #LinphoneContent with a size equal zero
- *
+ * File transfer send callback prototype. This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0.
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent outgoing content
- * @param buff pointer to the buffer where data chunk shall be written by the app
- * @param size as input value, it represents the number of bytes expected by the framework. As output value, it means the number of bytes wrote by the application in the buffer. 0 means end of file.
- *
+ * @param offset the offset in the file from where to get the data to be sent
+ * @param size the number of bytes expected by the framework
+ * @return A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file.
*/
-typedef void (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size);
+typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
/**
* File transfer progress indication callback prototype.
- *
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param offset The number of bytes sent/received since the beginning of the transfer.
diff --git a/coreapi/private.h b/coreapi/private.h
index a8816b04b..fb84eab14 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -936,6 +936,14 @@ struct _LinphoneContent {
BELLE_SIP_DECLARE_VPTR(LinphoneContent);
+struct _LinphoneBuffer {
+ belle_sip_object_t base;
+ void *user_data;
+ uint8_t *content; /**< A pointer to the buffer content */
+ size_t size; /**< The size of the buffer content */
+};
+
+BELLE_SIP_DECLARE_VPTR(LinphoneBuffer);
/*****************************************************************************
@@ -1012,6 +1020,7 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc);
*/
BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000)
+BELLE_SIP_TYPE_ID(LinphoneBuffer),
BELLE_SIP_TYPE_ID(LinphoneContactProvider),
BELLE_SIP_TYPE_ID(LinphoneContactSearch),
BELLE_SIP_TYPE_ID(LinphoneCall),
diff --git a/tools/genapixml.py b/tools/genapixml.py
index 42afb2e08..656428b9e 100755
--- a/tools/genapixml.py
+++ b/tools/genapixml.py
@@ -433,9 +433,16 @@ class Project:
if pos == -1:
return None
returntype = definition[0:pos].strip()
- if returntype != "void":
- return None
returnarg = CArgument(returntype, enums = self.enums, structs = self.__structs)
+ returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']")
+ if returndesc is not None:
+ if returnarg.ctype == 'MSList':
+ n = returndesc.find('.//mslist')
+ if n is not None:
+ returnarg.containedType = n.text
+ returnarg.description = self.__cleanDescription(returndesc)
+ elif returnarg.completeType != 'void':
+ missingDocWarning += "\tReturn value is not documented\n"
definition = definition[pos + 2 :]
pos = string.find(definition, "(")
definition = definition[pos + 1 : -1]
diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py
index 8d89b79c2..ff62efd30 100755
--- a/tools/python/apixml2python.py
+++ b/tools/python/apixml2python.py
@@ -38,6 +38,9 @@ blacklisted_events = [
'LinphoneCoreFileTransferSendCb' # missing LinphoneContent
]
blacklisted_functions = [
+ 'linphone_buffer_new_from_data',
+ 'linphone_buffer_get_content',
+ 'linphone_buffer_set_content',
'linphone_call_log_get_local_stats', # missing rtp_stats_t
'linphone_call_log_get_remote_stats', # missing rtp_stats_t
'linphone_call_params_get_privacy', # missing LinphonePrivacyMask
diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py
index 93f5f4c31..19f4cd6f7 100644
--- a/tools/python/apixml2python/linphone.py
+++ b/tools/python/apixml2python/linphone.py
@@ -238,24 +238,7 @@ class MethodDefinition:
self.method_type = 'instancemethod'
def format_local_variables_definition(self):
- body = ''
- if self.xml_method_return is not None:
- self.return_type = self.xml_method_return.get('type')
- self.return_complete_type = self.xml_method_return.get('completetype')
- self.return_contained_type = self.xml_method_return.get('containedtype')
- if is_callback(self.return_complete_type):
- body += "\tPyObject * pyresult;\n"
- body += "\tPyObject * pyret;\n"
- argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
- self.build_value_format = argument_type.fmt_str
- elif self.return_complete_type != 'void':
- body += "\t" + self.return_complete_type + " cresult;\n"
- argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
- self.build_value_format = argument_type.fmt_str
- if self.build_value_format == 'O':
- body += "\tPyObject * pyresult;\n"
- body += "\tPyObject * pyret;\n"
- body += "\tconst char *pyret_fmt;\n"
+ body = self.format_local_return_variables_definition()
if self.self_arg is not None:
body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n"
for xml_method_arg in self.xml_method_args:
@@ -473,6 +456,27 @@ class MethodDefinition:
body = body[1:] # Remove leading '\t'
return body
+ def format_local_return_variables_definition(self):
+ body = ''
+ if self.xml_method_return is not None:
+ self.return_type = self.xml_method_return.get('type')
+ self.return_complete_type = self.xml_method_return.get('completetype')
+ self.return_contained_type = self.xml_method_return.get('containedtype')
+ if is_callback(self.return_complete_type):
+ body += "\tPyObject * pyresult;\n"
+ body += "\tPyObject * pyret;\n"
+ argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
+ self.build_value_format = argument_type.fmt_str
+ elif self.return_complete_type != 'void':
+ body += "\t" + self.return_complete_type + " cresult;\n"
+ argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
+ self.build_value_format = argument_type.fmt_str
+ if self.build_value_format == 'O':
+ body += "\tPyObject * pyresult;\n"
+ body += "\tPyObject * pyret;\n"
+ body += "\tconst char *pyret_fmt;\n"
+ return body
+
def parse_method_node(self):
if self.method_node is not None:
self.xml_method_return = self.method_node.find('./return')
@@ -778,6 +782,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
nocallbacks_class_name = class_name
if class_name.endswith('Cbs'):
nocallbacks_class_name = class_name[:-3]
+ returnvars = self.format_local_return_variables_definition()
common = \
""" pylinphone_{class_name}Object *pyself = (pylinphone_{class_name}Object *){function_prefix}get_user_data(self);
PyObject *func;
@@ -796,7 +801,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
specific += "\tPyObject * py" + arg_name + " = NULL;\n"
- return "{common}\n{specific}".format(common=common, specific=specific)
+ return "{returnvars}\n{common}\n{specific}".format(returnvars=returnvars, common=common, specific=specific)
def format_arguments_parsing(self):
if self.class_['event_class'] == 'Core':
@@ -832,6 +837,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
def format_c_function_call(self):
create_python_objects_code = ''
+ convert_python_result_code = ''
fmt = 'O'
args = ['pyself']
for xml_method_arg in self.xml_method_args:
@@ -852,22 +858,52 @@ class EventCallbackMethodDefinition(MethodDefinition):
type_class = self.find_class_definition(arg_type)
create_python_objects_code += "\t\tpy{name} = pylinphone_{arg_type}_from_native_ptr(&pylinphone_{arg_type}Type, {name});\n".format(name=arg_name, arg_type=strip_leading_linphone(arg_type))
args=', '.join(args)
+ if self.return_complete_type != 'void':
+ argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
+ if argument_type.fmt_str == 'O':
+ convert_python_result_code = \
+""" if ((pyresult != Py_None) && !PyObject_IsInstance(pyresult, (PyObject *)&pylinphone_{class_name}Type)) {{
+ PyErr_SetString(PyExc_TypeError, "The return value must be a linphone.{class_name} instance.");
+ return NULL;
+ }}
+ if ((cresult = pylinphone_{class_name}_get_native_ptr(pyresult)) == NULL) {{
+ return NULL;
+ }}
+""".format(class_name=strip_leading_linphone(self.return_type))
+
+ else:
+ convert_python_result_code = "\t\tcresult = {convertfunc}(pyresult);\n".format(convertfunc=argument_type.convert_func)
return \
""" if ((func != NULL) && PyCallable_Check(func)) {{
{create_python_objects_code}
args = Py_BuildValue("{fmt}", {args});
- if (PyEval_CallObject(func, args) == NULL) {{
+ pyresult = PyEval_CallObject(func, args);
+ if (pyresult == NULL) {{
PyErr_Print();
}}
Py_DECREF(args);
+{convert_python_result_code}
}}
-""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code)
+""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code, convert_python_result_code=convert_python_result_code)
def format_return_trace(self):
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);\n"
def format_return_result(self):
- return '\tPyGILState_Release(pygil_state);'
+ s = '\tPyGILState_Release(pygil_state);'
+ if self.return_complete_type != 'void':
+ s += '\n\treturn cresult;'
+ return s
+
+ def format_local_return_variables_definition(self):
+ body = "\tPyObject * pyresult;"
+ if self.xml_method_return is not None:
+ self.return_type = self.xml_method_return.get('type')
+ self.return_complete_type = self.xml_method_return.get('completetype')
+ self.return_contained_type = self.xml_method_return.get('containedtype')
+ if self.return_complete_type != 'void':
+ body += "\n\t" + self.return_complete_type + " cresult;"
+ return body
def format(self):
body = MethodDefinition.format(self)
@@ -882,10 +918,10 @@ class EventCallbackMethodDefinition(MethodDefinition):
arg_complete_type = xml_method_arg.get('completetype')
arguments.append(arg_complete_type + ' ' + arg_name)
definition = \
-"""static void pylinphone_{class_name}_callback_{event_name}({arguments}) {{
+"""static {returntype} pylinphone_{class_name}_callback_{event_name}({arguments}) {{
{body}
}}
-""".format(class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
+""".format(returntype=self.return_complete_type, class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
return definition
diff --git a/tools/python/unittests/test_message.py b/tools/python/unittests/test_message.py
index ebd53fc66..a17b8f47e 100644
--- a/tools/python/unittests/test_message.py
+++ b/tools/python/unittests/test_message.py
@@ -3,11 +3,17 @@ from copy import deepcopy
import linphone
from linphonetester import *
import os
+import os.path
import time
class TestMessage:
+ @classmethod
+ def teardown_class(cls):
+ if os.path.exists('receive_file.dump'):
+ os.remove('receive_file.dump')
+
@classmethod
def msg_state_changed(cls, msg, state):
stats = msg.chat_room.core.user_data.stats
@@ -24,18 +30,23 @@ class TestMessage:
linphonetester_logger.error("[TESTER] Unexpected state [{state}] for message [{msg}]".format(msg=msg, state=linphone.ChatMessageState.string(state)))
@classmethod
- def file_transfer_received(cls, msg, content, buf, size):
- print buf, size
+ def file_transfer_send(cls, msg, content, offset, size):
+ if offset >= len(msg.user_data):
+ return linphone.Buffer.new() # end of file
+ return linphone.Buffer.new_from_string(msg.user_data[offset:offset+size])
+
+ @classmethod
+ def file_transfer_recv(cls, msg, content, buf):
stats = msg.chat_room.core.user_data.stats
if msg.user_data is None:
msg.user_data = open('receive_file.dump', 'wb')
- msg.user_data.write(buf)
+ msg.user_data.write(buf.string_content)
else:
- if size == 0: # Transfer complete
+ if buf.size == 0: # Transfer complete
stats.number_of_LinphoneMessageExtBodyReceived += 1
msg.user_data.close()
else: # Store content
- msg.user_data.write(buf)
+ msg.user_data.write(buf.string_content)
def wait_for_server_to_purge_messages(self, manager1, manager2):
# Wait a little bit just to have time to purge message stored in the server
@@ -87,14 +98,16 @@ class TestMessage:
content.size = len(big_file) # total size to be transfered
content.name = 'bigfile.txt'
message = chat_room.create_file_transfer_message(content)
+ message.user_data = big_file # Store the file in the user data of the chat message
self.wait_for_server_to_purge_messages(marie, pauline)
message.callbacks.msg_state_changed = TestMessage.msg_state_changed
+ message.callbacks.file_transfer_send = TestMessage.file_transfer_send
chat_room.send_chat_message(message)
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageReceivedWithFile == 1), True)
if marie.stats.last_received_chat_message is not None:
cbs = marie.stats.last_received_chat_message.callbacks
cbs.msg_state_changed = TestMessage.msg_state_changed
- cbs.file_transfer_recv = TestMessage.file_transfer_received
+ cbs.file_transfer_recv = TestMessage.file_transfer_recv
marie.stats.last_received_chat_message.download_file()
assert_equals(CoreManager.wait_for(pauline, marie, lambda pauline, marie: marie.stats.number_of_LinphoneMessageExtBodyReceived == 1), True)
assert_equals(pauline.stats.number_of_LinphoneMessageInProgress, 1)