Merge branch 'dev_refactor_cpp' into dev_chatroom_list_subscription

This commit is contained in:
Benjamin Reis 2018-03-20 10:40:25 +01:00
commit 1394899408
58 changed files with 1082 additions and 292 deletions

View file

@ -975,7 +975,7 @@ linphonec_idle_call ()
linphone_core_iterate(opm);
if (answer_call){
fprintf (stdout, "-------auto answering to call-------\n" );
linphone_core_accept_call(opm,NULL);
linphone_core_accept_call(opm, linphone_core_get_current_call(opm));
answer_call=FALSE;
}
/* auto call handling */

View file

@ -156,11 +156,11 @@ static char *argv_to_line(int argc, char *argv[]) {
}
#endif
#define MAX_ARGS 10
#define MAX_ARGS 20
#ifndef _WIN32
static void spawn_linphonec(int argc, char *argv[]){
char * args[MAX_ARGS];
char * args[MAX_ARGS+1];
int i,j;
pid_t pid;
j=0;
@ -168,10 +168,10 @@ static void spawn_linphonec(int argc, char *argv[]){
args[j++]="--pipe";
args[j++]="-c";
args[j++]="/dev/null";
for(i=0;i<argc;++i){
for(i=0;i<argc && i<MAX_ARGS;++i){
args[j++]=argv[i];
}
args[j++]=NULL;
args[j]=NULL;
#ifdef __uClinux__
pid = vfork();

View file

@ -256,7 +256,9 @@ static void call_terminated(SalOp *op, const char *from) {
}
static void call_failure(SalOp *op) {
std::shared_ptr<LinphonePrivate::CallSession> session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer())->getSharedFromThis();
shared_ptr<LinphonePrivate::CallSession> session;
if (op->get_user_pointer())
session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer())->getSharedFromThis();
if (!session) {
ms_warning("Failure reported on already terminated CallSession");
return;

View file

@ -3437,11 +3437,16 @@ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *
system.
*/
static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){
bctbx_list_t *ret=NULL;
const char *local_route=linphone_proxy_config_get_route(proxy);
const LinphoneAddress *srv_route=linphone_proxy_config_get_service_route(proxy);
if (local_route){
ret=bctbx_list_append(ret,sal_address_new(local_route));
bctbx_list_t *ret = NULL;
const bctbx_list_t *proxy_routes = linphone_proxy_config_get_routes(proxy);
bctbx_list_t *proxy_routes_iterator = (bctbx_list_t *)proxy_routes;
const LinphoneAddress *srv_route = linphone_proxy_config_get_service_route(proxy);
while (proxy_routes_iterator) {
const char *local_route = (const char *)bctbx_list_get_data(proxy_routes_iterator);
if (local_route) {
ret = bctbx_list_append(ret, sal_address_new(local_route));
}
proxy_routes_iterator = bctbx_list_next(proxy_routes_iterator);
}
if (srv_route){
ret=bctbx_list_append(ret,sal_address_clone(L_GET_PRIVATE_FROM_C_OBJECT(srv_route)->getInternalAddress()));

View file

@ -47,6 +47,7 @@ void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCal
void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats);
void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg);
void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received);
void linphone_call_notify_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr);
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op);
@ -291,8 +292,10 @@ void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom
void _linphone_chat_room_notify_chat_message_received(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_chat_message_sent(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_conference_address_generation(LinphoneChatRoom *cr);
void _linphone_chat_room_notify_participant_device_fetched(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
void _linphone_chat_room_notify_participant_device_fetch_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
void _linphone_chat_room_notify_participants_capabilities_checked(LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr);
void _linphone_chat_room_notify_participant_registration_subscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
void _linphone_chat_room_notify_participant_registration_unsubscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
void _linphone_chat_room_notify_chat_message_should_be_stored(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
void _linphone_chat_room_clear_callbacks (LinphoneChatRoom *cr);

View file

@ -90,7 +90,7 @@ struct _LinphoneProxyConfig
LinphoneAddress* identity_address;
LinphoneAddress *contact_address;
LinphoneAddress *contact_address_without_params;
char *reg_route;
bctbx_list_t *reg_routes;
char *quality_reporting_collector;
char *realm;
char *contact_params;

View file

@ -20,6 +20,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
#include <ctype.h>
#include <bctoolbox/defs.h>
#include "linphone/core_utils.h"
#include "linphone/core.h"
#include "linphone/lpconfig.h"
@ -113,7 +114,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf
const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL;
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL;
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; //TODO return list instead of string
const char *realm = lc ? lp_config_get_default_string(lc->config, "proxy", "realm", NULL) : NULL;
const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL;
const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
@ -130,7 +131,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cf
cfg->identity_address = identity ? linphone_address_new(identity) : NULL;
cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL;
cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
cfg->reg_route = route ? ms_strdup(route) : NULL;
cfg->reg_routes = route ? bctbx_list_append(cfg->reg_routes, ms_strdup(route)) : NULL; //TODO get list directly
cfg->realm = realm ? ms_strdup(realm) : NULL;
cfg->quality_reporting_enabled = lc ? !!lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0;
cfg->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL;
@ -183,13 +184,18 @@ bool_t linphone_proxy_config_compute_publish_params_hash(LinphoneProxyConfig * c
char hash[33];
char saved;
unsigned long long previous_hash[2];
bctbx_list_t *routes_iterator = cfg->reg_routes;
previous_hash[0] = cfg->previous_publish_config_hash[0];
previous_hash[1] = cfg->previous_publish_config_hash[1];
source = ms_strcat_printf(source, "%i",cfg->privacy);
source=append_linphone_address(cfg->identity_address, source);
source=append_string(cfg->reg_proxy,source);
source=append_string(cfg->reg_route,source);
while (routes_iterator) {
const char *route = (const char *)bctbx_list_get_data(routes_iterator);
source=append_string(route,source);
routes_iterator = bctbx_list_next(routes_iterator);
}
source=append_string(cfg->realm,source);
source = ms_strcat_printf(source, "%i",cfg->publish_expires);
source = ms_strcat_printf(source, "%i",cfg->publish);
@ -235,7 +241,7 @@ void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){
if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy);
if (cfg->reg_identity!=NULL) ms_free(cfg->reg_identity);
if (cfg->identity_address!=NULL) linphone_address_unref(cfg->identity_address);
if (cfg->reg_route!=NULL) ms_free(cfg->reg_route);
if (cfg->reg_routes!=NULL) bctbx_list_free_with_data(cfg->reg_routes, ms_free);
if (cfg->quality_reporting_collector!=NULL) ms_free(cfg->quality_reporting_collector);
if (cfg->ssctx!=NULL) sip_setup_context_free(cfg->ssctx);
if (cfg->realm!=NULL) ms_free(cfg->realm);
@ -348,9 +354,9 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route)
{
if (cfg->reg_route!=NULL){
ms_free(cfg->reg_route);
cfg->reg_route=NULL;
if (cfg->reg_routes != NULL) {
bctbx_list_free_with_data(cfg->reg_routes, ms_free);
cfg->reg_routes = NULL;
}
if (route!=NULL && route[0] !='\0'){
SalAddress *addr;
@ -362,7 +368,7 @@ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const c
addr=sal_address_new(tmp);
if (addr!=NULL){
sal_address_destroy(addr);
cfg->reg_route=tmp;
cfg->reg_routes = bctbx_list_append(cfg->reg_routes, tmp);
return 0;
}else{
ms_free(tmp);
@ -373,6 +379,37 @@ LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const c
}
}
LinphoneStatus linphone_proxy_config_set_routes(LinphoneProxyConfig *cfg, const bctbx_list_t *routes) {
if (cfg->reg_routes != NULL) {
bctbx_list_free_with_data(cfg->reg_routes, ms_free);
cfg->reg_routes = NULL;
}
bctbx_list_t *iterator = (bctbx_list_t *)routes;
while (iterator != NULL) {
char *route = (char *)bctbx_list_get_data(iterator);
if (route != NULL && route[0] !='\0') {
SalAddress *addr;
char *tmp;
/*try to prepend 'sip:' */
if (strstr(route,"sip:") == NULL && strstr(route,"sips:") == NULL) {
tmp = ms_strdup_printf("sip:%s",route);
} else {
tmp = ms_strdup(route);
}
addr = sal_address_new(tmp);
if (addr != NULL) {
sal_address_destroy(addr);
cfg->reg_routes = bctbx_list_append(cfg->reg_routes, tmp);
} else {
ms_free(tmp);
return -1;
}
}
iterator = bctbx_list_next(iterator);
}
return 0;
}
bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){
if (cfg->reg_proxy==NULL)
return FALSE;
@ -790,6 +827,13 @@ LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *pr
return NULL;
}
void linphone_proxy_config_set_etag(LinphoneProxyConfig *cfg,const char* sip_etag) {
if (cfg->sip_etag) ms_free(cfg->sip_etag);
if (sip_etag)
cfg->sip_etag = ms_strdup(sip_etag);
else
cfg->sip_etag = NULL;
}
/**
* Commits modification made to the proxy configuration.
**/
@ -831,11 +875,7 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg)
ms_message("Publish params have changed on proxy config [%p]",cfg);
if (cfg->presence_publish_event) {
if (cfg->publish) {
const char * sip_etag = linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag");
if (sip_etag) {
if (cfg->sip_etag) ms_free(cfg->sip_etag);
cfg->sip_etag = ms_strdup(sip_etag);
}
linphone_proxy_config_set_etag(cfg, linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag"));
}
/*publish is terminated*/
linphone_event_terminate(cfg->presence_publish_event);
@ -934,8 +974,13 @@ void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj) {
}
}
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){
return cfg->reg_route;
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg) {
if (cfg->reg_routes) return (const char *)bctbx_list_get_data(cfg->reg_routes);
return NULL;
}
const bctbx_list_t* linphone_proxy_config_get_routes(const LinphoneProxyConfig *cfg) {
return cfg->reg_routes;
}
const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg){
@ -1116,8 +1161,8 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
if (cfg->reg_proxy!=NULL){
lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy);
}
if (cfg->reg_route!=NULL){
lp_config_set_string(config,key,"reg_route",cfg->reg_route);
if (cfg->reg_routes != NULL) {
lp_config_set_string_list(config, key, "reg_route", cfg->reg_routes);
}
if (cfg->reg_identity!=NULL){
lp_config_set_string(config,key,"reg_identity",cfg->reg_identity);
@ -1187,7 +1232,10 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc
CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity")
CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy")
CONFIGURE_STRING_VALUE(cfg,config,key,route,"reg_route")
bctbx_list_t *routes = linphone_config_get_string_list(config, key, "reg_route", NULL);
linphone_proxy_config_set_routes(cfg, routes);
if (routes)
bctbx_list_free_with_data(routes, (bctbx_list_free_func)bctbx_free);
CONFIGURE_STRING_VALUE(cfg,config,key,realm,"realm")
@ -1498,9 +1546,23 @@ void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatP
}
void linphone_proxy_config_notify_publish_state_changed(LinphoneProxyConfig *cfg, LinphonePublishState state) {
if ((cfg->presence_publish_event != NULL) && ((state == LinphonePublishCleared) || (state == LinphonePublishError))) {
linphone_event_unref(cfg->presence_publish_event);
cfg->presence_publish_event = NULL;
if (cfg->presence_publish_event != NULL) {
switch (state) {
case LinphonePublishCleared:
linphone_proxy_config_set_etag(cfg,NULL);
BCTBX_NO_BREAK;
case LinphonePublishError:
linphone_event_unref(cfg->presence_publish_event);
cfg->presence_publish_event = NULL;
break;
case LinphonePublishOk:
linphone_proxy_config_set_etag(cfg,linphone_event_get_custom_header(cfg->presence_publish_event, "SIP-ETag"));
break;
default:
break;
}
}
}

View file

@ -159,6 +159,20 @@ LINPHONE_PUBLIC LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_process
*/
LINPHONE_PUBLIC void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb);
/**
* Get the TMMBR received callback.
* @param[in] cbs LinphoneCallCbs object.
* @return The current TMMBR received callback.
*/
LINPHONE_PUBLIC LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received(LinphoneCallCbs *cbs);
/**
* Set the TMMBR received callback.
* @param[in] cbs LinphoneCallCbs object.
* @param[in] cb The TMMBR received callback to be used.
*/
LINPHONE_PUBLIC void linphone_call_cbs_set_tmmbr_received(LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb);
/**
* @}
*/

View file

@ -87,6 +87,14 @@ typedef void (*LinphoneCallCbsTransferStateChangedCb)(LinphoneCall *call, Linpho
*/
typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received);
/**
* Callback for notifying a received TMMBR.
* @param call LinphoneCall for which the TMMBR has changed
* @param stream_index the index of the current stream
* @param tmmbr the value of the received TMMBR
*/
typedef void (*LinphoneCallCbsTmmbrReceivedCb)(LinphoneCall *call, int stream_index, int tmmbr);
/**
* @}
**/
@ -239,7 +247,7 @@ typedef void (*LinphoneChatRoomCbsConferenceAddressGenerationCb) (LinphoneChatRo
* @param[in] cr #LinphoneChatRoom object
* @param[in] participantAddr #LinphoneAddress object
*/
typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
/**
* Callback used when a group chat room server is checking participants capabilities.
@ -249,6 +257,20 @@ typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchedCb) (LinphoneChatRoom
*/
typedef void (*LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb) (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr);
/**
* Callback used when a group chat room server is subscribing to registration state of a participant.
* @param[in] cr #LinphoneChatRoom object
* @param[in] participantAddr #LinphoneAddress object
*/
typedef void (*LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
/**
* Callback used when a group chat room server is unsubscribing to registration state of a participant.
* @param[in] cr #LinphoneChatRoom object
* @param[in] participantAddr #LinphoneAddress object
*/
typedef void (*LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb) (LinphoneChatRoom *cr, const LinphoneAddress *participantAddr);
/**
* Callback used to tell the core whether or not to store the incoming message in db or not using linphone_chat_message_set_to_be_stored().
* @param[in] cr #LinphoneChatRoom object

View file

@ -244,18 +244,18 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_r
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsConferenceAddressGenerationCb cb);
/**
* Get the participant device getting callback.
* Get the participant device fetching callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @return The participant device getting callback
* @return The participant device fetching callback
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceFetchedCb linphone_chat_room_cbs_get_participant_device_fetched (const LinphoneChatRoomCbs *cbs);
LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb linphone_chat_room_cbs_get_participant_device_fetch_requested (const LinphoneChatRoomCbs *cbs);
/**
* Set the participant device getting callback.
* Set the participant device fetching callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @param[in] cb The participant device getting callback to be used
* @param[in] cb The participant device fetching callback to be used
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_fetched (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchedCb cb);
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_fetch_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb cb);
/**
* Get the participants capabilities callback.
@ -271,6 +271,34 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_ch
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb cb);
/**
* Get the participant registration subscription callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @return The participant registration subscription callback
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_subscription_requested (const LinphoneChatRoomCbs *cbs);
/**
* Set the participant registration subscription callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @param[in] cb The participant registration subscription callback to be used
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_registration_subscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb cb);
/**
* Get the participant registration unsubscription callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @return The participant registration unsubscription callback
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_unsubscription_requested (const LinphoneChatRoomCbs *cbs);
/**
* Set the participant registration unsubscription callback.
* @param[in] cbs LinphoneChatRoomCbs object
* @param[in] cb The participant registration unsubscription callback to be used
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_registration_unsubscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb cb);
/**
* Get the message should be stored callback.
* @param[in] cbs LinphoneChatRoomCbs object

View file

@ -454,13 +454,22 @@ LINPHONE_PUBLIC void linphone_chat_room_set_conference_address (LinphoneChatRoom
/**
* Set the participant device. This function needs to be called from the
* LinphoneChatRoomCbsParticipantDeviceFetchedCb callback and only there.
* LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb callback and only there.
* @param[in] cr A LinphoneChatRoom object
* @param[in] partAddr The participant address
* @param[in] partDevices \bctbx_list{LinphoneAddress} list of the participant devices to be used by the group chat room
*/
LINPHONE_PUBLIC void linphone_chat_room_set_participant_devices (LinphoneChatRoom *cr, const LinphoneAddress *partAddr, const bctbx_list_t *partDevices);
/**
* Add a participant device.
* This is to used if a new device registers itself after the chat room creation.
* @param[in] cr A #LinphoneChatRoom object
* @param[in] participantAddress The address of the participant for which a new device is to be added
* @param[in] deviceAddress The address of the new device to be added
*/
LINPHONE_PUBLIC void linphone_chat_room_add_participant_device (LinphoneChatRoom *cr, const LinphoneAddress *participantAddress, const LinphoneAddress *deviceAddress);
/**
* Set the participant device. This function needs to be called from the
* LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb callback and only there.

View file

@ -99,6 +99,16 @@ LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_identity_address(Linpho
**/
LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route);
/**
* Sets a list of SIP route.
* When a route is set, all outgoing calls will go to the route's destination if this proxy
* is the default one (see linphone_core_set_default_proxy() ).
* @param[in] cfg the #LinphoneProxyConfig
* @param[in] routes A \bctbx_list{const char *} of routes
* @return -1 if routes are invalid, 0 otherwise.
**/
LINPHONE_PUBLIC LinphoneStatus linphone_proxy_config_set_routes(LinphoneProxyConfig *cfg, const bctbx_list_t *routes);
/**
* Sets the registration expiration time in seconds.
**/
@ -257,9 +267,17 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, c
/**
* @return the route set for this proxy configuration.
* @deprecated Use linphone_proxy_config_get_routes() instead.
**/
LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg);
/**
* Gets the list of the routes set for this proxy config.
* @param[in] cfg #LinphoneProxyConfig object.
* @return \bctbx_list{const char *} the list of routes.
*/
LINPHONE_PUBLIC const bctbx_list_t* linphone_proxy_config_get_routes(const LinphoneProxyConfig *cfg);
/**
* @return the SIP identity that belongs to this proxy configuration.
**/

View file

@ -107,6 +107,8 @@ namespace Utils {
return str ? str : "";
}
LINPHONE_PUBLIC std::string trim (const std::string &str);
template<typename T>
LINPHONE_PUBLIC const T &getEmptyConstRefObject () {
static const T object;

View file

@ -94,6 +94,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
conference/session/media-session.h
conference/session/port-config.h
containers/lru-cache.h
content/content-disposition.h
content/content-manager.h
content/content-p.h
content/content-type.h
@ -220,6 +221,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
conference/remote-conference.cpp
conference/session/call-session.cpp
conference/session/media-session.cpp
content/content-disposition.cpp
content/content-manager.cpp
content/content-type.cpp
content/content.cpp

View file

@ -33,6 +33,7 @@ struct _LinphoneCallCbs {
LinphoneCallCbsStatsUpdatedCb statsUpdatedCb;
LinphoneCallCbsTransferStateChangedCb transferStateChangedCb;
LinphoneCallCbsAckProcessingCb ackProcessing;
LinphoneCallCbsTmmbrReceivedCb tmmbrReceivedCb;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallCbs);
@ -124,3 +125,11 @@ LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing (LinphoneCal
void linphone_call_cbs_set_ack_processing (LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){
cbs->ackProcessing = cb;
}
LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received (LinphoneCallCbs *cbs) {
return cbs->tmmbrReceivedCb;
}
void linphone_call_cbs_set_tmmbr_received (LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb) {
cbs->tmmbrReceivedCb = cb;
}

View file

@ -206,6 +206,10 @@ void linphone_call_notify_ack_processing (LinphoneCall *call, LinphoneHeaders *m
NOTIFY_IF_EXIST(AckProcessing, ack_processing, call, msg, is_received)
}
void linphone_call_notify_tmmbr_received (LinphoneCall *call, int stream_index, int tmmbr) {
NOTIFY_IF_EXIST(TmmbrReceived, tmmbr_received, call, stream_index, tmmbr)
}
// =============================================================================
// Public functions.

View file

@ -108,7 +108,7 @@ const char *linphone_chat_message_get_external_body_url(const LinphoneChatMessag
}
void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *url) {
L_GET_PRIVATE_FROM_C_OBJECT(msg)->setExternalBodyUrl(L_C_TO_STRING(url));
}
time_t linphone_chat_message_get_time(const LinphoneChatMessage *msg) {

View file

@ -39,8 +39,10 @@ struct _LinphoneChatRoomCbs {
LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb;
LinphoneChatRoomCbsChatMessageSentCb chatMessageSentCb;
LinphoneChatRoomCbsConferenceAddressGenerationCb conferenceAddressGenerationCb;
LinphoneChatRoomCbsParticipantDeviceFetchedCb participantDeviceFetchedCb;
LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb participantDeviceFetchRequestedCb;
LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb participantsCapabilitiesChecked;
LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb participantRegistrationSubscriptionRequestedCb;
LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb participantRegistrationUnsubscriptionRequestedCb;
LinphoneChatRoomCbsShouldChatMessageBeStoredCb shouldMessageBeStoredCb;
};
@ -182,12 +184,12 @@ void linphone_chat_room_cbs_set_conference_address_generation (LinphoneChatRoomC
cbs->conferenceAddressGenerationCb = cb;
}
LinphoneChatRoomCbsParticipantDeviceFetchedCb linphone_chat_room_cbs_get_participant_device_fetched (const LinphoneChatRoomCbs *cbs) {
return cbs->participantDeviceFetchedCb;
LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb linphone_chat_room_cbs_get_participant_device_fetch_requested (const LinphoneChatRoomCbs *cbs) {
return cbs->participantDeviceFetchRequestedCb;
}
void linphone_chat_room_cbs_set_participant_device_fetched (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchedCb cb) {
cbs->participantDeviceFetchedCb = cb;
void linphone_chat_room_cbs_set_participant_device_fetch_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceFetchRequestedCb cb) {
cbs->participantDeviceFetchRequestedCb = cb;
}
LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_chat_room_cbs_get_participants_capabilities_checked (const LinphoneChatRoomCbs *cbs) {
@ -198,6 +200,22 @@ void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatR
cbs->participantsCapabilitiesChecked = cb;
}
LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_subscription_requested (const LinphoneChatRoomCbs *cbs) {
return cbs->participantRegistrationSubscriptionRequestedCb;
}
void linphone_chat_room_cbs_set_participant_registration_subscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb cb) {
cbs->participantRegistrationSubscriptionRequestedCb = cb;
}
LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb linphone_chat_room_cbs_get_participant_registration_unsubscription_requested (const LinphoneChatRoomCbs *cbs) {
return cbs->participantRegistrationUnsubscriptionRequestedCb;
}
void linphone_chat_room_cbs_set_participant_registration_unsubscription_requested (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb cb) {
cbs->participantRegistrationUnsubscriptionRequestedCb = cb;
}
LinphoneChatRoomCbsShouldChatMessageBeStoredCb linphone_chat_room_cbs_get_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs) {
return cbs->shouldMessageBeStoredCb;
}

View file

@ -382,6 +382,16 @@ void linphone_chat_room_set_participant_devices (LinphoneChatRoom *cr, const Lin
bctbx_free(addrStr);
}
void linphone_chat_room_add_participant_device (LinphoneChatRoom *cr, const LinphoneAddress *participantAddress, const LinphoneAddress *deviceAddress) {
char *participantAddressStr = linphone_address_as_string(participantAddress);
char *deviceAddressStr = linphone_address_as_string(deviceAddress);
LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
if (sgcr)
sgcr->addParticipantDevice(LinphonePrivate::IdentityAddress(participantAddressStr), LinphonePrivate::IdentityAddress(deviceAddressStr));
bctbx_free(participantAddressStr);
bctbx_free(deviceAddressStr);
}
void linphone_chat_room_add_compatible_participants (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsCompatible) {
list<LinphonePrivate::Address> lPartsComp = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participantsCompatible, Address);
LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
@ -486,14 +496,22 @@ void _linphone_chat_room_notify_conference_address_generation(LinphoneChatRoom *
NOTIFY_IF_EXIST(ConferenceAddressGeneration, conference_address_generation, cr)
}
void _linphone_chat_room_notify_participant_device_fetched(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) {
NOTIFY_IF_EXIST(ParticipantDeviceFetched, participant_device_fetched, cr, participantAddr)
void _linphone_chat_room_notify_participant_device_fetch_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) {
NOTIFY_IF_EXIST(ParticipantDeviceFetchRequested, participant_device_fetch_requested, cr, participantAddr)
}
void _linphone_chat_room_notify_participants_capabilities_checked(LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr) {
NOTIFY_IF_EXIST(ParticipantsCapabilitiesChecked, participants_capabilities_checked, cr, deviceAddr, participantsAddr)
}
void _linphone_chat_room_notify_participant_registration_subscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) {
NOTIFY_IF_EXIST(ParticipantRegistrationSubscriptionRequested, participant_registration_subscription_requested, cr, participantAddr)
}
void _linphone_chat_room_notify_participant_registration_unsubscription_requested(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) {
NOTIFY_IF_EXIST(ParticipantRegistrationUnsubscriptionRequested, participant_registration_unsubscription_requested, cr, participantAddr)
}
void _linphone_chat_room_notify_chat_message_should_be_stored(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
NOTIFY_IF_EXIST(ShouldChatMessageBeStored, chat_message_should_be_stored, cr, msg)
}

View file

@ -110,6 +110,7 @@ private:
bool areSoundResourcesAvailable (const std::shared_ptr<CallSession> &session) override;
bool isPlayingRingbackTone (const std::shared_ptr<CallSession> &session) override;
void onRealTimeTextCharacterReceived (const std::shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *character) override;
void onTmmbrReceived(const std::shared_ptr<CallSession> &session, int streamIndex, int tmmbr) override;
mutable LinphonePlayer *player = nullptr;

View file

@ -491,6 +491,11 @@ void CallPrivate::onRealTimeTextCharacterReceived (const shared_ptr<CallSession>
getChatRoom()->getPrivate()->realtimeTextReceived(data->character, q->getSharedFromThis());
}
void CallPrivate::onTmmbrReceived (const shared_ptr<CallSession> &session, int streamIndex, int tmmbr) {
L_Q();
linphone_call_notify_tmmbr_received(L_GET_C_BACK_PTR(q), streamIndex, tmmbr);
}
// =============================================================================
Call::Call (CallPrivate &p, shared_ptr<Core> core) : Object(p), CoreAccessor(core) {

View file

@ -105,6 +105,7 @@ public:
std::string getSalCustomHeaderValue (const std::string &name);
void loadFileTransferUrlFromBodyToContent ();
std::string createFakeFileTransferFromUrl(const std::string &url);
void setChatRoom (const std::shared_ptr<AbstractChatRoom> &chatRoom);
@ -127,6 +128,7 @@ public:
void setAppdata (const std::string &appData);
const std::string &getExternalBodyUrl () const;
void setExternalBodyUrl (const std::string &url);
bool hasTextContent () const;
const Content* getTextContent () const;
@ -161,6 +163,7 @@ private:
time_t time = ::ms_time(0); // TODO: Change me in all files.
std::string imdnId;
std::string rttMessage;
std::string externalBodyUrl;
bool isSecured = false;
mutable bool isReadOnly = false;
Content internalContent;

View file

@ -147,7 +147,13 @@ void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
if (cbs && linphone_chat_message_cbs_get_msg_state_changed(cbs))
linphone_chat_message_cbs_get_msg_state_changed(cbs)(msg, (LinphoneChatMessageState)state);
updateInDb();
if (state == ChatMessage::State::FileTransferDone && !hasFileTransferContent()) {
// We wait until the file has been downloaded to send the displayed IMDN
q->sendDisplayNotification();
setState(ChatMessage::State::Displayed);
} else {
updateInDb();
}
}
belle_http_request_t *ChatMessagePrivate::getHttpRequest () const {
@ -236,26 +242,29 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) {
const string &ChatMessagePrivate::getAppdata () const {
for (const Content *c : getContents()) {
if (c->isFile()) {
FileContent *fileContent = (FileContent *)c;
return fileContent->getAppData("legacy");
if (!c->getAppData("legacy").empty()) {
return c->getAppData("legacy");
}
}
return Utils::getEmptyConstRefObject<string>();
}
void ChatMessagePrivate::setAppdata (const string &data) {
for (const Content *c : getContents()) {
if (c->isFile()) {
FileContent *fileContent = (FileContent *)c;
fileContent->setAppData("legacy", data);
break;
}
bool contentFound = false;
for (Content *c : getContents()) {
c->setAppData("legacy", data);
contentFound = true;
break;
}
if (contentFound) {
updateInDb();
}
updateInDb();
}
const string &ChatMessagePrivate::getExternalBodyUrl () const {
if (!externalBodyUrl.empty()) {
return externalBodyUrl;
}
if (hasFileTransferContent()) {
FileTransferContent *content = (FileTransferContent*) getFileTransferContent();
return content->getFileUrl();
@ -263,6 +272,10 @@ const string &ChatMessagePrivate::getExternalBodyUrl () const {
return Utils::getEmptyConstRefObject<string>();
}
void ChatMessagePrivate::setExternalBodyUrl (const string &url) {
externalBodyUrl = url;
}
const ContentType &ChatMessagePrivate::getContentType () {
loadContentsFromDatabase();
if (direction == ChatMessage::Direction::Incoming) {
@ -390,6 +403,10 @@ void ChatMessagePrivate::loadFileTransferUrlFromBodyToContent() {
fileTransferChatMessageModifier.decode(q->getSharedFromThis(), errorCode);
}
std::string ChatMessagePrivate::createFakeFileTransferFromUrl(const std::string &url) {
return fileTransferChatMessageModifier.createFakeFileTransferFromUrl(url);
}
void ChatMessagePrivate::setChatRoom (const shared_ptr<AbstractChatRoom> &cr) {
chatRoom = cr;
chatRoomId = cr->getChatRoomId();
@ -410,7 +427,7 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) {
shared_ptr<ChatMessage> msg = q->getChatRoom()->createChatMessage();
Content *content = new Content();
content->setContentType("message/imdn+xml");
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(imdnId, time, imdnType, reason));
msg->addContent(*content);
@ -711,14 +728,18 @@ void ChatMessagePrivate::send () {
if (internalContent.isEmpty()) {
if (contents.size() > 0) {
internalContent = *(contents.front());
} else {
} else if (externalBodyUrl.empty()) { // When using external body url, there is no content
lError() << "Trying to send a message without any content !";
return;
}
}
auto msgOp = dynamic_cast<SalMessageOpInterface *>(op);
if (internalContent.getContentType().isValid()) {
if (!externalBodyUrl.empty()) {
char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", externalBodyUrl.c_str());
msgOp->send_message(content_type, NULL);
ms_free(content_type);
} else if (internalContent.getContentType().isValid()) {
msgOp->send_message(internalContent.getContentType().asString().c_str(), internalContent.getBodyAsUtf8String().c_str());
} else {
msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsUtf8String().c_str());

View file

@ -26,6 +26,7 @@
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "sip-tools/sip-headers.h"
#include "logger/logger.h"
// =============================================================================
@ -193,8 +194,14 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
);
Content content;
content.setContentType(message->content_type);
content.setBodyFromUtf8(message->text ? message->text : "");
if (message->url && (ContentType(message->content_type) == ContentType::ExternalBody)) {
lInfo() << "Received a message with an external body URL " << message->url;
content.setContentType(ContentType::FileTransfer);
content.setBody(msg->getPrivate()->createFakeFileTransferFromUrl(message->url));
} else {
content.setContentType(ContentType(message->content_type));
content.setBodyFromUtf8(message->text ? message->text : "");
}
msg->setInternalContent(content);
msg->getPrivate()->setTime(message->time);
@ -438,8 +445,11 @@ void ChatRoom::markAsRead () {
CorePrivate *dCore = getCore()->getPrivate();
for (auto &chatMessage : dCore->mainDb->getUnreadChatMessages(d->chatRoomId)) {
chatMessage->sendDisplayNotification();
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true);
// Do not send display notification for file transfer until it has been downloaded (it won't have a file transfer content anymore)
if (!chatMessage->getPrivate()->hasFileTransferContent()) {
chatMessage->sendDisplayNotification();
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true); // True will ensure the setState won't update the database so it will be done below by the markChatMessagesAsRead
}
}
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);

View file

@ -29,6 +29,8 @@
#include "conference/participant-device.h"
#include "conference/remote-conference-p.h"
#include "conference/session/call-session-p.h"
#include "content/content-disposition.h"
#include "content/content-type.h"
#include "core/core-p.h"
#include "logger/logger.h"
#include "sal/refer-op.h"
@ -319,8 +321,8 @@ void ClientGroupChatRoom::addParticipants (
Content content;
content.setBody(getResourceLists(addressesList));
content.setContentType("application/resource-lists+xml");
content.setContentDisposition("recipient-list");
content.setContentType(ContentType::ResourceLists);
content.setContentDisposition(ContentDisposition::RecipientList);
// TODO: Activate compression
//if (linphone_core_content_encoding_supported(getCore()->getCCore(), "deflate"))
// content.setContentEncoding("deflate");

View file

@ -60,6 +60,7 @@ public:
void setConferenceAddress (const IdentityAddress &conferenceAddress);
void setParticipantDevices (const IdentityAddress &addr, const std::list<IdentityAddress> &devices);
void addParticipantDevice (const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress);
void addCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list<IdentityAddress> &compatibleParticipants);
void checkCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list<IdentityAddress> &addressesToCheck);
@ -67,17 +68,29 @@ public:
private:
struct Message {
Message (const std::string &from, const std::string &contentType, const std::string &text) : fromAddr(from) {
Message (const std::string &from, const ContentType &contentType, const std::string &text, const SalCustomHeader *salCustomHeaders)
: fromAddr(from)
{
content.setContentType(contentType);
if (!text.empty())
content.setBodyFromUtf8(text);
if (salCustomHeaders)
customHeaders = sal_custom_header_clone(salCustomHeaders);
}
~Message () {
if (customHeaders)
sal_custom_header_free(customHeaders);
}
IdentityAddress fromAddr;
Content content;
std::chrono::system_clock::time_point timestamp = std::chrono::system_clock::now();
SalCustomHeader *customHeaders = nullptr;
};
static void copyMessageHeaders (const std::shared_ptr<Message> &fromMessage, const std::shared_ptr<ChatMessage> &toMessage);
void designateAdmin ();
void dispatchMessage (const std::shared_ptr<Message> &message, const std::string &uri);
void finalizeCreation ();

View file

@ -80,6 +80,8 @@ void ServerGroupChatRoomPrivate::setConferenceAddress (const IdentityAddress &)
void ServerGroupChatRoomPrivate::setParticipantDevices (const IdentityAddress &addr, const list<IdentityAddress> &devices) {}
void ServerGroupChatRoomPrivate::addParticipantDevice (const IdentityAddress &participantAddress, const IdentityAddress &deviceAddress) {}
void ServerGroupChatRoomPrivate::addCompatibleParticipants (const IdentityAddress &deviceAddr, const list<IdentityAddress> &participantCompatible) {}
// -----------------------------------------------------------------------------

View file

@ -968,4 +968,18 @@ void FileTransferChatMessageModifier::releaseHttpRequest () {
}
}
string FileTransferChatMessageModifier::createFakeFileTransferFromUrl(const string &url) {
string fileName = url.substr(url.find_last_of("/") + 1);
stringstream fakeXml;
fakeXml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
fakeXml << "<file xmlns=\"urn:gsma:params:xml:ns:rcs:rcs:fthttp\">\r\n";
fakeXml << "<file-info type=\"file\">\r\n";
fakeXml << "<file-name>" << fileName << "</file-name>\r\n";
fakeXml << "<content-type>application/binary</content-type>\r\n";
fakeXml << "<data url = \"" << url << "\"/>\r\n";
fakeXml << "</file-info>\r\n";
fakeXml << "</file>";
return fakeXml.str();
}
LINPHONE_END_NAMESPACE

View file

@ -63,6 +63,7 @@ public:
int downloadFile(const std::shared_ptr<ChatMessage> &message, FileTransferContent *fileTransferContent);
void cancelFileTransfer();
bool isFileTransferInProgressAndValid();
std::string createFakeFileTransferFromUrl(const std::string &url);
private:
int uploadFile();

View file

@ -18,6 +18,7 @@
*/
#include "content/content.h"
#include "content/content-disposition.h"
#include "content/content-type.h"
#include "handlers/local-conference-event-handler.h"
#include "local-conference-p.h"
@ -70,7 +71,7 @@ void LocalConference::removeParticipant (const shared_ptr<const Participant> &pa
list<IdentityAddress> LocalConference::parseResourceLists (const Content &content) {
if ((content.getContentType() == ContentType::ResourceLists)
&& (content.getContentDisposition() == "recipient-list")
&& (content.getContentDisposition() == ContentDisposition::RecipientList)
) {
istringstream data(content.getBodyAsString());
unique_ptr<Xsd::ResourceLists::ResourceLists> rl(Xsd::ResourceLists::parseResourceLists(

View file

@ -54,6 +54,7 @@ public:
virtual void onIncomingCallSessionTimeoutCheck (const std::shared_ptr<CallSession> &session, int elapsed, bool oneSecondElapsed) {}
virtual void onInfoReceived (const std::shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) {}
virtual void onNoMediaTimeoutCheck (const std::shared_ptr<CallSession> &session, bool oneSecondElapsed) {}
virtual void onTmmbrReceived (const std::shared_ptr<CallSession> &session, int streamIndex, int tmmbr) {}
virtual void onEncryptionChanged (const std::shared_ptr<CallSession> &session, bool activated, const std::string &authToken) {}

View file

@ -134,6 +134,7 @@ protected:
bool broken = false;
bool deferIncomingNotification = false;
bool deferUpdate = false;
bool deferUpdateInternal = false;
bool needLocalIpRefresh = false;
bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */
bool notifyRinging = true;

View file

@ -467,9 +467,10 @@ void CallSessionPrivate::updated (bool isUpdate) {
void CallSessionPrivate::updatedByRemote () {
L_Q();
setState(CallSession::State::UpdatedByRemote,"Call updated by remote");
if (deferUpdate) {
if (state == CallSession::State::UpdatedByRemote)
lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call CallSession::acceptUpdate() later";
if (deferUpdate || deferUpdateInternal) {
if (state == CallSession::State::UpdatedByRemote && !deferUpdateInternal){
lInfo() << "CallSession [" << q << "]: UpdatedByRemoted was signaled but defered. LinphoneCore expects the application to call linphone_call_accept_update() later";
}
} else {
if (state == CallSession::State::UpdatedByRemote)
q->acceptUpdate(nullptr);
@ -820,8 +821,9 @@ void CallSessionPrivate::repairIfBroken () {
case CallSession::State::Pausing:
if (op->dialog_request_pending()) {
// Need to cancel first re-INVITE as described in section 5.5 of RFC 6141
op->cancel_invite();
reinviteOnCancelResponseRequested = true;
if (op->cancel_invite() == 0){
reinviteOnCancelResponseRequested = true;
}
}
break;
case CallSession::State::StreamsRunning:
@ -839,8 +841,9 @@ void CallSessionPrivate::repairIfBroken () {
break;
case CallSession::State::OutgoingInit:
case CallSession::State::OutgoingProgress:
op->cancel_invite();
reinviteOnCancelResponseRequested = true;
if (op->cancel_invite() == 0){
reinviteOnCancelResponseRequested = true;
}
break;
case CallSession::State::OutgoingEarlyMedia:
case CallSession::State::OutgoingRinging:

View file

@ -74,7 +74,7 @@ public:
void setParams (MediaSessionParams *msp);
void setRemoteParams (MediaSessionParams *msp);
IceSession *getIceSession () const { return iceAgent->getIceSession(); }
IceSession *getIceSession () const { return iceAgent ? iceAgent->getIceSession() : nullptr; }
SalMediaDescription *getLocalDesc () const { return localDesc; }
@ -254,7 +254,6 @@ private:
int sendDtmf ();
void stunAuthRequestedCb (const char *realm, const char *nonce, const char **username, const char **password, const char **ha1);
private:
static const std::string ecStateStore;
static const int ecStateMaxLen;
@ -284,8 +283,8 @@ private:
int mainTextStreamIndex = LINPHONE_CALL_STATS_TEXT;
LinphoneNatPolicy *natPolicy = nullptr;
StunClient *stunClient = nullptr;
IceAgent *iceAgent = nullptr;
std::unique_ptr<StunClient> stunClient;
std::unique_ptr<IceAgent> iceAgent;
// The address family to prefer for RTP path, guessed from signaling path.
int af;
@ -325,6 +324,7 @@ private:
bool automaticallyPaused = false;
bool pausedByApp = false;
bool recordActive = false;
bool incomingIceReinvitePending = false;
std::string onHoldFile;

View file

@ -382,6 +382,8 @@ void MediaSessionPrivate::updated (bool isUpdate) {
CallSessionPrivate::updated(isUpdate);
}
void MediaSessionPrivate::updating (bool isUpdate) {
L_Q();
SalMediaDescription *rmd = op->get_remote_media_description();
@ -702,6 +704,10 @@ shared_ptr<Participant> MediaSessionPrivate::getMe () const {
void MediaSessionPrivate::setState (CallSession::State newState, const string &message) {
L_Q();
SalMediaDescription *rmd;
lInfo()<<"MediaSessionPrivate::setState";
/* Take a ref on the session otherwise it might get destroyed during the call to setState */
shared_ptr<CallSession> sessionRef = q->getSharedFromThis();
if ((newState != state) && (newState != CallSession::State::StreamsRunning))
@ -709,6 +715,21 @@ void MediaSessionPrivate::setState (CallSession::State newState, const string &m
CallSessionPrivate::setState(newState, message);
if (listener)
listener->onCallSessionStateChangedForReporting(q->getSharedFromThis());
switch(newState){
case CallSession::State::UpdatedByRemote:
/*Handle specifically the case of an incoming ICE-concluded reINVITE*/
lInfo()<<"Checking for ICE reINVITE";
rmd = op->get_remote_media_description();
if (iceAgent && rmd != nullptr && iceAgent->checkIceReinviteNeedsDeferedResponse(rmd)){
deferUpdate = true;
deferUpdateInternal = true;
incomingIceReinvitePending = true;
lInfo()<<"CallSession [" << q << "]: ICE reinvite received, but one or more check-lists are not completed. Response will be sent later, when ICE has completed";
}
break;
default:
break;
}
}
// -----------------------------------------------------------------------------
@ -1177,7 +1198,7 @@ string MediaSessionPrivate::getPublicIpForStream (int streamIndex) {
void MediaSessionPrivate::runStunTestsIfNeeded () {
L_Q();
if (linphone_nat_policy_stun_enabled(natPolicy) && !(linphone_nat_policy_ice_enabled(natPolicy) || linphone_nat_policy_turn_enabled(natPolicy))) {
stunClient = new StunClient(q->getCore());
stunClient = makeUnique<StunClient>(q->getCore());
int ret = stunClient->run(mediaPorts[mainAudioStreamIndex].rtpPort, mediaPorts[mainVideoStreamIndex].rtpPort, mediaPorts[mainTextStreamIndex].rtpPort);
if (ret >= 0)
pingTime = ret;
@ -2191,11 +2212,14 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) {
OrtpEventData *evd = ortp_event_get_data(ev);
if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
if (iceAgent->hasCompletedCheckList()) {
/* At least one ICE session has succeeded, so perform a call update */
/* The ICE session has succeeded, so perform a call update */
if (iceAgent->isControlling() && q->getCurrentParams()->getPrivate()->getUpdateCallWhenIceCompleted()) {
MediaSessionParams newParams(*getParams());
newParams.getPrivate()->setInternalCallUpdate(true);
q->update(&newParams);
}else if (!iceAgent->isControlling() && incomingIceReinvitePending){
q->acceptUpdate(nullptr);
incomingIceReinvitePending = false;
}
startDtlsOnAllStreams();
}
@ -2238,6 +2262,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) {
}
void MediaSessionPrivate::handleStreamEvents (int streamIndex) {
L_Q();
MediaStream *ms = (streamIndex == mainAudioStreamIndex) ? &audioStream->ms :
(streamIndex == mainVideoStreamIndex ? &videoStream->ms : &textStream->ms);
if (ms) {
@ -2272,14 +2297,28 @@ void MediaSessionPrivate::handleStreamEvents (int streamIndex) {
stats = videoStats;
else
stats = textStats;
OrtpEventType evt = ortp_event_get_type(ev);
OrtpEventData *evd = ortp_event_get_data(ev);
/*This MUST be done before any call to "linphone_call_stats_fill" since it has ownership over evd->packet*/
if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
do {
if (evd->packet && rtcp_is_RTPFB(evd->packet)) {
if (rtcp_RTPFB_get_type(evd->packet) == RTCP_RTPFB_TMMBR) {
listener->onTmmbrReceived(q->getSharedFromThis(), streamIndex, (int)rtcp_RTPFB_tmmbr_get_max_bitrate(evd->packet));
}
}
} while (rtcp_next_packet(evd->packet));
rtcp_rewind(evd->packet);
}
/* And yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events
* in this loop*/
ms = getMediaStream(streamIndex);
if (ms)
linphone_call_stats_fill(stats, ms, ev);
notifyStatsUpdated(streamIndex);
OrtpEventType evt = ortp_event_get_type(ev);
OrtpEventData *evd = ortp_event_get_data(ev);
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) {
if (streamIndex == mainAudioStreamIndex)
audioStreamEncryptionChanged(!!evd->info.zrtp_stream_encrypted);
@ -2621,7 +2660,7 @@ void MediaSessionPrivate::startAudioStream (CallSession::State targetState, bool
if (playcard) {
ms_snd_card_set_stream_type(playcard, MS_SND_CARD_STREAM_VOICE);
}
media_stream_set_max_network_bitrate(&audioStream->ms, linphone_core_get_upload_bandwidth(q->getCore()->getCCore()) * 1000);
bool useEc = captcard && linphone_core_echo_cancellation_enabled(q->getCore()->getCCore());
audio_stream_enable_echo_canceller(audioStream, useEc);
if (playcard && (stream->max_rate > 0))
@ -2860,6 +2899,7 @@ void MediaSessionPrivate::startVideoStream (CallSession::State targetState) {
getCurrentParams()->getPrivate()->setUsedVideoCodec(rtp_profile_get_payload(videoProfile, usedPt));
getCurrentParams()->enableVideo(true);
rtp_session_enable_rtcp_mux(videoStream->ms.sessions.rtp_session, vstream->rtcp_mux);
media_stream_set_max_network_bitrate(&videoStream->ms, linphone_core_get_upload_bandwidth(q->getCore()->getCCore()) * 1000);
if (q->getCore()->getCCore()->video_conf.preview_vsize.width != 0)
video_stream_set_preview_size(videoStream, q->getCore()->getCCore()->video_conf.preview_vsize);
video_stream_set_fps(videoStream, linphone_core_get_preferred_framerate(q->getCore()->getCCore()));
@ -3924,7 +3964,7 @@ MediaSession::MediaSession (const shared_ptr<Core> &core, shared_ptr<Participant
d->setPortConfig(d->mainTextStreamIndex, make_pair(minPort, maxPort));
memset(d->sessions, 0, sizeof(d->sessions));
d->iceAgent = new IceAgent(*this);
d->iceAgent = makeUnique<IceAgent>(*this);
lInfo() << "New MediaSession [" << this << "] initialized (LinphoneCore version: " << linphone_core_get_version() << ")";
}
@ -3942,9 +3982,6 @@ MediaSession::~MediaSession () {
linphone_call_stats_unref(d->textStats);
if (d->natPolicy)
linphone_nat_policy_unref(d->natPolicy);
if (d->stunClient)
delete d->stunClient;
delete d->iceAgent;
if (d->localDesc)
sal_media_description_unref(d->localDesc);
if (d->biggestDesc)

View file

@ -0,0 +1,107 @@
/*
* content-disposition.cpp
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/utils/utils.h"
#include "content-disposition.h"
#include "object/clonable-object-p.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
class ContentDispositionPrivate : public ClonableObjectPrivate {
public:
string disposition;
string parameter;
};
// -----------------------------------------------------------------------------
const ContentDisposition ContentDisposition::RecipientList("recipient-list");
const ContentDisposition ContentDisposition::RecipientListHistory("recipient-list-history; handling=optional");
// -----------------------------------------------------------------------------
ContentDisposition::ContentDisposition (const string &disposition) : ClonableObject(*new ContentDispositionPrivate) {
L_D();
size_t posParam = disposition.find(";");
d->disposition = Utils::trim(disposition.substr(0, posParam));
if (posParam != string::npos)
setParameter(Utils::trim(disposition.substr(posParam + 1)));
}
ContentDisposition::ContentDisposition (const ContentDisposition &other)
: ContentDisposition(other.asString()) {}
ContentDisposition &ContentDisposition::operator= (const ContentDisposition &other) {
L_D();
if (this != &other) {
d->disposition = other.getPrivate()->disposition;
setParameter(other.getParameter());
}
return *this;
}
bool ContentDisposition::operator== (const ContentDisposition &other) const {
L_D();
return d->disposition == other.getPrivate()->disposition
&& getParameter() == other.getParameter();
}
bool ContentDisposition::operator!= (const ContentDisposition &other) const {
return !(*this == other);
}
bool ContentDisposition::isEmpty () const {
L_D();
return d->disposition.empty();
}
bool ContentDisposition::isValid () const {
L_D();
return !d->disposition.empty();
}
const string &ContentDisposition::getParameter () const {
L_D();
return d->parameter;
}
void ContentDisposition::setParameter (const string &parameter) {
L_D();
d->parameter = parameter;
}
string ContentDisposition::asString () const {
L_D();
if (isValid()) {
string asString = d->disposition;
if (!d->parameter.empty())
asString += ";" + d->parameter;
return asString;
}
return "";
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,63 @@
/*
* content-disposition.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_CONTENT_DISPOSITION_H_
#define _L_CONTENT_DISPOSITION_H_
#include "object/clonable-object.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ContentDispositionPrivate;
class LINPHONE_PUBLIC ContentDisposition : public ClonableObject {
public:
explicit ContentDisposition (const std::string &contentDisposition = "");
ContentDisposition (const ContentDisposition &other);
ContentDisposition &operator= (const ContentDisposition &other);
bool operator== (const ContentDisposition &other) const;
bool operator!= (const ContentDisposition &other) const;
// Delete these operators to prevent putting complicated content-disposition strings
// in the code. Instead define static const ContentDisposition objects below.
bool operator== (const std::string &other) const = delete;
bool operator!= (const std::string &other) const = delete;
bool isEmpty () const;
bool isValid () const;
const std::string &getParameter () const;
void setParameter (const std::string &parameter);
std::string asString () const;
static const ContentDisposition RecipientList;
static const ContentDisposition RecipientListHistory;
private:
L_DECLARE_PRIVATE(ContentDisposition);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_CONTENT_DISPOSITION_H_

View file

@ -20,6 +20,7 @@
#ifndef _L_CONTENT_P_H_
#define _L_CONTENT_P_H_
#include "content-disposition.h"
#include "content-type.h"
#include "content.h"
#include "object/clonable-object-p.h"
@ -32,7 +33,7 @@ class ContentPrivate : public ClonableObjectPrivate {
private:
std::vector<char> body;
ContentType contentType;
std::string contentDisposition;
ContentDisposition contentDisposition;
std::string contentEncoding;
std::list<std::pair<std::string, std::string>> headers;

View file

@ -57,20 +57,20 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte
L_D();
size_t pos = contentType.find('/');
size_t posParam = contentType.find("; ");
size_t posParam = contentType.find(";");
size_t end = contentType.length();
if (pos == string::npos)
return;
if (setType(contentType.substr(0, pos))) {
if (setType(Utils::trim(contentType.substr(0, pos)))) {
if (posParam != string::npos)
end = posParam;
if (!setSubType(contentType.substr(pos + 1, end - (pos + 1))))
if (!setSubType(Utils::trim(contentType.substr(pos + 1, end - (pos + 1)))))
d->type.clear();
}
if (posParam != string::npos)
setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ;.
setParameter(Utils::trim(contentType.substr(posParam + 1)));
}
ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) {

View file

@ -118,17 +118,12 @@ void Content::setContentType (const ContentType &contentType) {
d->contentType = contentType;
}
void Content::setContentType (const string &contentType) {
L_D();
d->contentType = ContentType(contentType);
}
const string &Content::getContentDisposition () const {
const ContentDisposition &Content::getContentDisposition () const {
L_D();
return d->contentDisposition;
}
void Content::setContentDisposition (const string &contentDisposition) {
void Content::setContentDisposition (const ContentDisposition &contentDisposition) {
L_D();
d->contentDisposition = contentDisposition;
}

View file

@ -32,6 +32,7 @@ L_DECL_C_STRUCT(LinphoneContent);
LINPHONE_BEGIN_NAMESPACE
class ContentDisposition;
class ContentType;
class ContentPrivate;
@ -49,10 +50,9 @@ public:
const ContentType &getContentType () const;
void setContentType (const ContentType &contentType);
void setContentType (const std::string &contentType);
const std::string &getContentDisposition () const;
void setContentDisposition (const std::string &contentDisposition);
const ContentDisposition &getContentDisposition () const;
void setContentDisposition (const ContentDisposition &contentDisposition);
const std::string &getContentEncoding () const;
void setContentEncoding (const std::string &contentEncoding);

View file

@ -738,4 +738,35 @@ void IceAgent::updateIceStateInCallStatsForStream (LinphoneCallStats *stats, Ice
}
}
bool IceAgent::checkIceReinviteNeedsDeferedResponse(SalMediaDescription *md){
int i,j;
IceCheckList *cl;
if (!iceSession) return false;
if (ice_session_state(iceSession) != IS_Running ) return false;
for (i = 0; i < md->nb_streams; i++) {
SalStreamDescription *stream = &md->streams[i];
cl = ice_session_check_list(iceSession, i);
if (cl==NULL) continue;
if (stream->ice_mismatch == TRUE) {
return false;
}
if (stream->rtp_port == 0) {
continue;
}
if (ice_check_list_state(cl) != ICL_Running) continue;
for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
const SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[j];
if (remote_candidate->addr[0] != '\0') return true;
}
}
return false;
}
LINPHONE_END_NAMESPACE

View file

@ -66,6 +66,11 @@ public:
void updateFromRemoteMediaDescription (const SalMediaDescription *localDesc, const SalMediaDescription *remoteDesc, bool isOffer);
void updateIceStateInCallStats ();
void updateLocalMediaDescriptionFromIce (SalMediaDescription *desc);
/*
* Checks if an incoming offer with ICE needs a delayed answer, because the ice session hasn't completed yet with
* connecvity checks.
*/
bool checkIceReinviteNeedsDeferedResponse(SalMediaDescription *md);
private:
void addLocalIceCandidates (int family, const char *addr, IceCheckList *audioCl, IceCheckList *videoCl, IceCheckList *textCl);

View file

@ -24,6 +24,7 @@
#include <bctoolbox/defs.h>
#include <belle-sip/provider.h>
#include "content/content-disposition.h"
#include "content/content-type.h"
using namespace std;
@ -102,7 +103,7 @@ belle_sip_header_allow_t *SalCallOp::create_allow(bool_t enable_update) {
int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) {
ContentType contentType = body.getContentType();
string contentDisposition = body.getContentDisposition();
auto contentDisposition = body.getContentDisposition();
string contentEncoding = body.getContentEncoding();
size_t bodySize = body.getBody().size();
@ -115,8 +116,10 @@ int SalCallOp::set_custom_body(belle_sip_message_t *msg, const Content &body) {
belle_sip_header_content_type_t *content_type = belle_sip_header_content_type_create(contentType.getType().c_str(), contentType.getSubType().c_str());
belle_sip_message_add_header(msg, BELLE_SIP_HEADER(content_type));
}
if (!contentDisposition.empty()) {
belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_header_content_disposition_create(contentDisposition.c_str());
if (contentDisposition.isValid()) {
belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_header_content_disposition_create(
contentDisposition.asString().c_str()
);
belle_sip_message_add_header(msg, BELLE_SIP_HEADER(contentDispositionHeader));
}
if (!contentEncoding.empty())
@ -243,7 +246,9 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) {
if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str));
if (contentDisposition)
body.setContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition));
body.setContentDisposition(
ContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition))
);
if (length > 0 && body_str) body.setBody(body_str, length);
return body;
}
@ -1115,9 +1120,15 @@ int SalCallOp::update(const char *subject, bool_t no_user_consent) {
return -1;
}
void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) {
int SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) {
belle_sip_request_t* cancel;
ms_message("Cancelling INVITE request from [%s] to [%s] ",get_from(), get_to());
if (this->pending_client_trans == NULL){
ms_warning("There is no transaction to cancel.");
return -1;
}
cancel = belle_sip_client_transaction_create_cancel(this->pending_client_trans);
if (cancel){
if (info != NULL){
@ -1125,6 +1136,7 @@ void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(cancel),BELLE_SIP_HEADER(reason));
}
send_request(cancel);
return 0;
}else if (this->dialog){
belle_sip_dialog_state_t state = belle_sip_dialog_get_state(this->dialog);;
/*case where the response received is invalid (could not establish a dialog), but the transaction is not cancellable
@ -1140,6 +1152,7 @@ void SalCallOp::cancel_invite_with_info(const SalErrorInfo *info) {
break;
}
}
return -1;
}
SalMediaDescription *SalCallOp::get_final_media_description() {

View file

@ -45,8 +45,8 @@ public:
int decline(SalReason reason, const char *redirection /*optional*/);
int decline_with_error_info(const SalErrorInfo *info, const SalAddress *redirectionAddr /*optional*/);
int update(const char *subject, bool_t no_user_consent);
void cancel_invite() {cancel_invite_with_info(NULL);}
void cancel_invite_with_info(const SalErrorInfo *info);
int cancel_invite() { return cancel_invite_with_info(NULL);}
int cancel_invite_with_info(const SalErrorInfo *info);
int refer(const char *refer_to_);
int refer_with_replaces(SalCallOp *other_call_op);
int set_referer(SalCallOp *refered_call);

View file

@ -118,7 +118,6 @@ void Sal::process_request_event_cb (void *ud, const belle_sip_request_event_t *e
op->fill_cbs();
}else if (strcmp("REFER",method)==0) {
op=new SalReferOp(sal);
op->fill_cbs();
}else if (strcmp("OPTIONS",method)==0) {
resp=belle_sip_response_create_from_request(req,200);
belle_sip_provider_send_response(sal->prov,resp);

View file

@ -175,6 +175,12 @@ char *Utils::utf8ToChar (uint32_t ic) {
return result;
}
string Utils::trim (const string &str) {
auto itFront = find_if_not(str.begin(), str.end(), [] (int c) { return isspace(c); });
auto itBack = find_if_not(str.rbegin(), str.rend(), [] (int c) { return isspace(c); }).base();
return (itBack <= itFront ? string() : string(itFront, itBack));
}
// -----------------------------------------------------------------------------
tm Utils::getTimeTAsTm (time_t time) {

View file

@ -30,7 +30,17 @@
#define unlink _unlink
#endif
/*
* With IPV6, Flexisip automatically switches to TCP, so it's no more possible to really have Laure configured with UDP
* Anyway for IPV4, it's still a good opportunity to test UDP.
*/
static const char* get_laure_rc(void) {
if (liblinphone_tester_ipv6_available()) {
return "laure_tcp_rc";
} else {
return "laure_rc_udp";
}
}
static void call_waiting_indication_with_param(bool_t enable_caller_privacy) {
bctbx_list_t *iterator;
bctbx_list_t* lcs;
@ -45,7 +55,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) {
linphone_core_remove_supported_tag(pauline->lc,"gruu");
linphone_core_manager_start(pauline,TRUE);
LinphoneCoreManager *laure = ms_new0(LinphoneCoreManager, 1);
linphone_core_manager_init(laure, "laure_rc_udp", NULL);
linphone_core_manager_init(laure, get_laure_rc(), NULL);
linphone_core_remove_supported_tag(laure->lc,"gruu");
linphone_core_manager_start(laure, TRUE);
LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL);
@ -187,7 +197,7 @@ static void second_call_allowed_if_not_using_audio(void){
static void incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallState state) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
bctbx_list_t* lcs;
LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL);
LinphoneCallParams *marie_params=linphone_core_create_call_params(marie->lc, NULL);
@ -385,7 +395,7 @@ end:
static void simple_conference(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
simple_conference_base(marie,pauline,laure, NULL, FALSE);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
@ -396,7 +406,7 @@ static void simple_conference(void) {
static void simple_conference_from_scratch(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneConference *conf;
LinphoneConferenceParams *conf_params;
LinphoneCall *pauline_call, *laure_call;
@ -469,7 +479,7 @@ static void simple_conference_from_scratch(void){
static void simple_encrypted_conference_with_ice(LinphoneMediaEncryption mode) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
if (linphone_core_media_encryption_supported(marie->lc,mode)) {
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
@ -504,7 +514,7 @@ static void simple_zrtp_conference_with_ice(void) {
static void conference_hang_up_call_on_hold(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new("laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new(get_laure_rc());
simple_conference_base(marie, pauline, laure, NULL, TRUE);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
@ -514,7 +524,7 @@ static void conference_hang_up_call_on_hold(void) {
static void simple_call_transfer(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneCall* pauline_called_by_marie;
LinphoneCall *marie_calling_pauline;
LinphoneCall *marie_calling_laure;
@ -579,7 +589,7 @@ end:
static void unattended_call_transfer(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneCall* pauline_called_by_marie;
char* laure_identity=linphone_address_as_string(laure->identity);
@ -668,7 +678,7 @@ static void unattended_call_transfer_with_error(void) {
static void call_transfer_existing_call(bool_t outgoing_call) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneCall* marie_call_pauline;
LinphoneCall* pauline_called_by_marie;
LinphoneCall* marie_call_laure;
@ -768,7 +778,7 @@ static void call_transfer_existing_call_incoming_call(void) {
static void call_transfer_existing_ringing_call(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp");
LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc());
LinphoneCall *marie_call_pauline;
LinphoneCall *pauline_called_by_marie;
LinphoneCall *marie_call_laure;
@ -934,7 +944,7 @@ end:
static void eject_from_3_participants_local_conference(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
eject_from_3_participants_conference(marie, pauline, laure, NULL);
@ -946,7 +956,7 @@ static void eject_from_3_participants_local_conference(void) {
static void eject_from_4_participants_conference(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneCoreManager* michelle = linphone_core_manager_new( "michelle_rc_udp");
int timeout_ms = 5000;
stats initial_laure_stat;
@ -1038,7 +1048,7 @@ end:
void simple_remote_conference(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp");
LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc());
LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE);
LpConfig *marie_config = linphone_core_get_config(marie->lc);
LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc);
@ -1064,7 +1074,7 @@ void simple_remote_conference(void) {
void simple_remote_conference_shut_down_focus(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc_udp");
LinphoneCoreManager *laure = linphone_core_manager_new(get_laure_rc());
LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", FALSE);
LpConfig *marie_config = linphone_core_get_config(marie->lc);
LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc);
@ -1090,7 +1100,7 @@ void simple_remote_conference_shut_down_focus(void) {
void eject_from_3_participants_remote_conference(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE);
LpConfig *marie_config = linphone_core_get_config(marie->lc);
LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc);
@ -1116,7 +1126,7 @@ void eject_from_3_participants_remote_conference(void) {
void do_not_stop_ringing_when_declining_one_of_two_incoming_calls(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc_udp");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneCall* pauline_called_by_marie;
LinphoneCall* pauline_called_by_laure;
LinphoneCallParams *laure_params=linphone_core_create_call_params(laure->lc, NULL);

View file

@ -2008,6 +2008,70 @@ static void video_call_with_thin_congestion(void){
linphone_core_manager_destroy(pauline);
}
static void on_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr) {
if (stream_index == _linphone_call_get_main_video_stream_index(call)) {
stats* stat = get_stats(linphone_call_get_core(call));
stat->tmmbr_received_from_cb = tmmbr;
}
}
static void call_created(LinphoneCore *lc, LinphoneCall *call) {
LinphoneCallCbs *cbs = linphone_factory_create_call_cbs(linphone_factory_get());
linphone_call_cbs_set_tmmbr_received(cbs, on_tmmbr_received);
linphone_call_add_callbacks(call, cbs);
linphone_call_cbs_unref(cbs);
}
/*
* This test simulates a higher bandwith available from marie than expected.
* The stream from pauline to marie is not under test.
* It checks that after a few seconds marie received a TMMBR with the approximate value corresponding to the new bandwidth.
*
**/
static void video_call_with_high_bandwidth_available(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc");
LinphoneVideoPolicy pol = {0};
OrtpNetworkSimulatorParams simparams = { 0 };
LinphoneCoreCbs *core_cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_set_video_device(marie->lc, "Mire: Mire (synthetic moving picture)");
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, TRUE);
pol.automatically_accept = TRUE;
pol.automatically_initiate = TRUE;
linphone_core_set_video_policy(marie->lc, &pol);
linphone_core_set_video_policy(pauline->lc, &pol);
linphone_core_set_preferred_video_size_by_name(marie->lc, "vga");
simparams.mode = OrtpNetworkSimulatorOutbound;
simparams.enabled = TRUE;
simparams.max_bandwidth = 1000000;
simparams.max_buffer_size = (int)simparams.max_bandwidth;
simparams.latency = 60;
linphone_core_set_network_simulator_params(marie->lc, &simparams);
linphone_core_cbs_set_call_created(core_cbs, call_created);
linphone_core_add_callbacks(marie->lc, core_cbs);
if (BC_ASSERT_TRUE(call(marie, pauline))){
/*wait a little in order to have traffic*/
BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, NULL, 5, 50000));
BC_ASSERT_GREATER((float)marie->stat.last_tmmbr_value_received, 870000.f, float, "%f");
BC_ASSERT_LOWER((float)marie->stat.last_tmmbr_value_received, 1150000.f, float, "%f");
end_call(marie, pauline);
}
linphone_core_cbs_unref(core_cbs);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
test_t call_video_tests[] = {
#ifdef VIDEO_ENABLED
TEST_NO_TAG("Call paused resumed with video", call_paused_resumed_with_video),
@ -2073,10 +2137,11 @@ test_t call_video_tests[] = {
TEST_NO_TAG("Classic video entry phone setup", classic_video_entry_phone_setup),
TEST_NO_TAG("Incoming REINVITE with invalid SDP in ACK", incoming_reinvite_with_invalid_ack_sdp),
TEST_NO_TAG("Outgoing REINVITE with invalid SDP in ACK", outgoing_reinvite_with_invalid_ack_sdp),
#endif
TEST_NO_TAG("Video call with no audio and no video codec", video_call_with_no_audio_and_no_video_codec),
TEST_NO_TAG("Call with early media and no SDP in 200 Ok with video", call_with_early_media_and_no_sdp_in_200_with_video),
TEST_NO_TAG("Video call with thin congestion", video_call_with_thin_congestion)
TEST_NO_TAG("Video call with thin congestion", video_call_with_thin_congestion),
TEST_NO_TAG("Video call with high bandwidth available", video_call_with_high_bandwidth_available)
#endif
};
test_suite_t call_video_test_suite = {"Video Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,

View file

@ -1388,7 +1388,7 @@ static void on_refer_received(SalOp *op, const SalAddress *refer_to) {
Sal *sal = sal_op_get_sal(op);
LinphoneCoreManager *receiver = (LinphoneCoreManager*)sal_get_user_pointer(sal);
receiver->stat.number_of_LinphoneCallRefered++;
sal_release_op(op);
}
void resend_refer_other_devices(void) {

View file

@ -2874,7 +2874,6 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2
linphone_core_manager_destroy(pauline2);
}
static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) {
LinphoneCoreManager *marie1 = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
@ -2925,16 +2924,11 @@ static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) {
coresManagerList = bctbx_list_concat(coresManagerList, newCoresManagerList);
coresList = bctbx_list_concat(coresList, newCoresList);
// Marie2 creates a new one-to-one chat room with Pauline
// Marie2 gets the one-to-one chat room with Pauline
stats initialMarie2Stats = marie2->stat;
participantsAddresses = bctbx_list_append(NULL, linphone_address_new(linphone_core_get_identity(pauline->lc)));
LinphoneChatRoom *marie2Cr = create_chat_room_client_side(coresList, marie2, &initialMarie2Stats, participantsAddresses, initialSubject, -1);
LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(coresList, marie2, &initialMarie2Stats, confAddr, initialSubject, 1, FALSE);
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marie2Cr) & LinphoneChatRoomCapabilitiesOneToOne);
// Check that the created address is the same as before
const LinphoneAddress *newConfAddr = linphone_chat_room_get_conference_address(marie2Cr);
BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, newConfAddr));
// Marie2 sends a new message
textMessage = "Fine and you?";
message = _send_message(marie2Cr, textMessage);
@ -3179,6 +3173,65 @@ static void find_one_to_one_chat_room (void) {
linphone_core_manager_destroy(chloe);
}
static void group_chat_room_new_device_after_creation (void) {
LinphoneCoreManager *marie1 = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline1 = linphone_core_manager_create("pauline_rc");
LinphoneCoreManager *pauline2 = linphone_core_manager_create("pauline_rc");
LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc");
bctbx_list_t *coresManagerList = NULL;
bctbx_list_t *participantsAddresses = NULL;
coresManagerList = bctbx_list_append(coresManagerList, marie1);
coresManagerList = bctbx_list_append(coresManagerList, pauline1);
coresManagerList = bctbx_list_append(coresManagerList, pauline2);
coresManagerList = bctbx_list_append(coresManagerList, laure);
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
start_core_for_conference(coresManagerList);
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline1->lc)));
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(laure->lc)));
stats initialMarie1Stats = marie1->stat;
stats initialPauline1Stats = pauline1->stat;
stats initialPauline2Stats = pauline2->stat;
stats initialLaureStats = laure->stat;
// Marie creates a new group chat room
const char *initialSubject = "Colleagues";
LinphoneChatRoom *marie1Cr = create_chat_room_client_side(coresList, marie1, &initialMarie1Stats, participantsAddresses, initialSubject, -1);
participantsAddresses = NULL;
const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marie1Cr);
// Check that the chat room is correctly created on Pauline1 and Pauline2's sides and that the participants are added
LinphoneChatRoom *pauline1Cr = check_creation_chat_room_client_side(coresList, pauline1, &initialPauline1Stats, confAddr, initialSubject, 2, FALSE);
LinphoneChatRoom *pauline2Cr = check_creation_chat_room_client_side(coresList, pauline2, &initialPauline2Stats, confAddr, initialSubject, 2, FALSE);
// Check that the chat room is correctly created on Laure's side and that the participants are added
LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure, &initialLaureStats, confAddr, initialSubject, 2, FALSE);
// Marie adds a new device
LinphoneCoreManager *marie2 = linphone_core_manager_create("marie_rc");
stats initialMarie2Stats = marie2->stat;
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, marie2);
bctbx_list_t *tmpCoresList = init_core_for_conference(tmpCoresManagerList);
coresList = bctbx_list_concat(coresList, tmpCoresList);
start_core_for_conference(tmpCoresManagerList);
bctbx_list_free(tmpCoresManagerList);
LinphoneChatRoom *marie2Cr = check_creation_chat_room_client_side(coresList, marie2, &initialMarie2Stats, confAddr, initialSubject, 2, TRUE);
// Clean db from chat room
linphone_core_manager_delete_chat_room(marie1, marie1Cr, coresList);
linphone_core_delete_chat_room(marie2->lc, marie2Cr);
linphone_core_manager_delete_chat_room(pauline1, pauline1Cr, coresList);
linphone_core_delete_chat_room(pauline2->lc, pauline2Cr);
linphone_core_manager_delete_chat_room(laure, laureCr, coresList);
bctbx_list_free(coresList);
bctbx_list_free(coresManagerList);
linphone_core_manager_destroy(marie1);
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(pauline1);
linphone_core_manager_destroy(pauline2);
linphone_core_manager_destroy(laure);
}
test_t group_chat_tests[] = {
TEST_NO_TAG("Group chat room creation server", group_chat_room_creation_server),
TEST_ONE_TAG("Add participant", group_chat_room_add_participant, "LeaksMemory"),
@ -3222,7 +3275,8 @@ test_t group_chat_tests[] = {
TEST_NO_TAG("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left),
TEST_NO_TAG("Unique one-to-one chatroom re-created from the party that deleted it, with inactive devices", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2),
TEST_NO_TAG("IMDN for group chat room", imdn_for_group_chat_room),
TEST_NO_TAG("Find one to one chat room", find_one_to_one_chat_room)
TEST_NO_TAG("Find one to one chat room", find_one_to_one_chat_room),
TEST_NO_TAG("New device after group chat room creation", group_chat_room_new_device_after_creation)
};
test_suite_t group_chat_test_suite = {

View file

@ -283,6 +283,7 @@ typedef struct _stats {
int number_of_rtcp_generic_nack;
int number_of_tmmbr_received;
int last_tmmbr_value_received;
int tmmbr_received_from_cb;
int number_of_participants_added;
int number_of_participant_admin_statuses_changed;

View file

@ -28,9 +28,14 @@
#include <zlib.h>
#endif
#ifdef __ANDROID__
#include "android/api-level.h"
#endif
/*getline is POSIX 2008, not available on many systems.*/
#if (defined(__ANDROID__) && !defined(__LP64__)) || defined(_WIN32) || defined(__QNX__)
/*It is declared since NDK14 unified headers, that can be detected by the presence of __ANDROID_API_O__ define*/
#if (defined(__ANDROID__) && __ANDROID_API__ <= 16) || defined(_WIN32) || defined(__QNX__)
/* This code is public domain -- Will Hartung 4/9/09 */
static ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
char *bufptr = NULL;

View file

@ -503,9 +503,13 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau
} else {
BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1, 60000));
if (marie->stat.last_received_chat_message) {
LinphoneChatRoom *marie_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
linphone_chat_room_mark_as_read(marie_room);
// We shoudln't get displayed IMDN until file has been downloaded
BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000));
LinphoneChatMessage *recv_msg;
if (download_from_history) {
LinphoneChatRoom *marie_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
msg_list = linphone_chat_room_get_history(marie_room,1);
BC_ASSERT_PTR_NOT_NULL(msg_list);
if (!msg_list) goto end;
@ -529,12 +533,13 @@ void transfer_message_base2(LinphoneCoreManager* marie, LinphoneCoreManager* pau
belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), -1);
BC_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneMessageNotDelivered,1, 10000));
belle_http_provider_set_recv_error(linphone_core_get_http_provider(marie->lc), 0);
BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000));
} else {
/* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */
if (BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneFileTransferDownloadSuccessful,1,55000))) {
compare_files(send_filepath, receive_filepath);
}
BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDisplayed,1, 5000));
}
}
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,2, int, "%d"); //sent twice because of file transfer
@ -549,41 +554,48 @@ end:
}
void transfer_message_base(bool_t upload_error, bool_t download_error, bool_t use_file_body_handler_in_upload,
bool_t use_file_body_handler_in_download, bool_t download_from_history) {
bool_t use_file_body_handler_in_download, bool_t download_from_history, bool_t enable_imdn) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
if (enable_imdn) {
lp_config_set_int(linphone_core_get_config(pauline->lc), "sip", "deliver_imdn", 1);
lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "deliver_imdn", 1);
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
}
transfer_message_base2(marie,pauline,upload_error,download_error, use_file_body_handler_in_upload, use_file_body_handler_in_download, download_from_history);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie);
}
}
static void transfer_message(void) {
transfer_message_base(FALSE, FALSE, FALSE, FALSE, FALSE);
transfer_message_base(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE);
}
static void transfer_message_2(void) {
transfer_message_base(FALSE, FALSE, TRUE, FALSE, FALSE);
transfer_message_base(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE);
}
static void transfer_message_3(void) {
transfer_message_base(FALSE, FALSE, FALSE, TRUE, FALSE);
transfer_message_base(FALSE, FALSE, FALSE, TRUE, FALSE, TRUE);
}
static void transfer_message_4(void) {
transfer_message_base(FALSE, FALSE, TRUE, TRUE, FALSE);
transfer_message_base(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
}
static void transfer_message_from_history(void) {
transfer_message_base(FALSE, FALSE, TRUE, TRUE, TRUE);
transfer_message_base(FALSE, FALSE, TRUE, TRUE, TRUE, TRUE);
}
static void transfer_message_with_upload_io_error(void) {
transfer_message_base(TRUE, FALSE, FALSE, FALSE, FALSE);
transfer_message_base(TRUE, FALSE, FALSE, FALSE, FALSE, TRUE);
}
static void transfer_message_with_download_io_error(void) {
transfer_message_base(FALSE, TRUE, FALSE, FALSE, FALSE);
transfer_message_base(FALSE, TRUE, FALSE, FALSE, FALSE, TRUE);
}
static void transfer_message_upload_cancelled(void) {
@ -730,6 +742,52 @@ static void file_transfer_2_messages_simultaneously(void) {
}
}
static void file_transfer_external_body_url(bool_t use_file_body_handler_in_download) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(marie->lc, pauline->identity);
LinphoneChatMessage* msg = linphone_chat_room_create_message(chat_room, NULL);
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(msg);
char *receive_filepath = bc_tester_file("receive_file.dump");
linphone_chat_message_set_external_body_url(msg, "https://www.linphone.org/img/linphone-open-source-voip-projectX2.png");
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_room_send_chat_message(chat_room, msg);
linphone_chat_message_unref(msg);
BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageReceivedWithFile, 1, 60000));
if (pauline->stat.last_received_chat_message) {
LinphoneChatMessage *recv_msg = pauline->stat.last_received_chat_message;
cbs = linphone_chat_message_get_callbacks(recv_msg);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_received);
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
if (use_file_body_handler_in_download) {
/* Remove any previously downloaded file */
remove(receive_filepath);
linphone_chat_message_set_file_transfer_filepath(recv_msg, receive_filepath);
}
linphone_chat_message_download_file(recv_msg);
/* wait for a long time in case the DNS SRV resolution takes times - it should be immediate though */
BC_ASSERT_TRUE(wait_for_until(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneFileTransferDownloadSuccessful, 1, 55000));
}
remove(receive_filepath);
bc_free(receive_filepath);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void file_transfer_using_external_body_url(void) {
file_transfer_external_body_url(FALSE);
}
static void file_transfer_using_external_body_url_2(void) {
file_transfer_external_body_url(TRUE);
}
static void text_message_denied(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
@ -2130,6 +2188,10 @@ void file_transfer_with_http_proxy(void) {
if (transport_supported(LinphoneTransportTls)) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
lp_config_set_int(linphone_core_get_config(pauline->lc), "sip", "deliver_imdn", 1);
lp_config_set_int(linphone_core_get_config(marie->lc), "sip", "deliver_imdn", 1);
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
linphone_core_set_http_proxy_host(marie->lc, "sip.linphone.org");
transfer_message_base2(marie,pauline,FALSE,FALSE,FALSE,FALSE,FALSE);
linphone_core_manager_destroy(pauline);
@ -2439,6 +2501,8 @@ test_t message_tests[] = {
TEST_NO_TAG("Transfer message upload cancelled", transfer_message_upload_cancelled),
TEST_NO_TAG("Transfer message download cancelled", transfer_message_download_cancelled),
TEST_NO_TAG("Transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously),
TEST_NO_TAG("Transfer using external body URL", file_transfer_using_external_body_url),
TEST_NO_TAG("Transfer using external body URL 2", file_transfer_using_external_body_url_2),
TEST_NO_TAG("Text message denied", text_message_denied),
TEST_NO_TAG("IsComposing notification", is_composing_notification),
TEST_NO_TAG("IMDN notifications", imdn_notifications),

View file

@ -50,7 +50,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool
if (first_file_transfer) {
char *send_filepath = bc_tester_res("sounds/sintel_trailer_opus_h264.mkv");
FileContent *content = new FileContent();
content->setContentType("video/mkv");
content->setContentType(ContentType("video/mkv"));
content->setFilePath(send_filepath);
content->setFileName("sintel_trailer_opus_h264.mkv");
marieMessage->addContent(*content);
@ -65,7 +65,7 @@ static void chat_message_multipart_modifier_base(bool first_file_transfer, bool
if (second_file_transfer) {
char *send_filepath = bc_tester_res("vcards/vcards.vcf");
FileContent *content = new FileContent();
content->setContentType("file/vcf");
content->setContentType(ContentType("file/vcf"));
content->setFilePath(send_filepath);
content->setFileName("vcards.vcf");
marieMessage->addContent(*content);

View file

@ -1571,8 +1571,157 @@ static void extended_notify_sub_unsub_sub2(void) {
bctbx_list_free(lcs);
}
static void simple_publish_with_expire(int expires) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
if (expires > 0) {
linphone_proxy_config_set_publish_expires(proxy,expires);
}
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
presence = linphone_presence_model_new();
linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
linphone_core_set_presence_model(marie->lc,presence);
linphone_presence_model_unref(presence);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_done(proxy);
/*make sure no publish is sent*/
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,FALSE);
linphone_proxy_config_done(proxy);
/*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/
/*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/
wait_for_until(marie->lc,marie->lc,NULL,0,2000);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(marie);
}
static void simple_publish(void) {
simple_publish_with_expire(-1);
}
static void publish_with_expires(void) {
simple_publish_with_expire(2);
}
static void publish_with_dual_identity(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc");
const bctbx_list_t* proxies;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(pauline->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) {
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data;
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
}
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(pauline);
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(pauline);
}
static void publish_with_network_state_changes(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneFriend* marie_as_friend = linphone_core_create_friend_with_address(pauline->lc, get_identity(marie));
LinphoneProxyConfig* proxy;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs,TRUE);
linphone_core_cbs_unref(cbs);
linphone_core_set_user_agent(marie->lc, "full-presence-support", NULL);
linphone_core_set_user_agent(marie->lc, "full-presence-support-bypass", NULL);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
linphone_core_set_network_reachable(marie->lc, FALSE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1));
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i");
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i");
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i");
linphone_core_manager_destroy(marie);
/*make sure there is no remaining publish caused by network failure*/
linphone_core_set_user_agent(pauline->lc, "full-presence-support", NULL);
linphone_core_set_user_agent(pauline->lc, "full-presence-support-bypass", NULL);
linphone_core_add_friend(pauline->lc, marie_as_friend);
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityAway,1));
linphone_friend_unref(marie_as_friend);
linphone_core_manager_destroy(pauline);
}
test_t presence_server_tests[] = {
TEST_NO_TAG("Simple Publish", simple_publish),
TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity),
TEST_NO_TAG("Simple Publish with expires", publish_with_expires),
TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"),
TEST_NO_TAG("Simple", simple),
TEST_NO_TAG("Fast activity change", fast_activity_change),
TEST_NO_TAG("Forked subscribe with late publish", test_forked_subscribe_notify_publish),

View file

@ -142,101 +142,6 @@ void notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *l
counters->number_of_NotifyPresenceReceivedForUriOrTel++;
}
static void simple_publish_with_expire(int expires) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
if (expires > 0) {
linphone_proxy_config_set_publish_expires(proxy,expires);
}
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
presence = linphone_presence_model_new();
linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
linphone_core_set_presence_model(marie->lc,presence);
linphone_presence_model_unref(presence);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_done(proxy);
/*make sure no publish is sent*/
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3,2000));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,FALSE);
linphone_proxy_config_done(proxy);
/*fixme PUBLISH state machine is too simple, clear state should only be propagated at API level when 200ok is received*/
/*BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));*/
wait_for_until(marie->lc,marie->lc,NULL,0,2000);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishCleared,1));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,3));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,3));
linphone_proxy_config_edit(proxy);
linphone_proxy_config_set_publish_expires(proxy, linphone_proxy_config_get_publish_expires(proxy)+1);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,3,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(marie);
}
static void simple_publish(void) {
simple_publish_with_expire(-1);
}
static void publish_with_expires(void) {
simple_publish_with_expire(2);
}
static void publish_with_dual_identity(void) {
LinphoneCoreManager* pauline = linphone_core_manager_new("multi_account_rc");
const bctbx_list_t* proxies;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(pauline->lc, cbs, TRUE);
linphone_core_cbs_unref(cbs);
for (proxies = linphone_core_get_proxy_config_list(pauline->lc); proxies!=NULL; proxies = proxies->next) {
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *) proxies->data;
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
}
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishProgress,4));
BC_ASSERT_TRUE(wait_for(pauline->lc,pauline->lc,&pauline->stat.number_of_LinphonePublishOk,4));
linphone_core_manager_stop(pauline);
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishCleared,4,int,"%i");
BC_ASSERT_EQUAL(pauline->stat.number_of_LinphonePublishOk,4,int,"%i");
linphone_core_manager_destroy(pauline);
}
static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) {
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
@ -306,40 +211,6 @@ static void subscribe_failure_handle_by_app(void) {
linphone_core_manager_destroy(pauline);
}
static void publish_with_network_state_changes(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneProxyConfig* proxy;
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_publish_state_changed(cbs, linphone_publish_state_changed);
_linphone_core_add_callbacks(marie->lc, cbs,TRUE);
linphone_core_cbs_unref(cbs);
proxy = linphone_core_get_default_proxy_config(marie->lc);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,1));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,1));
linphone_core_set_network_reachable(marie->lc, FALSE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationNone,1));
BC_ASSERT_FALSE(wait_for_until(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2,1000));
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,1,int,"%i");
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishError,0,int,"%i");
linphone_core_set_network_reachable(marie->lc, TRUE);
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishProgress,2));
BC_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphonePublishOk,2));
linphone_core_manager_stop(marie);
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishCleared,1,int,"%i"); /*yes it is 3 because when we change the expires, a new LinphoneEvent is created*/
BC_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,2,int,"%i");
linphone_core_manager_destroy(marie);
}
static void simple_subscribe(void) {
LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie");
LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline");
@ -640,14 +511,10 @@ test_t presence_tests[] = {
TEST_ONE_TAG("Simple Subscribe", simple_subscribe,"presence"),
TEST_ONE_TAG("Simple Subscribe with early NOTIFY", simple_subscribe_with_early_notify,"presence"),
TEST_NO_TAG("Simple Subscribe with friend from rc", simple_subscribe_with_friend_from_rc),
TEST_NO_TAG("Simple Publish", simple_publish),
TEST_NO_TAG("Publish with 2 identities", publish_with_dual_identity),
TEST_NO_TAG("Simple Publish with expires", publish_with_expires),
TEST_ONE_TAG("Publish with network state changes", publish_with_network_state_changes, "presence"),
/*TEST_ONE_TAG("Call with presence", call_with_presence, "LeaksMemory"),*/
TEST_NO_TAG("Unsubscribe while subscribing", unsubscribe_while_subscribing),
TEST_NO_TAG("Presence information", presence_information),
TEST_NO_TAG("App managed presence failure", subscribe_failure_handle_by_app),
TEST_ONE_TAG("App managed presence failure", subscribe_failure_handle_by_app,"presence"),
TEST_NO_TAG("Presence SUBSCRIBE forked", subscribe_presence_forked),
TEST_NO_TAG("Presence SUBSCRIBE expired", subscribe_presence_expired),
};

View file

@ -243,12 +243,36 @@ static void load_dynamic_proxy_config(void) {
}
static void single_route(void) {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneProxyConfig *marie_cfg = linphone_core_get_default_proxy_config(marie->lc);
BC_ASSERT_PTR_NOT_NULL(marie_cfg);
const bctbx_list_t *routes = linphone_proxy_config_get_routes(marie_cfg);
BC_ASSERT_PTR_NOT_NULL(routes);
BC_ASSERT_EQUAL(bctbx_list_size(routes), 1, int, "%d");
const char *route = (const char *)bctbx_list_get_data(routes);
BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_route(marie_cfg), "sip:sip.example.org;transport=tcp;lr");
BC_ASSERT_STRING_EQUAL(route, "sip:sip.example.org;transport=tcp;lr");
linphone_proxy_config_set_route(marie_cfg, "sip.linphone.org");
routes = linphone_proxy_config_get_routes(marie_cfg);
BC_ASSERT_PTR_NOT_NULL(routes);
BC_ASSERT_EQUAL(bctbx_list_size(routes), 1, int, "%d");
route = (const char *)bctbx_list_get_data(routes);
BC_ASSERT_STRING_EQUAL(linphone_proxy_config_get_route(marie_cfg), "sip:sip.linphone.org");
BC_ASSERT_STRING_EQUAL(route, "sip:sip.linphone.org");
linphone_core_manager_destroy(marie);
}
test_t proxy_config_tests[] = {
TEST_NO_TAG("Phone normalization without proxy", phone_normalization_without_proxy),
TEST_NO_TAG("Phone normalization with proxy", phone_normalization_with_proxy),
TEST_NO_TAG("Phone normalization with dial escape plus", phone_normalization_with_dial_escape_plus),
TEST_NO_TAG("SIP URI normalization", sip_uri_normalization),
TEST_NO_TAG("Load new default value for proxy config", load_dynamic_proxy_config)
TEST_NO_TAG("Load new default value for proxy config", load_dynamic_proxy_config),
TEST_NO_TAG("Single route", single_route)
};
test_suite_t proxy_config_test_suite = {"Proxy config", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,