Commit d468050c authored by Ghislain MARY's avatar Ghislain MARY

Implement RFC3994: Indication of Message Composition for Instant Messaging.

parent fe1ca6f0
......@@ -13,7 +13,8 @@ COMMON_CFLAGS=\
$(MEDIASTREAMER_CFLAGS) \
$(VIDEO_CFLAGS) \
$(READLINE_CFLAGS) \
$(SQLITE3_CFLAGS)
$(SQLITE3_CFLAGS) \
$(LIBXML2_CFLAGS)
if BUILD_CONSOLE
......@@ -29,7 +30,8 @@ linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \
$(READLINE_LIBS) \
$(SQLITE3_LIBS) \
$(X11_LIBS) \
$(BELLESIP_LIBS)
$(BELLESIP_LIBS) \
$(LIBXML2_LIBS)
if BUILD_WIN32
#special build of linphonec to detach from the windows console
......
......@@ -51,6 +51,7 @@ liblinphone_la_SOURCES=\
contactprovider.c contactprovider.h contact_providers_priv.h \
ldap/ldapprovider.c ldap/ldapprovider.h \
dict.c \
xml.c \
$(GITVERSION_FILE)
if BUILD_UPNP
......
......@@ -464,6 +464,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub;
if (ctx->callbacks.text_received==NULL)
ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
if (ctx->callbacks.is_composing_received==NULL)
ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub;
if (ctx->callbacks.ping_reply==NULL)
ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
if (ctx->callbacks.auth_requested==NULL)
......@@ -915,5 +917,12 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){
return belle_sip_random_bytes(ret,size);
}
belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) {
belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name);
}
void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) {
belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
belle_sip_main_loop_remove_source(ml, timer);
}
......@@ -76,6 +76,10 @@ 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;
}
static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) {
return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("im-iscomposing+xml",belle_sip_header_content_type_get_subtype(content_type))==0;
}
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
......@@ -88,8 +92,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
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);
SalMessage salmsg;
char message_id[256]={0};
int response_code=501;
char* from;
bool_t plain_text=FALSE;
......@@ -99,7 +101,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_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)))) {
SalMessage salmsg;
char message_id[256]={0};
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));
......@@ -121,6 +124,17 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
belle_sip_free(from);
if (salmsg.url) ms_free((char*)salmsg.url);
response_code=200;
} else if (content_type && 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);
belle_sip_object_unref(address);
belle_sip_free(from);
response_code=200;
} else {
ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type)
,belle_sip_header_content_type_get_subtype(content_type));
......
......@@ -843,6 +843,11 @@ static void text_received(SalOp *op, const SalMessage *msg){
}
}
static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) {
LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_core_is_composing_received(lc, op, is_composing);
}
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
linphone_notify_parse_presence(op, content_type, content_subtype, body, result);
}
......@@ -1001,8 +1006,14 @@ static int op_equals(LinphoneCall *a, SalOp *b) {
static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc);
const MSList* calls;
if (chat_msg == NULL) {
// Do not handle delivery status for isComposing messages.
return;
}
calls = linphone_core_get_calls(chat_msg->chat_room->lc);
chat_msg->state=chatStatusSal2Linphone(status);
linphone_chat_message_store_state(chat_msg);
if (chat_msg && chat_msg->cb) {
......@@ -1123,6 +1134,7 @@ SalCallbacks linphone_sal_callbacks={
refer_received,
text_received,
text_delivery_update,
is_composing_received,
notify_refer,
subscribe_received,
subscribe_closed,
......
This diff is collapsed.
......@@ -977,6 +977,20 @@ LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int
LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr);
LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr);
/**
* Notify the destination of the chat message being composed that the user is typing a new message.
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which a new message is being typed.
*/
LINPHONE_PUBLIC void linphone_chat_room_compose(LinphoneChatRoom *cr);
/**
* Tells whether the remote is currently composing a message.
* @param[in] cr The "LinphoneChatRoom object corresponding to the conversation.
* @return TRUE if the remote is currently composing a message, FALSE otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr);
LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
......@@ -1130,6 +1144,14 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat
*/
typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/**
* Is composing notification callback prototype.
*
* @param[in] lc #LinphoneCore object
* @param[in] room #LinphoneChatRoom involved in the conversation.
*/
typedef void (*LinphoneCoreIsComposingReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room);
/**
* Callback for being notified of DTMFs received.
* @param lc the linphone core
......@@ -1179,6 +1201,7 @@ typedef struct _LinphoneCoreVTable{
LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
LinphoneCoreMessageReceivedCb message_received; /** a message is received, can be text or external body*/
LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */
LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */
LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
......
This diff is collapsed.
......@@ -338,6 +338,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
void 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_play_tone(LinphoneCore *lc);
......@@ -426,12 +427,22 @@ struct _LinphoneAuthInfo
bool_t works;
};
typedef enum _LinphoneIsComposingState {
LinphoneIsComposingIdle,
LinphoneIsComposingActive
} LinphoneIsComposingState;
struct _LinphoneChatRoom{
struct _LinphoneCore *lc;
char *peer;
LinphoneAddress *peer_url;
void * user_data;
MSList *messages_hist;
LinphoneIsComposingState remote_is_composing;
LinphoneIsComposingState is_composing;
belle_sip_source_t *remote_composing_refresh_timer;
belle_sip_source_t *composing_idle_timer;
belle_sip_source_t *composing_refresh_timer;
};
......@@ -788,6 +799,35 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
/*****************************************************************************
* XML UTILITY FUNCTIONS *
****************************************************************************/
#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#define XMLPARSING_BUFFER_LEN 2048
#define MAX_XPATH_LENGTH 256
typedef struct _xmlparsing_context {
xmlDoc *doc;
xmlXPathContextPtr xpath_ctx;
char errorBuffer[XMLPARSING_BUFFER_LEN];
char warningBuffer[XMLPARSING_BUFFER_LEN];
} xmlparsing_context_t;
xmlparsing_context_t * linphone_xmlparsing_context_new(void);
void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx);
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...);
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx);
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
void linphone_free_xml_text_content(const char *text);
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
#ifdef __cplusplus
}
#endif
......
/*
linphone
Copyright (C) 2010-2013 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 "private.h"
#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
xmlparsing_context_t * linphone_xmlparsing_context_new(void) {
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t));
if (xmlCtx != NULL) {
xmlCtx->doc = NULL;
xmlCtx->xpath_ctx = NULL;
xmlCtx->errorBuffer[0] = '\0';
xmlCtx->warningBuffer[0] = '\0';
}
return xmlCtx;
}
void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx) {
if (ctx->doc != NULL) {
xmlFreeDoc(ctx->doc);
ctx->doc = NULL;
}
if (ctx->xpath_ctx != NULL) {
xmlXPathFreeContext(ctx->xpath_ctx);
ctx->xpath_ctx = NULL;
}
free(ctx);
}
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) {
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx;
int sl = strlen(xmlCtx->errorBuffer);
va_list args;
va_start(args, fmt);
vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args);
va_end(args);
}
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx) {
if (xml_ctx->xpath_ctx != NULL) {
xmlXPathFreeContext(xml_ctx->xpath_ctx);
}
xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc);
if (xml_ctx->xpath_ctx == NULL) return -1;
return 0;
}
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
xmlXPathObjectPtr xpath_obj;
xmlChar *text = NULL;
int i;
xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
if (xpath_obj != NULL) {
if (xpath_obj->nodesetval != NULL) {
xmlNodeSetPtr nodes = xpath_obj->nodesetval;
for (i = 0; i < nodes->nodeNr; i++) {
xmlNodePtr node = nodes->nodeTab[i];
if (node->children != NULL) {
text = xmlNodeListGetString(xml_ctx->doc, node->children, 1);
}
}
}
xmlXPathFreeObject(xpath_obj);
}
return (char *)text;
}
void linphone_free_xml_text_content(const char *text) {
xmlFree((xmlChar *)text);
}
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
}
......@@ -279,6 +279,16 @@ static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageS
update_chat_state_message(state,msg);
}
void linphone_gtk_compose_text(void) {
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview");
LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr");
if (cr) {
linphone_chat_room_compose(cr);
}
}
void linphone_gtk_send_text(){
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
......@@ -293,7 +303,11 @@ void linphone_gtk_send_text(){
linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL);
linphone_gtk_push_text(w,linphone_chat_message_get_from(msg),
TRUE,cr,msg,FALSE);
// Disconnect and reconnect the "changed" signal to prevent triggering it when clearing the text entry.
g_signal_handlers_disconnect_by_func(G_OBJECT(entry),(GCallback)linphone_gtk_compose_text,NULL);
gtk_entry_set_text(GTK_ENTRY(entry),"");
g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL);
}
}
......@@ -410,6 +424,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL);
entry = linphone_gtk_get_widget(chat_view,"text_entry");
g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL);
g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL);
g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL);
ms_free(with_str);
return chat_view;
......@@ -417,7 +432,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){
char *tmp=linphone_address_as_string(with);
LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp);
LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp);
ms_free(tmp);
return cr;
}
......@@ -516,3 +531,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room,
linphone_gtk_show_friends();
}
void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
linphone_gtk_friend_list_update_chat_picture();
}
......@@ -87,6 +87,18 @@ static GdkPixbuf *create_chat_picture(){
return pixbuf;
}
static GdkPixbuf *create_composing_unread_msg(){
GdkPixbuf *pixbuf;
pixbuf = create_pixbuf("composing_active_chat.png");
return pixbuf;
}
static GdkPixbuf *create_composing_chat_picture(){
GdkPixbuf *pixbuf;
pixbuf = create_pixbuf("composing_chat.png");
return pixbuf;
}
/*
void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){
GtkTreeIter iter;
......@@ -227,15 +239,23 @@ void linphone_gtk_friend_list_update_chat_picture(){
GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist));
LinphoneChatRoom *cr=NULL;
bool_t is_composing;
int nbmsg=0;
if (gtk_tree_model_get_iter_first(model,&iter)) {
do{
gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
nbmsg=linphone_chat_room_get_unread_messages_count(cr);
is_composing=linphone_chat_room_is_remote_composing(cr);
if(nbmsg != 0){
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1);
if (is_composing == TRUE)
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_unread_msg(),-1);
else
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1);
} else {
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1);
if (is_composing == TRUE)
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_chat_picture(),-1);
else
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1);
}
}while(gtk_tree_model_iter_next(model,&iter));
}
......
......@@ -116,6 +116,7 @@ void linphone_gtk_send_text();
GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with);
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with);
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room);
void linphone_gtk_friend_list_update_chat_picture();
void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la);
......
......@@ -266,6 +266,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
vtable.call_log_updated=linphone_gtk_call_log_updated;
//vtable.text_received=linphone_gtk_text_received;
vtable.message_received=linphone_gtk_text_received;
vtable.is_composing_received=linphone_gtk_is_composing_received;
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
......
......@@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/mscommon.h"
#include "ortp/ortp_srtp.h"
#include "belle-sip/belle-sip.h"
#ifndef LINPHONE_PUBLIC
#define LINPHONE_PUBLIC MS2_PUBLIC
......@@ -224,6 +225,11 @@ typedef struct SalMessage{
time_t time;
}SalMessage;
typedef struct SalIsComposing {
const char *from;
const char *text;
} SalIsComposing;
#define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5
SalMediaDescription *sal_media_description_new();
......@@ -390,6 +396,7 @@ typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg);
typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status);
typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing);
typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason);
typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body);
......@@ -425,6 +432,7 @@ typedef struct SalCallbacks{
SalOnRefer refer_received;
SalOnTextReceived text_received;
SalOnTextDeliveryUpdate text_delivery_update;
SalOnIsComposingReceived is_composing_received;
SalOnNotifyRefer notify_refer;
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
......@@ -690,6 +698,8 @@ LINPHONE_PUBLIC bool_t sal_dns_srv_enabled(const Sal *sal);
LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file);
LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal);
unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size);
belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name);
void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer);
int sal_body_has_type(const SalBody *body, const char *type, const char *subtype);
/*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/
......
......@@ -11,7 +11,7 @@ status-orange.png \
status-red.png \
status-offline.png \
call.png \
chat.png active_chat.png\
chat.png active_chat.png composing_chat.png composing_active_chat.png\
chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\
contact-orange.png dialer-orange.png history-orange.png\
startcall-green.png startcall-small.png stopcall-red.png stopcall-small.png addcall-green.png linphone.icns \
......
pixmaps/active_chat.png

3.33 KB | W: | H:

pixmaps/active_chat.png

3.31 KB | W: | H:

pixmaps/active_chat.png
pixmaps/active_chat.png
pixmaps/active_chat.png
pixmaps/active_chat.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -23,11 +23,11 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\
AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi
LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS)
LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS)
AM_LDFLAGS=$(CUNIT_LIBS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS)
test: liblinphone_tester
./liblinphone_tester --config $(abs_srcdir)
......
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