mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-18 03:28:07 +00:00
Merge remote-tracking branch 'origin/master' into dev_conference_info
This commit is contained in:
commit
cf86a35a48
46 changed files with 2309 additions and 228 deletions
|
|
@ -115,11 +115,13 @@ if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
|
|||
include("${EP_ortp_CONFIG_DIR}/ORTPConfig.cmake")
|
||||
set(BcToolbox_FIND_COMPONENTS tester)
|
||||
include("${EP_bctoolbox_CONFIG_DIR}/BcToolboxConfig.cmake")
|
||||
include("${EP_belr_CONFIG_DIR}/BelrConfig.cmake")
|
||||
else()
|
||||
find_package(BelleSIP REQUIRED)
|
||||
find_package(Mediastreamer2 REQUIRED)
|
||||
find_package(ORTP REQUIRED)
|
||||
find_package(BcToolbox 0.0.3 REQUIRED OPTIONAL_COMPONENTS tester)
|
||||
find_package(Belr REQUIRED)
|
||||
endif()
|
||||
find_package(XML2 REQUIRED)
|
||||
find_package(Zlib)
|
||||
|
|
@ -208,6 +210,7 @@ set(LINPHONE_INCLUDE_DIRS
|
|||
${BELLESIP_INCLUDE_DIRS}
|
||||
${MEDIASTREAMER2_INCLUDE_DIRS}
|
||||
${BCTOOLBOX_CORE_INCLUDE_DIRS}
|
||||
${BELR_INCLUDE_DIRS}
|
||||
)
|
||||
if (BZRTP_FOUND)
|
||||
list(APPEND LINPHONE_INCLUDE_DIRS ${BZRTP_INCLUDE_DIRS})
|
||||
|
|
@ -243,7 +246,7 @@ if(MSVC)
|
|||
endif()
|
||||
|
||||
add_definitions("-DLINPHONE_EXPORTS")
|
||||
set(LINPHONE_CPPFLAGS ${BELCARD_CPPFLAGS} ${BELLESIP_CPPFLAGS} ${MEDIASTREAMER2_CPPFLAGS} ${BCTOOLBOX_CPPFLAGS})
|
||||
set(LINPHONE_CPPFLAGS ${BELCARD_CPPFLAGS} ${BELLESIP_CPPFLAGS} ${MEDIASTREAMER2_CPPFLAGS} ${BCTOOLBOX_CPPFLAGS} ${BELR_CPPFLAGS})
|
||||
if(ENABLE_STATIC)
|
||||
list(APPEND LINPHONE_CPPFLAGS "-DLINPHONE_STATIC")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -35,13 +35,22 @@ endif()
|
|||
|
||||
|
||||
set(LINPHONE_PRIVATE_HEADER_FILES
|
||||
../src/conference/conference-info.hxx
|
||||
../src/conference/conference-listener.h
|
||||
../src/conference/local-conference-event-handler.h
|
||||
../src/conference/remote-conference-event-handler.h
|
||||
../src/cpim/cpim.h
|
||||
../src/cpim/header/cpim-core-headers.h
|
||||
../src/cpim/header/cpim-generic-header.h
|
||||
../src/cpim/header/cpim-header-p.h
|
||||
../src/cpim/header/cpim-header.h
|
||||
../src/cpim/message/cpim-message.h
|
||||
../src/cpim/parser/cpim-grammar.h
|
||||
../src/cpim/parser/cpim-parser.h
|
||||
../src/object/object.h
|
||||
../src/object/singleton.h
|
||||
../src/utils/general.h
|
||||
../src/conference/conference-listener.h
|
||||
../src/conference/remote-conference-event-handler.h
|
||||
../src/conference/local-conference-event-handler.h
|
||||
../src/conference/conference-info.hxx
|
||||
../src/utils/utils.h
|
||||
bellesip_sal/sal_impl.h
|
||||
carddav.h
|
||||
conference_private.h
|
||||
|
|
@ -128,9 +137,16 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
)
|
||||
set(LINPHONE_SOURCE_FILES_CXX
|
||||
conference.cc
|
||||
../src/conference/remote-conference-event-handler.cpp
|
||||
../src/conference/local-conference-event-handler.cpp
|
||||
../src/conference/conference-info.cxx
|
||||
../src/conference/local-conference-event-handler.cpp
|
||||
../src/conference/remote-conference-event-handler.cpp
|
||||
../src/cpim/header/cpim-core-headers.cpp
|
||||
../src/cpim/header/cpim-generic-header.cpp
|
||||
../src/cpim/header/cpim-header.cpp
|
||||
../src/cpim/message/cpim-message.cpp
|
||||
../src/cpim/parser/cpim-grammar.cpp
|
||||
../src/cpim/parser/cpim-parser.cpp
|
||||
../src/utils/utils.cpp
|
||||
)
|
||||
set(LINPHONE_INCLUDE_DIRS ${LINPHONE_INCLUDE_DIRS} /Users/reisbenjamin/xsd-4.0.0-i686-macosx/libxsd /usr/local/Cellar/xerces-c/3.1.4/include)
|
||||
if(ANDROID)
|
||||
|
|
@ -168,7 +184,11 @@ set(LIBS
|
|||
${MEDIASTREAMER2_LIBRARIES}
|
||||
${ORTP_LIBRARIES}
|
||||
${XML2_LIBRARIES}
|
||||
<<<<<<< HEAD
|
||||
/usr/local/Cellar/xerces-c/3.1.4/lib/libxerces-c.dylib
|
||||
=======
|
||||
${BELR_LIBRARIES}
|
||||
>>>>>>> origin/master
|
||||
)
|
||||
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
list(APPEND LIBS "Ws2_32")
|
||||
|
|
|
|||
|
|
@ -117,13 +117,14 @@ void linphone_chat_message_cbs_set_file_transfer_progress_indication(
|
|||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage);
|
||||
|
||||
static void _linphone_chat_room_destroy(LinphoneChatRoom *cr) {
|
||||
bctbx_list_free_with_data(cr->transient_messages, (void (*)(void *))linphone_chat_message_release);
|
||||
if (cr->received_rtt_characters) {
|
||||
cr->received_rtt_characters = bctbx_list_free_with_data(cr->received_rtt_characters, (void (*)(void *))ms_free);
|
||||
}
|
||||
linphone_chat_room_delete_composing_idle_timer(cr);
|
||||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
|
||||
bctbx_list_free_with_data(cr->transient_messages, (bctbx_list_free_func)linphone_chat_message_release);
|
||||
if (cr->weak_messages != NULL) bctbx_list_free(cr->weak_messages);
|
||||
if (cr->received_rtt_characters) {
|
||||
cr->received_rtt_characters = bctbx_list_free_with_data(cr->received_rtt_characters, (bctbx_list_free_func)ms_free);
|
||||
}
|
||||
if (cr->lc != NULL) {
|
||||
if (bctbx_list_find(cr->lc->chatrooms, cr)) {
|
||||
ms_error("LinphoneChatRoom[%p] is destroyed while still being used by the LinphoneCore. This is abnormal."
|
||||
|
|
@ -138,7 +139,6 @@ static void _linphone_chat_room_destroy(LinphoneChatRoom *cr) {
|
|||
if (cr->pending_message)
|
||||
linphone_chat_message_destroy(cr->pending_message);
|
||||
ms_free(cr->peer);
|
||||
if (cr->weak_messages != NULL) bctbx_list_free(cr->weak_messages);
|
||||
}
|
||||
|
||||
void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
|
||||
|
|
@ -313,6 +313,7 @@ void linphone_chat_room_release(LinphoneChatRoom *cr) {
|
|||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
|
||||
bctbx_list_for_each(cr->weak_messages, (bctbx_list_iterate_func)linphone_chat_message_deactivate);
|
||||
bctbx_list_for_each(cr->transient_messages, (bctbx_list_iterate_func)linphone_chat_message_deactivate);
|
||||
cr->lc = NULL;
|
||||
linphone_chat_room_unref(cr);
|
||||
}
|
||||
|
|
@ -784,8 +785,8 @@ static const char *iscomposing_prefix = "/xsi:isComposing";
|
|||
static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) {
|
||||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr iscomposing_object;
|
||||
const char *state_str = NULL;
|
||||
const char *refresh_str = NULL;
|
||||
char *state_str = NULL;
|
||||
char *refresh_str = NULL;
|
||||
int refresh_duration = lp_config_get_int(cr->lc->config, "sip", "composing_remote_refresh_timeout",
|
||||
COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT);
|
||||
int i;
|
||||
|
|
@ -860,8 +861,8 @@ static void process_imdn(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) {
|
|||
xmlXPathObjectPtr imdn_object;
|
||||
xmlXPathObjectPtr delivery_status_object;
|
||||
xmlXPathObjectPtr display_status_object;
|
||||
const char *message_id_str = NULL;
|
||||
const char *datetime_str = NULL;
|
||||
char *message_id_str = NULL;
|
||||
char *datetime_str = NULL;
|
||||
LinphoneCore *lc = linphone_chat_room_get_core(cr);
|
||||
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc);
|
||||
|
||||
|
|
@ -1717,11 +1718,11 @@ void linphone_chat_message_unref(LinphoneChatMessage *msg) {
|
|||
}
|
||||
|
||||
static void linphone_chat_message_deactivate(LinphoneChatMessage *msg){
|
||||
if (msg->file_transfer_information != NULL) {
|
||||
_linphone_chat_message_cancel_file_transfer(msg, FALSE);
|
||||
}
|
||||
/*mark the chat msg as orphan (it has no chat room anymore)*/
|
||||
msg->chat_room = NULL;
|
||||
if (msg->file_transfer_information != NULL) {
|
||||
linphone_chat_message_cancel_file_transfer(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_chat_message_release(LinphoneChatMessage *msg) {
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data,
|
|||
} else { /* no encryption key, transfer in plain, just copy the msg sent by server */
|
||||
msg->message = ms_strdup(body);
|
||||
}
|
||||
msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
|
||||
linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml");
|
||||
linphone_chat_message_ref(msg);
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone);
|
||||
_release_http_request(msg);
|
||||
|
|
@ -613,7 +613,7 @@ void linphone_chat_message_start_file_download(LinphoneChatMessage *msg,
|
|||
linphone_chat_message_download_file(msg);
|
||||
}
|
||||
|
||||
void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) {
|
||||
void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) {
|
||||
if (msg->http_request) {
|
||||
if (msg->state == LinphoneChatMessageStateInProgress) {
|
||||
linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered);
|
||||
|
|
@ -625,7 +625,7 @@ void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) {
|
|||
, msg
|
||||
, msg->chat_room);
|
||||
belle_http_provider_cancel_request(msg->chat_room->lc->http_provider, msg->http_request);
|
||||
if (msg->dir == LinphoneChatMessageOutgoing) {
|
||||
if ((msg->dir == LinphoneChatMessageOutgoing) && unref) {
|
||||
// must release it
|
||||
linphone_chat_message_unref(msg);
|
||||
}
|
||||
|
|
@ -639,6 +639,10 @@ void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) {
|
|||
}
|
||||
}
|
||||
|
||||
void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) {
|
||||
_linphone_chat_message_cancel_file_transfer(msg, TRUE);
|
||||
}
|
||||
|
||||
void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) {
|
||||
if (msg->file_transfer_filepath != NULL) {
|
||||
ms_free(msg->file_transfer_filepath);
|
||||
|
|
|
|||
|
|
@ -205,9 +205,9 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
|
|||
LinphoneFriend *lf;
|
||||
LinphoneContent *presence_part;
|
||||
xmlXPathObjectPtr resource_object;
|
||||
const char *version_str = NULL;
|
||||
const char *full_state_str = NULL;
|
||||
const char *uri = NULL;
|
||||
char *version_str = NULL;
|
||||
char *full_state_str = NULL;
|
||||
char *uri = NULL;
|
||||
bool_t full_state = FALSE;
|
||||
int version;
|
||||
int i;
|
||||
|
|
@ -249,7 +249,7 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
|
|||
resource_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/rlmi:list/rlmi:resource/rlmi:instance[@state=\"active\"]/..");
|
||||
if ((resource_object != NULL) && (resource_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) {
|
||||
const char *cid = NULL;
|
||||
char *cid = NULL;
|
||||
linphone_xml_xpath_context_set_node(xml_ctx, xmlXPathNodeSetItem(resource_object->nodesetval, i-1));
|
||||
cid = linphone_get_xml_text_content(xml_ctx, "./rlmi:instance/@cid");
|
||||
if (cid != NULL) {
|
||||
|
|
|
|||
|
|
@ -579,8 +579,8 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
|
|||
uint8_t selfZid[12]; /* same data but in byte buffer */
|
||||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
limeKey_t associatedKey;
|
||||
const char *peerZidHex = NULL;
|
||||
const char *sessionIndexHex = NULL;
|
||||
char *peerZidHex = NULL;
|
||||
char *sessionIndexHex = NULL;
|
||||
xmlparsing_context_t *xml_ctx;
|
||||
xmlXPathObjectPtr msg_object;
|
||||
uint8_t *encryptedMessage = NULL;
|
||||
|
|
@ -635,12 +635,14 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
|
|||
msg_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/doc/msg");
|
||||
if ((msg_object != NULL) && (msg_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= msg_object->nodesetval->nodeNr; i++) {
|
||||
const char *currentZidHex;
|
||||
const char *encryptedMessageb64;
|
||||
const char *encryptedContentTypeb64;
|
||||
char *currentZidHex;
|
||||
|
||||
char *encryptedMessageb64;
|
||||
char *encryptedContentTypeb64;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/pzid", i);
|
||||
currentZidHex = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if ((currentZidHex != NULL) && (strcmp(currentZidHex, (char *)selfZidHex) == 0)) {
|
||||
linphone_free_xml_text_content(currentZidHex);
|
||||
/* We found the msg node we are looking for */
|
||||
snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/index", i);
|
||||
sessionIndexHex = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
|
@ -665,9 +667,9 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (currentZidHex != NULL) linphone_free_xml_text_content(currentZidHex);
|
||||
}
|
||||
}
|
||||
if (msg_object != NULL) xmlXPathFreeObject(msg_object);
|
||||
}
|
||||
|
||||
/* do we have retrieved correctly all the needed data */
|
||||
|
|
@ -766,6 +768,7 @@ bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
|
|||
return the list of possible uris and store the selected one in the chatroom ? */
|
||||
res = (lime_getCachedSndKeysByURI(zrtp_cache_db, &associatedKeys) == 0);
|
||||
lime_freeKeys(&associatedKeys);
|
||||
ms_free(peer);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
@ -795,7 +798,10 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
|
|||
}
|
||||
peerUri = linphone_address_as_string_uri_only(msg->from);
|
||||
selfUri = linphone_address_as_string_uri_only(msg->to);
|
||||
retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type, bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")));
|
||||
retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type,
|
||||
bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")));
|
||||
ms_free(peerUri);
|
||||
ms_free(selfUri);
|
||||
if (retval != 0) {
|
||||
ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval));
|
||||
if (decrypted_body) ms_free(decrypted_body);
|
||||
|
|
@ -809,6 +815,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
|
|||
msg->message = (char *)decrypted_body;
|
||||
if (decrypted_content_type != NULL) {
|
||||
linphone_chat_message_set_content_type(msg, decrypted_content_type);
|
||||
ms_free(decrypted_content_type);
|
||||
} else {
|
||||
if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) {
|
||||
linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml");
|
||||
|
|
@ -863,7 +870,7 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn
|
|||
ms_free(msg->message);
|
||||
}
|
||||
msg->message = (char *)crypted_body;
|
||||
msg->content_type = ms_strdup(new_content_type);
|
||||
linphone_chat_message_set_content_type(msg, new_content_type);
|
||||
}
|
||||
ms_free(peerUri);
|
||||
ms_free(selfUri);
|
||||
|
|
|
|||
|
|
@ -1721,6 +1721,9 @@ static void linphone_call_set_terminated(LinphoneCall *call){
|
|||
if (call->chat_room){
|
||||
call->chat_room->call = NULL;
|
||||
}
|
||||
if (lc->calls == NULL){
|
||||
ms_bandwidth_controller_reset_state(lc->bw_controller);
|
||||
}
|
||||
}
|
||||
|
||||
/*function to be called at each incoming reINVITE, in order to adjust various local parameters to what is being offered by remote:
|
||||
|
|
|
|||
|
|
@ -6227,6 +6227,9 @@ static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reacha
|
|||
bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
|
||||
}
|
||||
linphone_core_repair_calls(lc);
|
||||
if (lc->bw_controller){
|
||||
ms_bandwidth_controller_reset_state(lc->bw_controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6623,8 +6626,7 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName) {
|
|||
int ret;
|
||||
const char *errmsg;
|
||||
const char *backupExtension = "_backup";
|
||||
char *backupName = reinterpret_cast<char *>(malloc(snprintf(NULL, 0, "%s%s", fileName, backupExtension) + 1));
|
||||
sprintf(backupName, "%s%s", fileName, backupExtension);
|
||||
char *backupName = bctbx_strdup_printf("%s%s", fileName, backupExtension);
|
||||
sqlite3 *db;
|
||||
|
||||
linphone_core_zrtp_cache_close(lc);
|
||||
|
|
@ -6637,7 +6639,7 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName) {
|
|||
unlink(backupName);
|
||||
rename(fileName, backupName);
|
||||
lc->zrtp_cache_db=NULL;
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = ms_zrtp_initCache((void *)db); /* this may perform an update, check return value */
|
||||
|
|
@ -6652,11 +6654,13 @@ void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName) {
|
|||
unlink(backupName);
|
||||
rename(fileName, backupName);
|
||||
lc->zrtp_cache_db = NULL;
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* everything ok, set the db pointer into core */
|
||||
lc->zrtp_cache_db = db;
|
||||
end:
|
||||
if (backupName) bctbx_free(backupName);
|
||||
#endif /* SQLITE_STORAGE_ENABLED */
|
||||
}
|
||||
|
||||
|
|
@ -7011,9 +7015,9 @@ const char * linphone_core_get_video_preset(const LinphoneCore *lc) {
|
|||
static int linphone_core_call_void_method(jobject obj, jmethodID id) {
|
||||
JNIEnv *env=ms_get_jni_env();
|
||||
if (env && obj) {
|
||||
(*env)->CallVoidMethod(env,obj,id);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionClear(env);
|
||||
env->CallVoidMethod(obj,id);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionClear();
|
||||
return -1;
|
||||
} else
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -3512,6 +3512,107 @@ extern "C" jint Java_org_linphone_core_PayloadTypeImpl_getRate(JNIEnv* env,jobj
|
|||
return (jint)payload_type_get_rate(pt);
|
||||
}
|
||||
|
||||
/* Linphone Player */
|
||||
struct LinphonePlayerData {
|
||||
LinphonePlayerData(JNIEnv *env, jobject listener, jobject window) :
|
||||
mListener(env->NewGlobalRef(listener)),
|
||||
mWindow(env->NewGlobalRef(window))
|
||||
{
|
||||
mListenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass(listener));
|
||||
mEndOfFileMethodID = env->GetMethodID(mListenerClass, "endOfFile", "(Lorg/linphone/core/LinphonePlayer;)V");
|
||||
if(mEndOfFileMethodID == NULL) {
|
||||
ms_error("Could not get endOfFile method ID");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
~LinphonePlayerData() {
|
||||
JNIEnv *env;
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
env->DeleteGlobalRef(mListener);
|
||||
env->DeleteGlobalRef(mListenerClass);
|
||||
if (mWindow) env->DeleteGlobalRef(mWindow);
|
||||
}
|
||||
|
||||
void setPlayer(jobject player) { mJLinphonePlayer = player; }
|
||||
|
||||
jobject mListener;
|
||||
jclass mListenerClass;
|
||||
jobject mJLinphonePlayer;
|
||||
jobject mWindow;
|
||||
jmethodID mEndOfFileMethodID;
|
||||
};
|
||||
|
||||
static void _eof_callback(LinphonePlayer *player) {
|
||||
JNIEnv *env;
|
||||
LinphonePlayerData *player_data = (LinphonePlayerData *)linphone_player_get_user_data(player);
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
env->CallVoidMethod(player_data->mListener, player_data->mEndOfFileMethodID, player_data->mJLinphonePlayer);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphonePlayerImpl_init(JNIEnv *env, jobject jPlayer, jlong ptr) {
|
||||
LinphonePlayer *player = (LinphonePlayer *)ptr;
|
||||
LinphonePlayerData *data = (LinphonePlayerData *)linphone_player_get_user_data(player);
|
||||
data->setPlayer(jPlayer);
|
||||
linphone_player_cbs_set_eof_reached(linphone_player_get_callbacks(player), _eof_callback);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_open(JNIEnv *env, jobject jPlayer, jlong ptr, jstring filename) {
|
||||
const char *cfilename = GetStringUTFChars(env, filename);
|
||||
if(linphone_player_open((LinphonePlayer *)ptr, cfilename) == -1) {
|
||||
ReleaseStringUTFChars(env, filename, cfilename);
|
||||
return -1;
|
||||
}
|
||||
ReleaseStringUTFChars(env, filename, cfilename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_start(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_start((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_pause(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_pause((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_seek(JNIEnv *env, jobject jobj, jlong ptr, jint timeMs) {
|
||||
return (jint)linphone_player_seek((LinphonePlayer *)ptr, timeMs);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getState(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_state((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getDuration(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_duration((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getCurrentPosition(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_current_position((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphonePlayerImpl_close(JNIEnv *env, jobject playerPtr, jlong ptr) {
|
||||
LinphonePlayer *player = (LinphonePlayer *)ptr;
|
||||
if(player->user_data) {
|
||||
LinphonePlayerData *data = (LinphonePlayerData *)player->user_data;
|
||||
if(data) delete data;
|
||||
player->user_data = NULL;
|
||||
}
|
||||
linphone_player_close(player);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphonePlayerImpl_destroy(JNIEnv *env, jobject jobj, jlong playerPtr) {
|
||||
LinphonePlayer *player = (LinphonePlayer *)playerPtr;
|
||||
if(player == NULL) {
|
||||
ms_error("Cannot destroy the LinphonePlayerImpl object. Native pointer is NULL");
|
||||
return;
|
||||
}
|
||||
if(linphone_player_get_user_data(player)) {
|
||||
delete (LinphonePlayerData *)linphone_player_get_user_data(player);
|
||||
}
|
||||
linphone_player_unref(player);
|
||||
}
|
||||
|
||||
//LinphoneCall
|
||||
extern "C" void Java_org_linphone_core_LinphoneCallImpl_finalize(JNIEnv* env
|
||||
,jobject thiz
|
||||
|
|
@ -3702,7 +3803,10 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getAverageQuality( JNI
|
|||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getPlayer(JNIEnv *env, jobject thiz, jlong callPtr) {
|
||||
return (jlong)linphone_call_get_player((LinphoneCall *)callPtr);
|
||||
LinphonePlayer *player = linphone_call_get_player((LinphoneCall *)callPtr);
|
||||
LinphonePlayerData *data = new LinphonePlayerData(env, thiz, NULL);
|
||||
linphone_player_set_user_data(player, data);
|
||||
return (jlong)linphone_player_ref(player);
|
||||
}
|
||||
|
||||
extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_mediaInProgress( JNIEnv* env
|
||||
|
|
@ -7503,109 +7607,15 @@ JNIEXPORT void JNICALL Java_org_linphone_core_ErrorInfoImpl_unref(JNIEnv *env, j
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Linphone Player */
|
||||
struct LinphonePlayerData {
|
||||
LinphonePlayerData(JNIEnv *env, jobject listener, jobject jLinphonePlayer) :
|
||||
mListener(env->NewGlobalRef(listener)),
|
||||
mJLinphonePlayer(env->NewGlobalRef(jLinphonePlayer))
|
||||
{
|
||||
mListenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass(listener));
|
||||
mEndOfFileMethodID = env->GetMethodID(mListenerClass, "endOfFile", "(Lorg/linphone/core/LinphonePlayer;)V");
|
||||
if(mEndOfFileMethodID == NULL) {
|
||||
ms_error("Could not get endOfFile method ID");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
~LinphonePlayerData() {
|
||||
JNIEnv *env;
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
env->DeleteGlobalRef(mListener);
|
||||
env->DeleteGlobalRef(mListenerClass);
|
||||
env->DeleteGlobalRef(mJLinphonePlayer);
|
||||
}
|
||||
|
||||
jobject mListener;
|
||||
jclass mListenerClass;
|
||||
jobject mJLinphonePlayer;
|
||||
jmethodID mEndOfFileMethodID;
|
||||
};
|
||||
|
||||
static void _eof_callback(LinphonePlayer *player, void *user_data) {
|
||||
JNIEnv *env;
|
||||
LinphonePlayerData *player_data = (LinphonePlayerData *)user_data;
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
env->CallVoidMethod(player_data->mListener, player_data->mEndOfFileMethodID, player_data->mJLinphonePlayer);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_open(JNIEnv *env, jobject jPlayer, jlong ptr, jstring filename) {
|
||||
const char *cfilename = GetStringUTFChars(env, filename);
|
||||
if(linphone_player_open((LinphonePlayer *)ptr, cfilename) == -1) {
|
||||
ReleaseStringUTFChars(env, filename, cfilename);
|
||||
return -1;
|
||||
}
|
||||
ReleaseStringUTFChars(env, filename, cfilename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_start(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_start((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_pause(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_pause((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_seek(JNIEnv *env, jobject jobj, jlong ptr, jint timeMs) {
|
||||
return (jint)linphone_player_seek((LinphonePlayer *)ptr, timeMs);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getState(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_state((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getDuration(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_duration((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphonePlayerImpl_getCurrentPosition(JNIEnv *env, jobject jobj, jlong ptr) {
|
||||
return (jint)linphone_player_get_current_position((LinphonePlayer *)ptr);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphonePlayerImpl_close(JNIEnv *env, jobject playerPtr, jlong ptr) {
|
||||
LinphonePlayer *player = (LinphonePlayer *)ptr;
|
||||
if(player->user_data) {
|
||||
LinphonePlayerData *data = (LinphonePlayerData *)player->user_data;
|
||||
if(data) delete data;
|
||||
player->user_data = NULL;
|
||||
}
|
||||
linphone_player_close(player);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphonePlayerImpl_destroy(JNIEnv *env, jobject jobj, jlong playerPtr) {
|
||||
LinphonePlayer *player = (LinphonePlayer *)playerPtr;
|
||||
if(player == NULL) {
|
||||
ms_error("Cannot destroy the LinphonePlayerImpl object. Native pointer is NULL");
|
||||
return;
|
||||
}
|
||||
if(player->user_data) {
|
||||
delete (LinphonePlayerData *)player->user_data;
|
||||
}
|
||||
jobject window_id = (jobject)ms_media_player_get_window_id((MSMediaPlayer *)player->impl);
|
||||
if(window_id) env->DeleteGlobalRef(window_id);
|
||||
_linphone_player_destroy(player);
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createLocalPlayer(JNIEnv *env, jobject jobj, jlong ptr, jobject window) {
|
||||
jobject window_ref = NULL;
|
||||
window_ref = env->NewGlobalRef(window);
|
||||
LinphonePlayer *player = linphone_core_create_local_player((LinphoneCore *)ptr, NULL, "MSAndroidDisplay", (void *)window_ref);
|
||||
LinphonePlayer *player = linphone_core_create_local_player((LinphoneCore *)ptr, NULL, "MSAndroidDisplay", (void *)window);
|
||||
LinphonePlayerData *data = new LinphonePlayerData(env, jobj, window);
|
||||
linphone_player_set_user_data(player, data);
|
||||
if(player == NULL) {
|
||||
ms_error("Fails to create a player");
|
||||
if(window_ref) env->DeleteGlobalRef(window_ref);
|
||||
return 0;
|
||||
} else {
|
||||
return (jlong)player;
|
||||
return (jlong)linphone_player_ref(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
#ifdef SQLITE_STORAGE_ENABLED
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "I64u"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !defined(__QNXNTO__) && !defined(__ANDROID__)
|
||||
|
|
@ -883,7 +880,7 @@ void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
|
|||
}
|
||||
|
||||
static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){
|
||||
ms_warning("SQL statement '%s' took %" PRIu64 " microseconds", statement, (uint64_t)(duration / 1000LL) );
|
||||
ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)(duration / 1000LL) );
|
||||
}
|
||||
|
||||
static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){
|
||||
|
|
|
|||
|
|
@ -616,9 +616,6 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
|||
IceCheckList *video_cl;
|
||||
IceCheckList *text_cl;
|
||||
LinphoneNatPolicy *nat_policy = call->nat_policy;
|
||||
const char *server = NULL;
|
||||
|
||||
if (nat_policy != NULL) server = linphone_nat_policy_get_stun_server(nat_policy);
|
||||
|
||||
if (call->ice_session == NULL) return -1;
|
||||
audio_cl = ice_session_check_list(call->ice_session, call->main_audio_stream_index);
|
||||
|
|
@ -626,7 +623,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
|||
text_cl = ice_session_check_list(call->ice_session, call->main_text_stream_index);
|
||||
if ((audio_cl == NULL) && (video_cl == NULL) && (text_cl == NULL)) return -1;
|
||||
|
||||
if ((nat_policy != NULL) && (server != NULL) && (server[0] != '\0')) {
|
||||
if ((nat_policy != NULL) && linphone_nat_policy_stun_server_activated(nat_policy)) {
|
||||
ai=linphone_nat_policy_get_stun_server_addrinfo(nat_policy);
|
||||
if (ai==NULL){
|
||||
ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun.");
|
||||
|
|
@ -658,9 +655,9 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){
|
|||
} else {
|
||||
linphone_core_add_local_ice_candidates(call, AF_INET, local_addr, audio_cl, video_cl, text_cl);
|
||||
}
|
||||
if ((ai != NULL) && (nat_policy != NULL)
|
||||
&& (linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy))) {
|
||||
if ((ai != NULL) && (nat_policy != NULL) && linphone_nat_policy_stun_server_activated(nat_policy)) {
|
||||
bool_t gathering_in_progress;
|
||||
const char *server = linphone_nat_policy_get_stun_server(nat_policy);
|
||||
ms_message("ICE: gathering candidate from [%s] using %s", server, linphone_nat_policy_turn_enabled(nat_policy) ? "TURN" : "STUN");
|
||||
/* Gather local srflx candidates. */
|
||||
ice_session_enable_turn(call->ice_session, linphone_nat_policy_turn_enabled(nat_policy));
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static void linphone_nat_policy_destroy(LinphoneNatPolicy *policy) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy) {
|
||||
bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy) {
|
||||
const char *server = linphone_nat_policy_get_stun_server(policy);
|
||||
return (server != NULL) && (server[0] != '\0')
|
||||
&& ((linphone_nat_policy_stun_enabled(policy) == TRUE) || (linphone_nat_policy_turn_enabled(policy) == TRUE));
|
||||
|
|
@ -234,6 +234,7 @@ void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) {
|
|||
if (service != NULL) {
|
||||
int family = AF_INET;
|
||||
if (linphone_core_ipv6_enabled(policy->lc) == TRUE) family = AF_INET6;
|
||||
ms_message("Starting stun server resolution [%s]", host);
|
||||
policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, family, stun_server_resolved, policy);
|
||||
if (policy->stun_resolver_context) belle_sip_object_ref(policy->stun_resolver_context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1201,8 +1201,8 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx
|
|||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr note_object;
|
||||
LinphonePresenceNote *note;
|
||||
const char *note_str;
|
||||
const char *lang;
|
||||
char *note_str;
|
||||
char *lang;
|
||||
int i;
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx);
|
||||
|
|
@ -1231,10 +1231,10 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
|
|||
xmlXPathObjectPtr service_object;
|
||||
xmlXPathObjectPtr pidfonline_object;
|
||||
LinphonePresenceService *service;
|
||||
const char *basic_status_str;
|
||||
const char *service_id_str;
|
||||
const char *timestamp_str;
|
||||
const char *contact_str;
|
||||
char *basic_status_str;
|
||||
char *service_id_str;
|
||||
char *timestamp_str;
|
||||
char *contact_str;
|
||||
LinphonePresenceBasicStatus basic_status;
|
||||
int i;
|
||||
|
||||
|
|
@ -1306,7 +1306,7 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml
|
|||
xmlXPathObjectPtr activities_object;
|
||||
xmlNodePtr activity_node;
|
||||
LinphonePresenceActivity *activity;
|
||||
const char *description;
|
||||
char *description;
|
||||
int i, j;
|
||||
int err = 0;
|
||||
|
||||
|
|
@ -1321,7 +1321,7 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml
|
|||
activity_node = activities_object->nodesetval->nodeTab[j];
|
||||
if ((activity_node->name != NULL) && (is_valid_activity_name((const char *)activity_node->name) == TRUE)) {
|
||||
LinphonePresenceActivityType acttype;
|
||||
description = (const char *)xmlNodeGetContent(activity_node);
|
||||
description = (char *)xmlNodeGetContent(activity_node);
|
||||
if ((description != NULL) && (description[0] == '\0')) {
|
||||
linphone_free_xml_text_content(description);
|
||||
description = NULL;
|
||||
|
|
@ -1348,8 +1348,8 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx,
|
|||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr note_object;
|
||||
LinphonePresenceNote *note;
|
||||
const char *note_str;
|
||||
const char *lang;
|
||||
char *note_str;
|
||||
char *lang;
|
||||
int i;
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note", person_prefix, person_idx);
|
||||
|
|
@ -1395,8 +1395,8 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp
|
|||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr person_object;
|
||||
LinphonePresencePerson *person;
|
||||
const char *person_id_str;
|
||||
const char *person_timestamp_str;
|
||||
char *person_id_str;
|
||||
char *person_timestamp_str;
|
||||
time_t timestamp;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
|
@ -1444,8 +1444,8 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho
|
|||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr note_object;
|
||||
LinphonePresenceNote *note;
|
||||
const char *note_str;
|
||||
const char *lang;
|
||||
char *note_str;
|
||||
char *lang;
|
||||
int i;
|
||||
|
||||
note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note");
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
|
@ -656,6 +657,7 @@ void linphone_chat_message_set_state(LinphoneChatMessage *msg, LinphoneChatMessa
|
|||
void linphone_chat_message_set_is_secured(LinphoneChatMessage *msg, bool_t secured);
|
||||
void linphone_chat_message_send_delivery_notification(LinphoneChatMessage *cm, LinphoneReason reason);
|
||||
void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm);
|
||||
void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref);
|
||||
int linphone_chat_room_upload_file(LinphoneChatMessage *msg);
|
||||
void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
|
||||
LinphoneChatMessageCbs *linphone_chat_message_cbs_new(void);
|
||||
|
|
@ -1371,6 +1373,7 @@ struct _LinphoneNatPolicy {
|
|||
|
||||
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneNatPolicy);
|
||||
|
||||
bool_t linphone_nat_policy_stun_server_activated(LinphoneNatPolicy *policy);
|
||||
void linphone_nat_policy_save_to_config(const LinphoneNatPolicy *policy);
|
||||
|
||||
struct _LinphoneImNotifPolicy {
|
||||
|
|
@ -1700,8 +1703,8 @@ void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...);
|
|||
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx);
|
||||
void linphone_xml_xpath_context_set_node(xmlparsing_context_t *xml_ctx, xmlNodePtr node);
|
||||
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name);
|
||||
void linphone_free_xml_text_content(const char *text);
|
||||
char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name);
|
||||
void linphone_free_xml_text_content(char *text);
|
||||
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx);
|
||||
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
|
|||
size_t namesize;
|
||||
char *machine;
|
||||
sysctlbyname("hw.machine", NULL, &namesize, NULL, 0);
|
||||
machine = malloc(namesize);
|
||||
machine = reinterpret_cast<char *>(malloc(namesize));
|
||||
sysctlbyname("hw.machine", machine, &namesize, NULL, 0);
|
||||
APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "Device: %s\r\n", machine);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
#include "linphone/linphonecore.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LinphoneRingtonePlayer* linphone_ringtoneplayer_ios_new();
|
||||
void linphone_ringtoneplayer_ios_destroy(LinphoneRingtonePlayer* rp);
|
||||
int linphone_ringtoneplayer_ios_start_with_cb(LinphoneRingtonePlayer* rp, const char* ringtone, int loop_pause_ms, LinphoneRingtonePlayerFunc end_of_ringtone, void * user_data);
|
||||
bool_t linphone_ringtoneplayer_ios_is_started(LinphoneRingtonePlayer* rp);
|
||||
int linphone_ringtoneplayer_ios_stop(LinphoneRingtonePlayer* rp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *
|
|||
return (char *)text;
|
||||
}
|
||||
|
||||
const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name) {
|
||||
char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression, const char *attribute_name) {
|
||||
xmlXPathObjectPtr xpath_obj;
|
||||
xmlChar *text = NULL;
|
||||
|
||||
|
|
@ -118,10 +118,10 @@ const char * linphone_get_xml_attribute_text_content(xmlparsing_context_t *xml_c
|
|||
xmlXPathFreeObject(xpath_obj);
|
||||
}
|
||||
|
||||
return (const char *)text;
|
||||
return (char*)text;
|
||||
}
|
||||
|
||||
void linphone_free_xml_text_content(const char *text) {
|
||||
void linphone_free_xml_text_content(char *text) {
|
||||
xmlFree((xmlChar *)text);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ static void parse_valid_xml_rpc_response(LinphoneXmlRpcRequest *request, const c
|
|||
request->status = LinphoneXmlRpcStatusFailed;
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)response_body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
const char *response_str = NULL;
|
||||
char *response_str = NULL;
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) goto end;
|
||||
switch (request->response.type) {
|
||||
case LinphoneXmlRpcArgInt:
|
||||
|
|
|
|||
|
|
@ -3719,6 +3719,7 @@ LINPHONE_PUBLIC void linphone_core_set_device_rotation(LinphoneCore *lc, int rot
|
|||
* This is needed on some mobile platforms to get the number of degrees the camera sensor
|
||||
* is rotated relative to the screen.
|
||||
* @param lc The linphone core related to the operation
|
||||
* @ingroup media_parameters
|
||||
* @return The camera sensor rotation in degrees (0 to 360) or -1 if it could not be retrieved
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc);
|
||||
|
|
|
|||
|
|
@ -487,8 +487,9 @@ typedef struct belle_sip_dict LinphoneDictionary;
|
|||
|
||||
/**
|
||||
* Enum describing the result of the echo canceller calibration process.
|
||||
* @ingroup media_parameters
|
||||
**/
|
||||
typedef enum {
|
||||
typedef enum _LinphoneEcCalibratorStatus {
|
||||
LinphoneEcCalibratorInProgress, /**< The echo canceller calibration process is on going */
|
||||
LinphoneEcCalibratorDone, /**< The echo canceller calibration has been performed and produced an echo delay measure */
|
||||
LinphoneEcCalibratorFailed, /**< The echo canceller calibration process has failed */
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ package org.linphone.core;
|
|||
public class LinphonePlayerImpl implements LinphonePlayer {
|
||||
private long nativePtr = 0;
|
||||
|
||||
private native void init(long nativePtr);
|
||||
LinphonePlayerImpl(long nativePtr) {
|
||||
this.nativePtr = nativePtr;
|
||||
init(nativePtr);
|
||||
}
|
||||
|
||||
private native int open(long nativePtr, String filename);
|
||||
|
|
|
|||
26
src/cpim/cpim.h
Normal file
26
src/cpim/cpim.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* cpim.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_H_
|
||||
#define _CPIM_H_
|
||||
|
||||
#include "message/cpim-message.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#endif // ifndef _CPIM_H_
|
||||
105
src/cpim/header/cpim-core-headers.cpp
Normal file
105
src/cpim/header/cpim-core-headers.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* cpim-core-headers.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpim-header-p.h"
|
||||
#include "cpim/parser/cpim-parser.h"
|
||||
|
||||
#include "cpim-core-headers.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Cpim::CoreHeader::CoreHeader () : Header(*new HeaderPrivate) {}
|
||||
|
||||
Cpim::CoreHeader::CoreHeader (HeaderPrivate &p) : Header(p) {}
|
||||
|
||||
Cpim::CoreHeader::~CoreHeader () {}
|
||||
|
||||
bool Cpim::CoreHeader::isValid () const {
|
||||
return !getValue().empty();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define MAKE_CORE_HEADER_IMPL(CLASS_PREFIX) \
|
||||
bool Cpim::CLASS_PREFIX ## Header::setValue(const string &value) { \
|
||||
return Parser::getInstance()->coreHeaderIsValid<CLASS_PREFIX ## Header>(value) && Header::setValue(value); \
|
||||
}
|
||||
|
||||
MAKE_CORE_HEADER_IMPL(From);
|
||||
MAKE_CORE_HEADER_IMPL(To);
|
||||
MAKE_CORE_HEADER_IMPL(Cc);
|
||||
MAKE_CORE_HEADER_IMPL(DateTime);
|
||||
|
||||
MAKE_CORE_HEADER_IMPL(Ns);
|
||||
MAKE_CORE_HEADER_IMPL(Require);
|
||||
|
||||
#undef MAKE_CORE_HEADER_IMPL
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Cpim::CoreHeader::force (const std::string &value) {
|
||||
Header::setValue(value);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Cpim::SubjectHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
string language;
|
||||
};
|
||||
|
||||
Cpim::SubjectHeader::SubjectHeader () : CoreHeader(*new SubjectHeaderPrivate) {}
|
||||
|
||||
bool Cpim::SubjectHeader::setValue (const string &value) {
|
||||
return Parser::getInstance()->coreHeaderIsValid<SubjectHeader>(value) && Header::setValue(value);
|
||||
}
|
||||
|
||||
string Cpim::SubjectHeader::getLanguage () const {
|
||||
L_D(const SubjectHeader);
|
||||
return d->language;
|
||||
}
|
||||
|
||||
bool Cpim::SubjectHeader::setLanguage (const string &language) {
|
||||
if (!language.empty() && !Parser::getInstance()->subjectHeaderLanguageIsValid(language))
|
||||
return false;
|
||||
|
||||
L_D(SubjectHeader);
|
||||
d->language = language;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string Cpim::SubjectHeader::asString () const {
|
||||
L_D(const SubjectHeader);
|
||||
|
||||
string languageParam;
|
||||
if (!d->language.empty())
|
||||
languageParam = ";lang=" + d->language;
|
||||
|
||||
return getName() + ":" + languageParam + " " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
void Cpim::SubjectHeader::force (const string &value, const string &language) {
|
||||
L_D(SubjectHeader);
|
||||
CoreHeader::force(value);
|
||||
d->language = language;
|
||||
}
|
||||
111
src/cpim/header/cpim-core-headers.h
Normal file
111
src/cpim/header/cpim-core-headers.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* cpim-core-headers.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_CORE_HEADERS_H_
|
||||
#define _CPIM_CORE_HEADERS_H_
|
||||
|
||||
#include "cpim-header.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#define MAKE_CORE_HEADER(CLASS_PREFIX, NAME) \
|
||||
class CLASS_PREFIX ## Header : public CoreHeader { \
|
||||
public: \
|
||||
CLASS_PREFIX ## Header() = default; \
|
||||
inline std::string getName() const override { \
|
||||
return NAME; \
|
||||
} \
|
||||
bool setValue(const std::string &value) override; \
|
||||
private: \
|
||||
L_DISABLE_COPY(CLASS_PREFIX ## Header); \
|
||||
};
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class HeaderNode;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Generic core header.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class CoreHeader : public Header {
|
||||
friend class HeaderNode;
|
||||
|
||||
public:
|
||||
CoreHeader ();
|
||||
|
||||
virtual ~CoreHeader () = 0;
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
protected:
|
||||
explicit CoreHeader (HeaderPrivate &p);
|
||||
|
||||
void force (const std::string &value);
|
||||
|
||||
private:
|
||||
L_DISABLE_COPY(CoreHeader);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Core headers.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
MAKE_CORE_HEADER(From, "From");
|
||||
MAKE_CORE_HEADER(To, "To");
|
||||
MAKE_CORE_HEADER(Cc, "cc");
|
||||
MAKE_CORE_HEADER(DateTime, "DateTime");
|
||||
MAKE_CORE_HEADER(Ns, "NS");
|
||||
MAKE_CORE_HEADER(Require, "Require");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Specific Subject declaration.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class SubjectHeaderPrivate;
|
||||
|
||||
class SubjectHeader : public CoreHeader {
|
||||
friend class HeaderNode;
|
||||
|
||||
public:
|
||||
SubjectHeader ();
|
||||
|
||||
inline std::string getName () const override {
|
||||
return "Subject";
|
||||
}
|
||||
|
||||
bool setValue (const std::string &value) override;
|
||||
|
||||
std::string getLanguage () const;
|
||||
bool setLanguage (const std::string &language);
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
protected:
|
||||
void force (const std::string &value, const std::string &language);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(SubjectHeader);
|
||||
L_DISABLE_COPY(SubjectHeader);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#undef MAKE_CORE_HEADER
|
||||
|
||||
#endif // ifndef _CPIM_CORE_HEADERS_H_
|
||||
117
src/cpim/header/cpim-generic-header.cpp
Normal file
117
src/cpim/header/cpim-generic-header.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* cpim-generic-header.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "cpim-header-p.h"
|
||||
#include "cpim/parser/cpim-parser.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "cpim-generic-header.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class Cpim::GenericHeaderPrivate : public HeaderPrivate {
|
||||
public:
|
||||
string name;
|
||||
shared_ptr<list<pair<string, string> > > parameters = make_shared<list<pair<string, string> > >();
|
||||
};
|
||||
|
||||
Cpim::GenericHeader::GenericHeader () : Header(*new GenericHeaderPrivate) {}
|
||||
|
||||
string Cpim::GenericHeader::getName () const {
|
||||
L_D(const GenericHeader);
|
||||
return d->name;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::setName (const string &name) {
|
||||
L_D(GenericHeader);
|
||||
|
||||
static const set<string> reserved = {
|
||||
"From", "To", "cc", "DateTime", "Subject", "NS", "Require"
|
||||
};
|
||||
|
||||
if (
|
||||
reserved.find(name) != reserved.end() ||
|
||||
!Parser::getInstance()->headerNameIsValid(name)
|
||||
)
|
||||
return false;
|
||||
|
||||
d->name = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::setValue (const string &value) {
|
||||
return Parser::getInstance()->headerValueIsValid(value) && Header::setValue(value);
|
||||
}
|
||||
|
||||
Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const {
|
||||
L_D(const GenericHeader);
|
||||
return d->parameters;
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::addParameter (const string &key, const string &value) {
|
||||
L_D(GenericHeader);
|
||||
|
||||
if (!Parser::getInstance()->headerParameterIsValid(key + "=" + value))
|
||||
return false;
|
||||
|
||||
d->parameters->push_back(make_pair(key, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cpim::GenericHeader::removeParameter (const string &key, const string &value) {
|
||||
L_D(GenericHeader);
|
||||
d->parameters->remove(make_pair(key, value));
|
||||
}
|
||||
|
||||
bool Cpim::GenericHeader::isValid () const {
|
||||
L_D(const GenericHeader);
|
||||
return !d->name.empty() && !getValue().empty();
|
||||
}
|
||||
|
||||
string Cpim::GenericHeader::asString () const {
|
||||
L_D(const GenericHeader);
|
||||
|
||||
string parameters;
|
||||
for (const auto ¶meter : *d->parameters)
|
||||
parameters += ";" + parameter.first + "=" + parameter.second;
|
||||
|
||||
return d->name + ":" + parameters + " " + getValue() + "\r\n";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Cpim::GenericHeader::force (const string &name, const string &value, const string ¶meters) {
|
||||
L_D(GenericHeader);
|
||||
|
||||
// Set name/value.
|
||||
d->name = name;
|
||||
Header::setValue(value);
|
||||
|
||||
// Parse and build parameters list.
|
||||
for (const auto ¶meter : Utils::split(parameters, ';')) {
|
||||
size_t equalIndex = parameter.find('=');
|
||||
if (equalIndex != string::npos)
|
||||
d->parameters->push_back(make_pair(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1)));
|
||||
}
|
||||
}
|
||||
65
src/cpim/header/cpim-generic-header.h
Normal file
65
src/cpim/header/cpim-generic-header.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* cpim-generic-header.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_GENERIC_HEADER_H_
|
||||
#define _CPIM_GENERIC_HEADER_H_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "cpim-header.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class GenericHeaderPrivate;
|
||||
class HeaderNode;
|
||||
|
||||
class GenericHeader : public Header {
|
||||
friend class HeaderNode;
|
||||
|
||||
public:
|
||||
GenericHeader ();
|
||||
|
||||
std::string getName () const override;
|
||||
bool setName (const std::string &name);
|
||||
|
||||
bool setValue (const std::string &value) override;
|
||||
|
||||
typedef std::shared_ptr<const std::list<std::pair<std::string, std::string> > > ParameterList;
|
||||
|
||||
ParameterList getParameters () const;
|
||||
bool addParameter (const std::string &key, const std::string &value);
|
||||
void removeParameter (const std::string &key, const std::string &value);
|
||||
|
||||
bool isValid () const override;
|
||||
|
||||
std::string asString () const override;
|
||||
|
||||
protected:
|
||||
void force (const std::string &name, const std::string &value, const std::string ¶meters);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(GenericHeader);
|
||||
L_DISABLE_COPY(GenericHeader);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_GENERIC_HEADER_H_
|
||||
40
src/cpim/header/cpim-header-p.h
Normal file
40
src/cpim/header/cpim-header-p.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* cpim-header-p.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_HEADER_P_H_
|
||||
#define _CPIM_HEADER_P_H_
|
||||
|
||||
#include "cpim-header.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class HeaderPrivate : public ObjectPrivate {
|
||||
public:
|
||||
virtual ~HeaderPrivate () = default;
|
||||
|
||||
private:
|
||||
std::string value;
|
||||
|
||||
L_DECLARE_PUBLIC(Header);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_HEADER_P_H_
|
||||
45
src/cpim/header/cpim-header.cpp
Normal file
45
src/cpim/header/cpim-header.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* cpim-header.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpim-header-p.h"
|
||||
|
||||
#include "cpim-header.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Cpim::Header::Header (HeaderPrivate &p) : Object(p) {}
|
||||
|
||||
string Cpim::Header::getValue () const {
|
||||
L_D(const Header);
|
||||
return d->value;
|
||||
}
|
||||
|
||||
bool Cpim::Header::setValue (const string &value) {
|
||||
L_D(Header);
|
||||
d->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
string Cpim::Header::asString () const {
|
||||
L_D(const Header);
|
||||
return getName() + ": " + d->value + "\r\n";
|
||||
}
|
||||
55
src/cpim/header/cpim-header.h
Normal file
55
src/cpim/header/cpim-header.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* cpim-header.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_HEADER_H_
|
||||
#define _CPIM_HEADER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "object/object.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class HeaderPrivate;
|
||||
|
||||
class Header : public Object {
|
||||
public:
|
||||
virtual ~Header () = default;
|
||||
|
||||
virtual std::string getName () const = 0;
|
||||
|
||||
std::string getValue () const;
|
||||
virtual bool setValue (const std::string &value);
|
||||
|
||||
virtual bool isValid () const = 0;
|
||||
|
||||
virtual std::string asString () const;
|
||||
|
||||
protected:
|
||||
explicit Header (HeaderPrivate &p);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(Header);
|
||||
L_DISABLE_COPY(Header);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_HEADER_H_
|
||||
140
src/cpim/message/cpim-message.cpp
Normal file
140
src/cpim/message/cpim-message.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* cpim-message.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "cpim/parser/cpim-parser.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "cpim-message.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class Cpim::MessagePrivate : public ObjectPrivate {
|
||||
public:
|
||||
typedef list<shared_ptr<const Header> > PrivHeaderList;
|
||||
|
||||
shared_ptr<PrivHeaderList> cpimHeaders = make_shared<PrivHeaderList>();
|
||||
shared_ptr<PrivHeaderList> messageHeaders = make_shared<PrivHeaderList>();
|
||||
string content;
|
||||
};
|
||||
|
||||
Cpim::Message::Message () : Object(*new MessagePrivate) {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Cpim::Message::HeaderList Cpim::Message::getCpimHeaders () const {
|
||||
L_D(const Message);
|
||||
return d->cpimHeaders;
|
||||
}
|
||||
|
||||
bool Cpim::Message::addCpimHeader (const Header &cpimHeader) {
|
||||
L_D(Message);
|
||||
|
||||
if (!cpimHeader.isValid())
|
||||
return false;
|
||||
|
||||
d->cpimHeaders->push_back(Parser::getInstance()->cloneHeader(cpimHeader));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cpim::Message::removeCpimHeader (const Header &cpimHeader) {
|
||||
L_D(Message);
|
||||
d->cpimHeaders->remove_if([&cpimHeader](const shared_ptr<const Header> &header) {
|
||||
return cpimHeader.getName() == header->getName() && cpimHeader.getValue() == header->getValue();
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Cpim::Message::HeaderList Cpim::Message::getMessageHeaders () const {
|
||||
L_D(const Message);
|
||||
return d->messageHeaders;
|
||||
}
|
||||
|
||||
bool Cpim::Message::addMessageHeader (const Header &messageHeader) {
|
||||
L_D(Message);
|
||||
|
||||
if (!messageHeader.isValid())
|
||||
return false;
|
||||
|
||||
d->messageHeaders->push_back(Parser::getInstance()->cloneHeader(messageHeader));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cpim::Message::removeMessageHeader (const Header &messageHeader) {
|
||||
L_D(Message);
|
||||
d->messageHeaders->remove_if([&messageHeader](const shared_ptr<const Header> &header) {
|
||||
return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue();
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string Cpim::Message::getContent () const {
|
||||
L_D(const Message);
|
||||
return d->content;
|
||||
}
|
||||
|
||||
bool Cpim::Message::setContent (const string &content) {
|
||||
L_D(Message);
|
||||
d->content = content;
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Cpim::Message::isValid () const {
|
||||
L_D(const Message);
|
||||
|
||||
return find_if(d->cpimHeaders->cbegin(), d->cpimHeaders->cend(),
|
||||
[](const shared_ptr<const Header> &header) {
|
||||
return Utils::iequals(header->getName(), "content-type") && header->getValue() == "Message/CPIM";
|
||||
}) != d->cpimHeaders->cend();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string Cpim::Message::asString () const {
|
||||
L_D(const Message);
|
||||
|
||||
string output;
|
||||
for (const auto &cpimHeader : *d->cpimHeaders)
|
||||
output += cpimHeader->asString();
|
||||
|
||||
output += "\r\n";
|
||||
|
||||
for (const auto &messageHeader : *d->messageHeaders)
|
||||
output += messageHeader->asString();
|
||||
|
||||
output += "\r\n";
|
||||
output += ""; // TODO: Headers MIME.
|
||||
output += getContent();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
shared_ptr<const Cpim::Message> Cpim::Message::createFromString (const string &str) {
|
||||
return Parser::getInstance()->parseMessage(str);
|
||||
}
|
||||
61
src/cpim/message/cpim-message.h
Normal file
61
src/cpim/message/cpim-message.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* cpim-message.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_MESSAGE_H_
|
||||
#define _CPIM_MESSAGE_H_
|
||||
|
||||
#include "cpim/header/cpim-core-headers.h"
|
||||
#include "cpim/header/cpim-generic-header.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class MessagePrivate;
|
||||
|
||||
class Message : public Object {
|
||||
public:
|
||||
Message ();
|
||||
|
||||
typedef std::shared_ptr<std::list<std::shared_ptr<const Cpim::Header> > > HeaderList;
|
||||
|
||||
HeaderList getCpimHeaders () const;
|
||||
bool addCpimHeader (const Header &cpimHeader);
|
||||
void removeCpimHeader (const Header &cpimHeader);
|
||||
|
||||
HeaderList getMessageHeaders () const;
|
||||
bool addMessageHeader (const Header &messageHeader);
|
||||
void removeMessageHeader (const Header &messageHeader);
|
||||
|
||||
std::string getContent () const;
|
||||
bool setContent (const std::string &content);
|
||||
|
||||
bool isValid () const;
|
||||
|
||||
std::string asString () const;
|
||||
|
||||
static std::shared_ptr<const Message> createFromString (const std::string &str);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(Message);
|
||||
L_DISABLE_COPY(Message);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_MESSAGE_H_
|
||||
207
src/cpim/parser/cpim-grammar.cpp
Normal file
207
src/cpim/parser/cpim-grammar.cpp
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* cpim-grammar.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpim-grammar.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
static const char *grammar =
|
||||
// See: https://tools.ietf.org/html/rfc3862
|
||||
R"==GRAMMAR==(
|
||||
Message = Headers CRLF Headers CRLF
|
||||
|
||||
Headers = *Header
|
||||
Header = Header-name ":" Header-parameters SP Header-value CRLF
|
||||
|
||||
Header-name = [ Name-prefix "." ] Name
|
||||
Name-prefix = Name
|
||||
|
||||
Header-parameters = *( ";" Parameter )
|
||||
|
||||
Parameter = Lang-param / Ext-param
|
||||
Lang-param = "lang=" Language-tag
|
||||
Ext-param = Param-name "=" Param-value
|
||||
Param-name = Name
|
||||
Param-value = Token / Number / String
|
||||
|
||||
Header-value = *HEADERCHAR
|
||||
|
||||
From-header = %d70.114.111.109 ": " From-header-value
|
||||
From-header-value = [ Formal-name ] "<" URI ">"
|
||||
|
||||
To-header = %d84.111 ": " To-header-value
|
||||
To-header-value = [ Formal-name ] "<" URI ">"
|
||||
|
||||
DateTime-header = %d68.97.116.101.84.105.109.101 ": " DateTime-header-value
|
||||
DateTime-header-value = date-time
|
||||
|
||||
cc-header = %d99.99 ": " cc-header-value
|
||||
cc-header-value = [ Formal-name ] "<" URI ">"
|
||||
|
||||
Subject-header = %d83.117.98.106.101.99.116 ":" Subject-header-value
|
||||
Subject-header-value = [ ";" Lang-param ] SP *HEADERCHAR
|
||||
|
||||
NS-header = %d78.83 ": " NS-header-value
|
||||
NS-header-value = [ Name-prefix SP ] "<" URI ">"
|
||||
|
||||
Require-header = %d82.101.113.117.105.114.101 ": " Require-header-value
|
||||
Require-header-value = Header-name *( "," Header-name )
|
||||
|
||||
Name = 1*NAMECHAR
|
||||
Token = 1*TOKENCHAR
|
||||
Number = 1*DIGIT
|
||||
String = DQUOTE *( Str-char / Escape ) DQUOTE
|
||||
Str-char = %x20-21 / %x23-5B / %x5D-7E / UCS-high
|
||||
Escape = "\" ( "u" 4(HEXDIG) / "b" / "t" / "n" / "r" / DQUOTE / "'" / "\" )
|
||||
|
||||
Formal-name = 1*( Token SP ) / String
|
||||
|
||||
HEADERCHAR = UCS-no-CTL / Escape
|
||||
|
||||
NAMECHAR = %x21 / %x23-27 / %x2a-2b / %x2d / %x5e-60
|
||||
/ %x7c / %x7e / ALPHA / DIGIT
|
||||
|
||||
TOKENCHAR = NAMECHAR / "." / UCS-high
|
||||
|
||||
UCS-no-CTL = UTF8-no-CTL
|
||||
UCS-high = UTF8-multi
|
||||
UTF8-no-CTL = %x20-7e / UTF8-multi
|
||||
UTF8-multi = %xC0-DF %x80-BF
|
||||
/ %xE0-EF %x80-BF %x80-BF
|
||||
/ %xF0-F7 %x80-BF %x80-BF %x80-BF
|
||||
/ %xF8-FB %x80-BF %x80-BF %x80-BF %x80-BF
|
||||
/ %xFC-FD %x80-BF %x80-BF %x80-BF %x80-BF %x80-BF
|
||||
)==GRAMMAR=="
|
||||
|
||||
// See: https://tools.ietf.org/html/rfc2396
|
||||
R"==GRAMMAR==(
|
||||
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
|
||||
hier-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-rootless
|
||||
/ path-empty
|
||||
|
||||
URI-reference = URI / relative-ref
|
||||
|
||||
absolute-URI = scheme ":" hier-part [ "?" query ]
|
||||
|
||||
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
||||
|
||||
relative-part = "//" authority path-abempty
|
||||
/ path-absolute
|
||||
/ path-noscheme
|
||||
/ path-empty
|
||||
|
||||
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
|
||||
authority = [ userinfo "@" ] host [ ":" port ]
|
||||
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
|
||||
host = IP-literal / IPv4address / reg-name
|
||||
port = *DIGIT
|
||||
|
||||
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
|
||||
|
||||
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
|
||||
|
||||
IPv6address = 6( h16 ":" ) ls32
|
||||
/ "::" 5( h16 ":" ) ls32
|
||||
/ [ h16 ] "::" 4( h16 ":" ) ls32
|
||||
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
||||
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
||||
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
||||
/ [ *4( h16 ":" ) h16 ] "::" ls32
|
||||
/ [ *5( h16 ":" ) h16 ] "::" h16
|
||||
/ [ *6( h16 ":" ) h16 ] "::"
|
||||
|
||||
h16 = 1*4HEXDIG
|
||||
ls32 = ( h16 ":" h16 ) / IPv4address
|
||||
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
|
||||
dec-octet = DIGIT
|
||||
/ %x31-39 DIGIT
|
||||
/ "1" 2DIGIT
|
||||
/ "2" %x30-34 DIGIT
|
||||
/ "25" %x30-35
|
||||
|
||||
reg-name = *( unreserved / pct-encoded / sub-delims )
|
||||
|
||||
path = path-abempty
|
||||
/ path-absolute
|
||||
/ path-noscheme
|
||||
/ path-rootless
|
||||
/ path-empty
|
||||
|
||||
path-abempty = *( "/" segment )
|
||||
path-absolute = "/" [ segment-nz *( "/" segment ) ]
|
||||
path-noscheme = segment-nz-nc *( "/" segment )
|
||||
path-rootless = segment-nz *( "/" segment )
|
||||
path-empty = [pchar]
|
||||
|
||||
segment = *pchar
|
||||
segment-nz = 1*pchar
|
||||
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
|
||||
|
||||
pchar = unreserved / pct-encoded / sub-delims / ":" / "@" / "\,"
|
||||
|
||||
query = *( pchar / "/" / "?" )
|
||||
|
||||
fragment = *( pchar / "/" / "?" )
|
||||
|
||||
pct-encoded = "%" HEXDIG HEXDIG
|
||||
|
||||
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
reserved = gen-delims / sub-delims
|
||||
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
/ "*" / "+" / "," / ";" / "="
|
||||
)==GRAMMAR=="
|
||||
|
||||
// See: https://tools.ietf.org/html/rfc3066
|
||||
R"==GRAMMAR==(
|
||||
Language-Tag = Primary-subtag *( "-" Subtag )
|
||||
Primary-subtag = 1*8ALPHA
|
||||
Subtag = 1*8(ALPHA / DIGIT)
|
||||
)==GRAMMAR=="
|
||||
|
||||
// See: https://tools.ietf.org/html/rfc3339
|
||||
R"==GRAMMAR==(
|
||||
date-fullyear = 4DIGIT
|
||||
date-month = 2DIGIT
|
||||
date-mday = 2DIGIT
|
||||
|
||||
time-hour = 2DIGIT
|
||||
time-minute = 2DIGIT
|
||||
time-second = 2DIGIT
|
||||
|
||||
time-secfrac = "." 1*DIGIT
|
||||
time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
|
||||
time-offset = "Z" / time-numoffset
|
||||
|
||||
partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ]
|
||||
|
||||
full-date = date-fullyear "-" date-month "-" date-mday
|
||||
full-time = partial-time time-offset
|
||||
|
||||
date-time = full-date "T" full-time
|
||||
)==GRAMMAR==";
|
||||
}
|
||||
|
||||
const char *LinphonePrivate::Cpim::getGrammar () {
|
||||
return grammar;
|
||||
}
|
||||
30
src/cpim/parser/cpim-grammar.h
Normal file
30
src/cpim/parser/cpim-grammar.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* cpim-grammar.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_GRAMMAR_H_
|
||||
#define _CPIM_GRAMMAR_H_
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
const char *getGrammar ();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_GRAMMAR_H_
|
||||
413
src/cpim/parser/cpim-parser.cpp
Normal file
413
src/cpim/parser/cpim-parser.cpp
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* cpim-parser.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <belr/abnf.h>
|
||||
#include <belr/grammarbuilder.h>
|
||||
|
||||
#include "linphone/core.h"
|
||||
|
||||
#include "cpim-grammar.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "cpim-parser.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class Node {
|
||||
public:
|
||||
virtual ~Node () = default;
|
||||
};
|
||||
|
||||
class HeaderNode : public Node {
|
||||
public:
|
||||
HeaderNode () = default;
|
||||
|
||||
explicit HeaderNode (const Header &header) {
|
||||
mName = header.getName();
|
||||
mValue = header.getValue();
|
||||
|
||||
// Generic header.
|
||||
const GenericHeader *genericHeader = dynamic_cast<const GenericHeader *>(&header);
|
||||
if (genericHeader) {
|
||||
for (const auto ¶meter : *genericHeader->getParameters())
|
||||
mParameters += ";" + parameter.first + "=" + parameter.second;
|
||||
return;
|
||||
}
|
||||
|
||||
// Subject header.
|
||||
const SubjectHeader *subjectHeader = dynamic_cast<const SubjectHeader *>(&header);
|
||||
if (subjectHeader) {
|
||||
const string language = subjectHeader->getLanguage();
|
||||
if (!language.empty())
|
||||
mParameters = ";lang=" + language;
|
||||
}
|
||||
}
|
||||
|
||||
string getName () const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
void setName (const string &name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
string getParameters () const {
|
||||
return mParameters;
|
||||
}
|
||||
|
||||
void setParameters (const string ¶meters) {
|
||||
mParameters = parameters;
|
||||
}
|
||||
|
||||
string getValue () const {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void setValue (const string &value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
shared_ptr<Header> createHeader (bool force) const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
shared_ptr<Header> createCoreHeader (bool force) const {
|
||||
shared_ptr<T> header = make_shared<T>();
|
||||
if (force)
|
||||
header->force(mValue);
|
||||
else if (!header->setValue(mValue)) {
|
||||
ms_fatal("Unable to set value on core header: `%s` => `%s`.", mName.c_str(), mValue.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
string mValue;
|
||||
string mName;
|
||||
string mParameters;
|
||||
};
|
||||
|
||||
template<>
|
||||
shared_ptr<Header> HeaderNode::createCoreHeader<SubjectHeader>(bool force) const {
|
||||
shared_ptr<SubjectHeader> header = make_shared<SubjectHeader>();
|
||||
const string language = mParameters.length() >= 6 ? mParameters.substr(6) : "";
|
||||
|
||||
if (force)
|
||||
header->force(mValue, language);
|
||||
else if (!header->setValue(mValue) || (!language.empty() && !header->setLanguage(language))) {
|
||||
ms_fatal("Unable to set value on subject header: `%s` => `%s`, `%s`.", mName.c_str(), mValue.c_str(), language.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
shared_ptr<Header> HeaderNode::createHeader (bool force = false) const {
|
||||
static const unordered_map<string, shared_ptr<Header>(HeaderNode::*)(bool)const> reservedHandlers = {
|
||||
{ "From", &HeaderNode::createCoreHeader<FromHeader> },
|
||||
{ "To", &HeaderNode::createCoreHeader<ToHeader> },
|
||||
{ "cc", &HeaderNode::createCoreHeader<CcHeader> },
|
||||
{ "DateTime", &HeaderNode::createCoreHeader<DateTimeHeader> },
|
||||
{ "Subject", &HeaderNode::createCoreHeader<SubjectHeader> },
|
||||
{ "NS", &HeaderNode::createCoreHeader<NsHeader> },
|
||||
{ "Require", &HeaderNode::createCoreHeader<RequireHeader> }
|
||||
};
|
||||
|
||||
// Core Header.
|
||||
const auto it = reservedHandlers.find(mName);
|
||||
if (it != reservedHandlers.cend())
|
||||
return (this->*it->second)(force);
|
||||
|
||||
// Generic Header
|
||||
shared_ptr<GenericHeader> genericHeader = make_shared<GenericHeader>();
|
||||
genericHeader->force(mName, mValue, mParameters);
|
||||
return genericHeader;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class ListHeaderNode :
|
||||
public Node,
|
||||
public list<shared_ptr<HeaderNode> > {};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class MessageNode : public Node {
|
||||
public:
|
||||
void addHeaders (const shared_ptr<ListHeaderNode> &headers) {
|
||||
mHeaders->push_back(headers);
|
||||
}
|
||||
|
||||
// Warning: Call this function one time!
|
||||
shared_ptr<Message> createMessage () const {
|
||||
size_t size = mHeaders->size();
|
||||
if (size != 2) {
|
||||
ms_fatal("Bad headers lists size.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const shared_ptr<Message> message = make_shared<Message>();
|
||||
const shared_ptr<ListHeaderNode> cpimHeaders = mHeaders->front();
|
||||
|
||||
if (find_if(cpimHeaders->cbegin(), cpimHeaders->cend(),
|
||||
[](const shared_ptr<const HeaderNode> &headerNode) {
|
||||
return Utils::iequals(headerNode->getName(), "content-type") && headerNode->getValue() == "Message/CPIM";
|
||||
}) == cpimHeaders->cend()) {
|
||||
ms_fatal("No MIME `Content-Type` found!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add MIME headers.
|
||||
for (const auto &headerNode : *cpimHeaders) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addCpimHeader(*header))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add message headers.
|
||||
for (const auto &headerNode : *mHeaders->back()) {
|
||||
const shared_ptr<const Header> header = headerNode->createHeader();
|
||||
if (!header || !message->addMessageHeader(*header))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<list<shared_ptr<ListHeaderNode> > > mHeaders = make_shared<list<shared_ptr<ListHeaderNode> > >();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Cpim::ParserPrivate : public ObjectPrivate {
|
||||
public:
|
||||
shared_ptr<belr::Grammar> grammar;
|
||||
};
|
||||
|
||||
Cpim::Parser::Parser () : Singleton(*new ParserPrivate) {
|
||||
L_D(Parser);
|
||||
|
||||
belr::ABNFGrammarBuilder builder;
|
||||
|
||||
d->grammar = builder.createFromAbnf(getGrammar(), make_shared<belr::CoreRules>());
|
||||
if (!d->grammar)
|
||||
ms_fatal("Unable to build CPIM grammar.");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
|
||||
L_D(Parser);
|
||||
|
||||
typedef void (list<shared_ptr<HeaderNode> >::*pushPtr)(const shared_ptr<HeaderNode> &value);
|
||||
|
||||
belr::Parser<shared_ptr<Node> > parser(d->grammar);
|
||||
parser.setHandler(
|
||||
"Message", belr::make_fn(make_shared<MessageNode> )
|
||||
)->setCollector(
|
||||
"Headers", belr::make_sfn(&MessageNode::addHeaders)
|
||||
);
|
||||
|
||||
parser.setHandler(
|
||||
"Headers", belr::make_fn(make_shared<ListHeaderNode> )
|
||||
)->setCollector(
|
||||
"Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back))
|
||||
);
|
||||
|
||||
parser.setHandler(
|
||||
"Header", belr::make_fn(make_shared<HeaderNode> )
|
||||
)->setCollector(
|
||||
"Header-name", belr::make_sfn(&HeaderNode::setName)
|
||||
)->setCollector(
|
||||
"Header-value", belr::make_sfn(&HeaderNode::setValue)
|
||||
)->setCollector(
|
||||
"Header-parameters", belr::make_sfn(&HeaderNode::setParameters)
|
||||
);
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<Node> node = parser.parseInput("Message", input, &parsedSize);
|
||||
if (!node) {
|
||||
ms_fatal("Unable to parse message.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<MessageNode> messageNode = dynamic_pointer_cast<MessageNode>(node);
|
||||
if (!messageNode) {
|
||||
ms_fatal("Unable to cast belr result to message node.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<Message> message = messageNode->createMessage();
|
||||
if (message)
|
||||
message->setContent(input.substr(parsedSize));
|
||||
return message;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
shared_ptr<Cpim::Header> Cpim::Parser::cloneHeader (const Header &header) {
|
||||
return HeaderNode(header).createHeader(true);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class EmptyObject {};
|
||||
|
||||
inline bool headerIsValid (const shared_ptr<belr::Grammar> &grammar, const string &input) {
|
||||
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
|
||||
parser.setHandler(
|
||||
"Header", belr::make_fn(make_shared<EmptyObject> )
|
||||
);
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<EmptyObject> node = parser.parseInput("Header", input, &parsedSize);
|
||||
return node && parsedSize == input.length();
|
||||
}
|
||||
|
||||
bool Cpim::Parser::headerNameIsValid (const string &headerName) const {
|
||||
L_D(const Parser);
|
||||
return ::headerIsValid(d->grammar, headerName + ": value\r\n");
|
||||
}
|
||||
|
||||
bool Cpim::Parser::headerValueIsValid (const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::headerIsValid(d->grammar, "key: " + headerValue + "\r\n");
|
||||
}
|
||||
|
||||
bool Cpim::Parser::headerParameterIsValid (const std::string &headerParameter) const {
|
||||
L_D(const Parser);
|
||||
return ::headerIsValid(d->grammar, "key:;" + headerParameter + " value\r\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
inline bool coreHeaderIsValid (
|
||||
const shared_ptr<belr::Grammar> &grammar,
|
||||
const string &headerName,
|
||||
const string &headerValue,
|
||||
const string &headerParams = string()
|
||||
) {
|
||||
const string mainRule = headerName + "-header";
|
||||
|
||||
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
|
||||
parser.setHandler(
|
||||
mainRule, belr::make_fn(make_shared<EmptyObject> )
|
||||
);
|
||||
|
||||
const string input = headerName + ":" + headerParams + " " + headerValue;
|
||||
|
||||
size_t parsedSize;
|
||||
shared_ptr<EmptyObject> node = parser.parseInput(mainRule, input, &parsedSize);
|
||||
return node && parsedSize == input.length();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::FromHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "From", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::ToHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "To", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::CcHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "cc", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::DateTimeHeader>(const string &headerValue) const {
|
||||
static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
L_D(const Parser);
|
||||
if (!::coreHeaderIsValid(d->grammar, "DateTime", headerValue))
|
||||
return false;
|
||||
|
||||
// Check date.
|
||||
const int year = Utils::stoi(headerValue.substr(0, 4));
|
||||
const bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
|
||||
|
||||
const int month = Utils::stoi(headerValue.substr(5, 2));
|
||||
if (month < 1 || month > 12)
|
||||
return false;
|
||||
|
||||
const int day = Utils::stoi(headerValue.substr(8, 2));
|
||||
if (day < 1 || (month == 2 && isLeapYear ? day > 29 : day > daysInMonth[month - 1]))
|
||||
return false;
|
||||
|
||||
// Check time.
|
||||
if (
|
||||
Utils::stoi(headerValue.substr(11, 2)) > 24 ||
|
||||
Utils::stoi(headerValue.substr(14, 2)) > 59 ||
|
||||
Utils::stoi(headerValue.substr(17, 2)) > 60
|
||||
)
|
||||
return false;
|
||||
|
||||
// Check num offset.
|
||||
if (headerValue.back() != 'Z') {
|
||||
size_t length = headerValue.length();
|
||||
if (
|
||||
Utils::stoi(headerValue.substr(length - 5, 2)) > 24 ||
|
||||
Utils::stoi(headerValue.substr(length - 2, 2)) > 59
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::SubjectHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "Subject", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::NsHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "NS", headerValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Cpim::Parser::coreHeaderIsValid<Cpim::RequireHeader>(const string &headerValue) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "Require", headerValue);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Cpim::Parser::subjectHeaderLanguageIsValid (const string &language) const {
|
||||
L_D(const Parser);
|
||||
return ::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language);
|
||||
}
|
||||
82
src/cpim/parser/cpim-parser.h
Normal file
82
src/cpim/parser/cpim-parser.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* cpim-parser.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CPIM_PARSER_H_
|
||||
#define _CPIM_PARSER_H_
|
||||
|
||||
#include "cpim/message/cpim-message.h"
|
||||
#include "object/singleton.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Cpim {
|
||||
class ParserPrivate;
|
||||
|
||||
class Parser : public Singleton<Parser> {
|
||||
friend class Singleton<Parser>;
|
||||
|
||||
public:
|
||||
std::shared_ptr<Message> parseMessage (const std::string &input);
|
||||
|
||||
std::shared_ptr<Header> cloneHeader (const Header &header);
|
||||
|
||||
bool headerNameIsValid (const std::string &headerName) const;
|
||||
bool headerValueIsValid (const std::string &headerValue) const;
|
||||
bool headerParameterIsValid (const std::string &headerParameter) const;
|
||||
|
||||
template<typename>
|
||||
bool coreHeaderIsValid (const std::string &headerValue) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool subjectHeaderLanguageIsValid (const std::string &language) const;
|
||||
|
||||
private:
|
||||
Parser ();
|
||||
|
||||
L_DECLARE_PRIVATE(Parser);
|
||||
L_DISABLE_COPY(Parser);
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<FromHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<ToHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<CcHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<DateTimeHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<SubjectHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<NsHeader>(const std::string &headerValue) const;
|
||||
|
||||
template<>
|
||||
bool Parser::coreHeaderIsValid<RequireHeader>(const std::string &headerValue) const;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _CPIM_PARSER_H_
|
||||
|
|
@ -44,9 +44,8 @@ namespace LinphonePrivate {
|
|||
}
|
||||
|
||||
protected:
|
||||
explicit Object (ObjectPrivate *objectPrivate) : mPrivate(objectPrivate) {
|
||||
if (mPrivate)
|
||||
mPrivate->mPublic = this;
|
||||
explicit Object (ObjectPrivate &p) : mPrivate(&p) {
|
||||
mPrivate->mPublic = this;
|
||||
}
|
||||
|
||||
ObjectPrivate *mPrivate = nullptr;
|
||||
|
|
|
|||
|
|
@ -27,25 +27,25 @@ namespace LinphonePrivate {
|
|||
template<class T>
|
||||
class Singleton : public Object {
|
||||
public:
|
||||
static Singleton<T> *getInstance () {
|
||||
virtual ~Singleton () = default;
|
||||
|
||||
static T *getInstance () {
|
||||
if (!mInstance)
|
||||
mInstance = new Singleton<T>();
|
||||
mInstance = new T();
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
virtual ~Singleton () = default;
|
||||
|
||||
protected:
|
||||
explicit Singleton (ObjectPrivate *objectPrivate = nullptr) : Object(objectPrivate) {}
|
||||
explicit Singleton (ObjectPrivate &p) : Object(p) {}
|
||||
|
||||
private:
|
||||
static Singleton<T> *mInstance;
|
||||
static T *mInstance;
|
||||
|
||||
L_DISABLE_COPY(Singleton);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
Singleton<T> *Singleton<T>::mInstance = nullptr;
|
||||
T *Singleton<T>::mInstance = nullptr;
|
||||
}
|
||||
|
||||
#endif // ifndef _SINGLETON_H_
|
||||
|
|
|
|||
61
src/utils/utils.cpp
Normal file
61
src/utils/utils.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* utils.cpp
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
bool Utils::iequals (const string &a, const string &b) {
|
||||
size_t size = a.size();
|
||||
if (b.size() != size)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (tolower(a[i]) != tolower(b[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<string> Utils::split (const string &str, const string &delimiter) {
|
||||
vector<string> out;
|
||||
|
||||
size_t pos = 0, oldPos = 0;
|
||||
for (; (pos = str.find(delimiter, pos)) != string::npos; oldPos = pos + 1, pos = oldPos)
|
||||
out.push_back(str.substr(oldPos, pos - oldPos));
|
||||
out.push_back(str.substr(oldPos));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int Utils::stoi (const string &str, size_t *idx, int base) {
|
||||
char *p;
|
||||
int v = strtol(str.c_str(), &p, base);
|
||||
|
||||
if (idx)
|
||||
*idx = p - str.c_str();
|
||||
|
||||
return v;
|
||||
}
|
||||
41
src/utils/utils.h
Normal file
41
src/utils/utils.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* utils.h
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace LinphonePrivate {
|
||||
namespace Utils {
|
||||
bool iequals (const std::string &a, const std::string &b);
|
||||
|
||||
std::vector<std::string> split (const std::string &str, const std::string &delimiter);
|
||||
|
||||
inline std::vector<std::string> split (const std::string &str, char delimiter) {
|
||||
return split(str, std::string(1, delimiter));
|
||||
}
|
||||
|
||||
int stoi (const std::string &str, size_t *idx = 0, int base = 10);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef _UTILS_H_
|
||||
|
|
@ -194,6 +194,7 @@ set(SOURCE_FILES_C
|
|||
|
||||
set(SOURCE_FILES_CXX
|
||||
confeventpackage_tester.cpp
|
||||
cpim_tester.cpp
|
||||
)
|
||||
|
||||
set(SOURCE_FILES_OBJC )
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ struct _Account{
|
|||
int done;
|
||||
int created;
|
||||
char *phone_alias;
|
||||
char *uuid;
|
||||
};
|
||||
|
||||
typedef struct _Account Account;
|
||||
|
|
@ -49,6 +50,7 @@ static Account *account_new(LinphoneAddress *identity, const char *unique_id){
|
|||
};
|
||||
|
||||
void account_destroy(Account *obj){
|
||||
if (obj->uuid) bctbx_free(obj->uuid);
|
||||
linphone_address_unref(obj->identity);
|
||||
linphone_address_unref(obj->modified_identity);
|
||||
ms_free(obj->password);
|
||||
|
|
@ -198,7 +200,7 @@ void account_create_on_server(Account *account, const LinphoneProxyConfig *refcf
|
|||
ms_free(chatdb);
|
||||
}
|
||||
|
||||
static LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg,const char* phone_alias){
|
||||
static LinphoneAddress *account_manager_check_account(AccountManager *m, LinphoneProxyConfig *cfg, LinphoneCoreManager *cm){
|
||||
LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
|
||||
const char *identity=linphone_proxy_config_get_identity(cfg);
|
||||
LinphoneAddress *id_addr=linphone_address_new(identity);
|
||||
|
|
@ -209,6 +211,7 @@ static LinphoneAddress *account_manager_check_account(AccountManager *m, Linphon
|
|||
,NULL
|
||||
, linphone_address_get_username(id_addr)
|
||||
, linphone_address_get_domain(id_addr));
|
||||
const char *phone_alias = cm->phone_alias;
|
||||
|
||||
if (!account||(phone_alias&&(!account->phone_alias||strcmp(phone_alias,account->phone_alias)!=0))){
|
||||
if (account) {
|
||||
|
|
@ -229,6 +232,16 @@ static LinphoneAddress *account_manager_check_account(AccountManager *m, Linphon
|
|||
account_create_on_server(account,cfg,phone_alias);
|
||||
}
|
||||
|
||||
if (liblinphone_tester_keep_uuid) {
|
||||
/* create and/or set uuid */
|
||||
if (account->uuid == NULL) {
|
||||
char tmp[64];
|
||||
sal_create_uuid(cm->lc->sal, tmp, sizeof(tmp));
|
||||
account->uuid = bctbx_strdup(tmp);
|
||||
}
|
||||
sal_set_uuid(cm->lc->sal, account->uuid);
|
||||
}
|
||||
|
||||
/*remove previous auth info to avoid mismatching*/
|
||||
if (original_ai)
|
||||
linphone_core_remove_auth_info(lc,original_ai);
|
||||
|
|
@ -251,7 +264,7 @@ void linphone_core_manager_check_accounts(LinphoneCoreManager *m){
|
|||
if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
|
||||
for(it=linphone_core_get_proxy_config_list(m->lc);it!=NULL;it=it->next){
|
||||
LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)it->data;
|
||||
account_manager_check_account(am,cfg,m->phone_alias);
|
||||
account_manager_check_account(am,cfg,m);
|
||||
}
|
||||
if (!liblinphonetester_show_account_manager_logs) linphone_core_set_log_level_mask(logmask);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
bool_t is_remote_conf;
|
||||
bool_t focus_is_up = (focus && ((LinphoneConferenceServer *)focus)->reg_state == LinphoneRegistrationOk);
|
||||
bctbx_list_t* lcs=bctbx_list_append(NULL,marie->lc);
|
||||
|
||||
|
||||
lcs=bctbx_list_append(lcs,pauline->lc);
|
||||
lcs=bctbx_list_append(lcs,laure->lc);
|
||||
if (focus) lcs=bctbx_list_append(lcs,focus->lc);
|
||||
|
|
@ -263,7 +263,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
if(is_remote_conf) BC_ASSERT_PTR_NOT_NULL(focus);
|
||||
|
||||
if (!BC_ASSERT_TRUE(call(marie,pauline))) goto end;
|
||||
|
||||
|
||||
marie_call_pauline=linphone_core_get_current_call(marie->lc);
|
||||
pauline_called_by_marie=linphone_core_get_current_call(pauline->lc);
|
||||
BC_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie));
|
||||
|
|
@ -391,40 +391,40 @@ static void simple_conference_from_scratch(void){
|
|||
LinphoneCall *pauline_call, *laure_call;
|
||||
bctbx_list_t *participants = NULL;
|
||||
bctbx_list_t *lcs = NULL;
|
||||
|
||||
|
||||
lcs = bctbx_list_append(lcs, marie->lc);
|
||||
lcs = bctbx_list_append(lcs, pauline->lc);
|
||||
lcs = bctbx_list_append(lcs, laure->lc);
|
||||
|
||||
|
||||
/*marie creates the conference*/
|
||||
conf_params = linphone_core_create_conference_params(marie->lc);
|
||||
linphone_conference_params_enable_video(conf_params, FALSE);
|
||||
conf = linphone_core_create_conference_with_params(marie->lc, conf_params);
|
||||
linphone_conference_params_unref(conf_params);
|
||||
|
||||
|
||||
participants = bctbx_list_append(participants, pauline->identity);
|
||||
participants = bctbx_list_append(participants, laure->identity);
|
||||
|
||||
|
||||
linphone_conference_invite_participants(conf, participants, NULL);
|
||||
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,2,2000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallIncomingReceived,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,10000));
|
||||
|
||||
|
||||
pauline_call = linphone_core_get_current_call(pauline->lc);
|
||||
laure_call = linphone_core_get_current_call(laure->lc);
|
||||
|
||||
|
||||
BC_ASSERT_PTR_NOT_NULL(pauline_call);
|
||||
BC_ASSERT_PTR_NOT_NULL(laure_call);
|
||||
|
||||
|
||||
if (pauline_call && laure_call){
|
||||
const bctbx_list_t *marie_calls, *it;
|
||||
linphone_call_accept(pauline_call);
|
||||
linphone_call_accept(laure_call);
|
||||
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,2,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,2,3000));
|
||||
|
||||
|
||||
/*make sure that the two calls from Marie's standpoint are in conference*/
|
||||
marie_calls = linphone_core_get_calls(marie->lc);
|
||||
BC_ASSERT_EQUAL((int)bctbx_list_size(marie_calls), 2, int, "%i");
|
||||
|
|
@ -433,12 +433,12 @@ static void simple_conference_from_scratch(void){
|
|||
}
|
||||
/*wait a bit for the conference audio processing to run, despite we do not test it for the moment*/
|
||||
wait_for_list(lcs,NULL,0,5000);
|
||||
|
||||
|
||||
linphone_core_terminate_conference(marie->lc);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallReleased,2,1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallReleased,1,1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallReleased,1,1000));
|
||||
|
|
@ -447,7 +447,7 @@ static void simple_conference_from_scratch(void){
|
|||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(laure);
|
||||
|
||||
|
||||
bctbx_list_free(participants);
|
||||
bctbx_list_free(lcs);
|
||||
}
|
||||
|
|
@ -691,7 +691,7 @@ static void call_transfer_existing_call(bool_t outgoing_call) {
|
|||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
marie_call_laure=linphone_core_get_current_call(marie->lc);
|
||||
laure_called_by_marie=linphone_core_get_current_call(laure->lc);
|
||||
|
||||
|
|
|
|||
379
tester/cpim_tester.cpp
Normal file
379
tester/cpim_tester.cpp
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* liblinphone_tester - liblinphone test suite
|
||||
* Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpim/cpim.h"
|
||||
|
||||
#include "liblinphone_tester.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace LinphonePrivate;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static void parse_minimal_message (void) {
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"Content-Type: text/plain; charset=utf-8\r\n"
|
||||
"\r\n";
|
||||
|
||||
shared_ptr<const Cpim::Message> message = Cpim::Message::createFromString(str);
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(message)) return;
|
||||
|
||||
const string str2 = message->asString();
|
||||
BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str());
|
||||
}
|
||||
|
||||
static void set_generic_header_name (void) {
|
||||
const list<pair<string, bool> > entries = {
|
||||
{ "toto", true },
|
||||
{ "george.abitbol", true },
|
||||
{ "tata/titi", false },
|
||||
{ "hey ho", false },
|
||||
{ " fail", false },
|
||||
{ "fail2 ", false },
|
||||
|
||||
// Reserved.
|
||||
{ "From", false },
|
||||
{ "To", false },
|
||||
{ "cc", false },
|
||||
{ "DateTime", false },
|
||||
{ "Subject", false },
|
||||
{ "NS", false },
|
||||
{ "Require", false },
|
||||
|
||||
// Case sensitivity.
|
||||
{ "FROM", true },
|
||||
{ "to", true },
|
||||
{ "cC", true },
|
||||
{ "Datetime", true },
|
||||
{ "SuBject", true },
|
||||
{ "nS", true },
|
||||
{ "requirE", true }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
Cpim::GenericHeader genericHeader;
|
||||
|
||||
const bool result = genericHeader.setName(entry.first);
|
||||
BC_ASSERT_EQUAL(result, entry.second, bool, "%d");
|
||||
|
||||
const string name = genericHeader.getName();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), entry.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void set_generic_header_value (void) {
|
||||
const list<pair<string, bool> > entries = {
|
||||
{ "MyFeatures <mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "2000-12-13T13:40:00-08:00", true },
|
||||
{ "2000-12-13T13:40:00-08:00", true },
|
||||
{ "text/xml; charset=utf-8", true },
|
||||
{ "text/xml; charset=ut\r\nf-8", false }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
Cpim::GenericHeader genericHeader;
|
||||
|
||||
const bool result = genericHeader.setValue(entry.first);
|
||||
BC_ASSERT_EQUAL(result, entry.second, bool, "%d");
|
||||
|
||||
const string value = genericHeader.getValue();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), entry.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void check_core_header_names (void) {
|
||||
const list<pair<shared_ptr<Cpim::CoreHeader>, string> > entries = {
|
||||
{ make_shared<Cpim::FromHeader>(), "From" },
|
||||
{ make_shared<Cpim::ToHeader>(), "To" },
|
||||
{ make_shared<Cpim::CcHeader>(), "cc" },
|
||||
{ make_shared<Cpim::DateTimeHeader>(), "DateTime" },
|
||||
{ make_shared<Cpim::SubjectHeader>(), "Subject" },
|
||||
{ make_shared<Cpim::NsHeader>(), "NS" },
|
||||
{ make_shared<Cpim::RequireHeader>(), "Require" }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
const string name = entry.first->getName();
|
||||
BC_ASSERT_STRING_EQUAL(name.c_str(), entry.second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void set_core_header_values (void) {
|
||||
const list<pair<shared_ptr<Cpim::Header>, list<pair<string, bool> > > > entries = {
|
||||
{ make_shared<Cpim::FromHeader>(), {
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "<im:tigger>", true },
|
||||
{ "toto", false }
|
||||
} },
|
||||
{ make_shared<Cpim::ToHeader>(), {
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "toto", false },
|
||||
{ "<im:tigger>", true },
|
||||
{ "<im:tigger@100akerwood.com>", true }
|
||||
} },
|
||||
{ make_shared<Cpim::CcHeader>(), {
|
||||
{ "<im:tigger@100akerwood.com>", true },
|
||||
{ "<im:tigger@100akerwood.com", false },
|
||||
{ "Winnie the Pooh <im:pooh@100akerwood.com>", true },
|
||||
{ "<im:tigger>", true },
|
||||
{ "toto", false }
|
||||
} },
|
||||
{ make_shared<Cpim::DateTimeHeader>(), {
|
||||
{ "abcd", false },
|
||||
{ "1985-04-12T23:20:50.52Z", true },
|
||||
{ "1996-12-19T16:39:57-08:00", true },
|
||||
{ "1990-12-31T23:59:60Z", true },
|
||||
{ "1990-12-31T15:59:60-08:00", true },
|
||||
{ "2001-02-29T10:10:10Z", false },
|
||||
{ "2000-02-29T10:10:10Z", true },
|
||||
{ "1937-01-01T12:00:27.87+00:20", true },
|
||||
{ "1937-01-01T12:00:27.87Z", true },
|
||||
{ "1956", false }
|
||||
} },
|
||||
{ make_shared<Cpim::SubjectHeader>(), {
|
||||
{ "Eeyore's feeling very depressed today", true },
|
||||
{ "🤣", true },
|
||||
{ "hello", true }
|
||||
} },
|
||||
{ make_shared<Cpim::NsHeader>(), {
|
||||
{ "MyAlias <mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "What is this? - Barry Burton", false },
|
||||
{ "<mid:MessageFeatures@id.foo.com>", true },
|
||||
{ "<mid:MessageFeatures@id.foo.com", false }
|
||||
} },
|
||||
{ make_shared<Cpim::RequireHeader>(), {
|
||||
{ "MyAlias.VitalHeader", true },
|
||||
{ "MyAlias.VitalHeader,Test", true },
|
||||
{ "MyAlias.VitalHeader,🤣", false }
|
||||
} }
|
||||
};
|
||||
|
||||
for (const auto &entry : entries) {
|
||||
const shared_ptr<Cpim::Header> header = entry.first;
|
||||
string previousValue;
|
||||
|
||||
for (const auto &test : entry.second) {
|
||||
const bool result = header->setValue(test.first);
|
||||
BC_ASSERT_EQUAL(result, test.second, bool, "%d");
|
||||
|
||||
const string value = header->getValue();
|
||||
|
||||
if (result)
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), test.first.c_str());
|
||||
else
|
||||
BC_ASSERT_STRING_EQUAL(value.c_str(), previousValue.c_str());
|
||||
|
||||
previousValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_subject_header_language (void) {
|
||||
Cpim::SubjectHeader subjectHeader;
|
||||
|
||||
// Check for not defined language.
|
||||
{
|
||||
const string language = subjectHeader.getLanguage();
|
||||
BC_ASSERT_STRING_EQUAL(language.c_str(), "");
|
||||
}
|
||||
|
||||
// Set valid language.
|
||||
{
|
||||
const string languageToSet = "fr";
|
||||
|
||||
BC_ASSERT_TRUE(subjectHeader.setLanguage(languageToSet));
|
||||
BC_ASSERT_TRUE(languageToSet == subjectHeader.getLanguage());
|
||||
|
||||
const string str = subjectHeader.asString();
|
||||
const string expected = "Subject:;lang=" + languageToSet + " \r\n";
|
||||
BC_ASSERT_STRING_EQUAL(str.c_str(), expected.c_str());
|
||||
}
|
||||
|
||||
// Set invalid language.
|
||||
{
|
||||
const string languageToSet = "fr--";
|
||||
BC_ASSERT_FALSE(subjectHeader.setLanguage(languageToSet));
|
||||
BC_ASSERT_FALSE(languageToSet == subjectHeader.getLanguage());
|
||||
BC_ASSERT_FALSE(subjectHeader.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_rfc_example (void) {
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
"To: Depressed Donkey <im:eeyore@100akerwood.com>\r\n"
|
||||
"DateTime: 2000-12-13T13:40:00-08:00\r\n"
|
||||
"Subject: the weather will be fine today\r\n"
|
||||
"Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
|
||||
"NS: MyFeatures <mid:MessageFeatures@id.foo.com>\r\n"
|
||||
"Require: MyFeatures.VitalMessageOption\r\n"
|
||||
"MyFeatures.VitalMessageOption: Confirmation-requested\r\n"
|
||||
"MyFeatures.WackyMessageOption: Use-silly-font\r\n"
|
||||
"\r\n"
|
||||
"Content-type text/xml; charset=utf-8\r\n"
|
||||
"Content-ID: <1234567890@foo.com>\r\n"
|
||||
"\r\n"
|
||||
"<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
shared_ptr<const Cpim::Message> message = Cpim::Message::createFromString(str);
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(message)) return;
|
||||
|
||||
const string str2 = message->asString();
|
||||
BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str());
|
||||
}
|
||||
|
||||
static void parse_message_with_generic_header_parameters (void) {
|
||||
const string str = "Content-type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
"Test:;aaa=bbb;yes=no CheckMe\r\n"
|
||||
"yaya: coucou\r\n"
|
||||
"yepee:;good=bad ugly\r\n"
|
||||
"\r\n"
|
||||
"Content-type text/xml; charset=utf-8\r\n"
|
||||
"Content-ID: <1234567890@foo.com>\r\n"
|
||||
"\r\n"
|
||||
"<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
shared_ptr<const Cpim::Message> message = Cpim::Message::createFromString(str);
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(message)) return;
|
||||
|
||||
const string str2 = message->asString();
|
||||
BC_ASSERT_STRING_EQUAL(str2.c_str(), str.c_str());
|
||||
}
|
||||
|
||||
static void build_message (void) {
|
||||
Cpim::Message message;
|
||||
if (!BC_ASSERT_FALSE(message.isValid()))
|
||||
return;
|
||||
|
||||
// Set CPIM headers.
|
||||
Cpim::GenericHeader contentTypeHeader;
|
||||
if (!BC_ASSERT_TRUE(contentTypeHeader.setName("Content-Type"))) return;
|
||||
if (!BC_ASSERT_TRUE(contentTypeHeader.setValue("Message/CPIM"))) return;
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.addCpimHeader(contentTypeHeader))) return;
|
||||
|
||||
// Set message headers.
|
||||
Cpim::FromHeader fromHeader;
|
||||
if (!BC_ASSERT_TRUE(fromHeader.setValue("MR SANDERS <im:piglet@100akerwood.com>"))) return;
|
||||
|
||||
Cpim::ToHeader toHeader;
|
||||
if (!BC_ASSERT_TRUE(toHeader.setValue("Depressed Donkey <im:eeyore@100akerwood.com>"))) return;
|
||||
|
||||
Cpim::DateTimeHeader dateTimeHeader;
|
||||
if (!BC_ASSERT_TRUE(dateTimeHeader.setValue("2000-12-13T13:40:00-08:00"))) return;
|
||||
|
||||
Cpim::SubjectHeader subjectHeader;
|
||||
if (!BC_ASSERT_TRUE(subjectHeader.setValue("the weather will be fine today"))) return;
|
||||
|
||||
Cpim::SubjectHeader subjectWithLanguageHeader;
|
||||
if (!BC_ASSERT_TRUE(subjectWithLanguageHeader.setValue("beau temps prevu pour aujourd'hui"))) return;
|
||||
if (!BC_ASSERT_TRUE(subjectWithLanguageHeader.setLanguage("fr"))) return;
|
||||
|
||||
Cpim::NsHeader nsHeader;
|
||||
if (!BC_ASSERT_TRUE(nsHeader.setValue("MyFeatures <mid:MessageFeatures@id.foo.com>"))) return;
|
||||
|
||||
Cpim::RequireHeader requireHeader;
|
||||
if (!BC_ASSERT_TRUE(requireHeader.setValue("MyFeatures.VitalMessageOption"))) return;
|
||||
|
||||
Cpim::GenericHeader vitalMessageHeader;
|
||||
if (!BC_ASSERT_TRUE(vitalMessageHeader.setName("MyFeatures.VitalMessageOption"))) return;
|
||||
if (!BC_ASSERT_TRUE(vitalMessageHeader.setValue("Confirmation-requested"))) return;
|
||||
|
||||
Cpim::GenericHeader wackyMessageHeader;
|
||||
if (!BC_ASSERT_TRUE(wackyMessageHeader.setName("MyFeatures.WackyMessageOption"))) return;
|
||||
if (!BC_ASSERT_TRUE(wackyMessageHeader.setValue("Use-silly-font"))) return;
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(fromHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(toHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(dateTimeHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(subjectHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(subjectWithLanguageHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(nsHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(requireHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(vitalMessageHeader))) return;
|
||||
if (!BC_ASSERT_TRUE(message.addMessageHeader(wackyMessageHeader))) return;
|
||||
|
||||
const string content = "Content-type text/xml; charset=utf-8\r\n"
|
||||
"Content-ID: <1234567890@foo.com>\r\n"
|
||||
"\r\n"
|
||||
"<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
if (!BC_ASSERT_TRUE(message.setContent(content))) return;
|
||||
if (!BC_ASSERT_TRUE(message.isValid())) return;
|
||||
|
||||
const string strMessage = message.asString();
|
||||
const string expectedMessage = "Content-Type: Message/CPIM\r\n"
|
||||
"\r\n"
|
||||
"From: MR SANDERS <im:piglet@100akerwood.com>\r\n"
|
||||
"To: Depressed Donkey <im:eeyore@100akerwood.com>\r\n"
|
||||
"DateTime: 2000-12-13T13:40:00-08:00\r\n"
|
||||
"Subject: the weather will be fine today\r\n"
|
||||
"Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
|
||||
"NS: MyFeatures <mid:MessageFeatures@id.foo.com>\r\n"
|
||||
"Require: MyFeatures.VitalMessageOption\r\n"
|
||||
"MyFeatures.VitalMessageOption: Confirmation-requested\r\n"
|
||||
"MyFeatures.WackyMessageOption: Use-silly-font\r\n"
|
||||
"\r\n"
|
||||
"Content-type text/xml; charset=utf-8\r\n"
|
||||
"Content-ID: <1234567890@foo.com>\r\n"
|
||||
"\r\n"
|
||||
"<body>"
|
||||
"Here is the text of my message."
|
||||
"</body>";
|
||||
|
||||
BC_ASSERT_STRING_EQUAL(strMessage.c_str(), expectedMessage.c_str());
|
||||
}
|
||||
|
||||
test_t cpim_tests[] = {
|
||||
TEST_NO_TAG("Parse minimal CPIM message", parse_minimal_message),
|
||||
TEST_NO_TAG("Set generic header name", set_generic_header_name),
|
||||
TEST_NO_TAG("Set generic header value", set_generic_header_value),
|
||||
TEST_NO_TAG("Check core header names", check_core_header_names),
|
||||
TEST_NO_TAG("Set core header values", set_core_header_values),
|
||||
TEST_NO_TAG("Check Subject header language", check_subject_header_language),
|
||||
TEST_NO_TAG("Parse RFC example", parse_rfc_example),
|
||||
TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters),
|
||||
TEST_NO_TAG("Build Message", build_message)
|
||||
};
|
||||
|
||||
test_suite_t cpim_test_suite = {
|
||||
"Cpim", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
|
||||
sizeof(cpim_tests) / sizeof(cpim_tests[0]), cpim_tests
|
||||
};
|
||||
|
|
@ -39,37 +39,41 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern test_suite_t setup_test_suite;
|
||||
extern test_suite_t register_test_suite;
|
||||
extern test_suite_t account_creator_test_suite;
|
||||
extern test_suite_t call_test_suite;
|
||||
extern test_suite_t call_video_test_suite;
|
||||
extern test_suite_t message_test_suite;
|
||||
extern test_suite_t presence_test_suite;
|
||||
extern test_suite_t presence_server_test_suite;
|
||||
extern test_suite_t upnp_test_suite;
|
||||
extern test_suite_t cpim_test_suite;
|
||||
extern test_suite_t dtmf_test_suite;
|
||||
extern test_suite_t event_test_suite;
|
||||
extern test_suite_t conf_event_test_suite;
|
||||
extern test_suite_t flexisip_test_suite;
|
||||
extern test_suite_t stun_test_suite;
|
||||
extern test_suite_t remote_provisioning_test_suite;
|
||||
extern test_suite_t quality_reporting_test_suite;
|
||||
extern test_suite_t log_collection_test_suite;
|
||||
extern test_suite_t tunnel_test_suite;
|
||||
extern test_suite_t player_test_suite;
|
||||
extern test_suite_t dtmf_test_suite;
|
||||
extern test_suite_t offeranswer_test_suite;
|
||||
extern test_suite_t video_test_suite;
|
||||
extern test_suite_t multicast_call_test_suite;
|
||||
extern test_suite_t message_test_suite;
|
||||
extern test_suite_t multi_call_test_suite;
|
||||
extern test_suite_t multicast_call_test_suite;
|
||||
extern test_suite_t offeranswer_test_suite;
|
||||
extern test_suite_t player_test_suite;
|
||||
extern test_suite_t presence_server_test_suite;
|
||||
extern test_suite_t presence_test_suite;
|
||||
extern test_suite_t proxy_config_test_suite;
|
||||
extern test_suite_t account_creator_test_suite;
|
||||
extern test_suite_t quality_reporting_test_suite;
|
||||
extern test_suite_t register_test_suite;
|
||||
extern test_suite_t remote_provisioning_test_suite;
|
||||
extern test_suite_t setup_test_suite;
|
||||
extern test_suite_t stun_test_suite;
|
||||
extern test_suite_t tunnel_test_suite;
|
||||
extern test_suite_t upnp_test_suite;
|
||||
extern test_suite_t video_test_suite;
|
||||
|
||||
#ifdef VCARD_ENABLED
|
||||
extern test_suite_t vcard_test_suite;
|
||||
#endif
|
||||
|
||||
extern test_suite_t audio_bypass_suite;
|
||||
#if HAVE_SIPP
|
||||
extern test_suite_t complex_sip_call_test_suite;
|
||||
#endif
|
||||
|
||||
extern int manager_count;
|
||||
|
||||
extern int liblinphone_tester_ipv6_available(void);
|
||||
|
|
@ -112,6 +116,7 @@ extern const char* test_username;
|
|||
extern const char* test_password;
|
||||
extern const char* test_route;
|
||||
extern const char* userhostsfile;
|
||||
extern bool_t liblinphone_tester_keep_uuid;
|
||||
extern bool_t liblinphone_tester_tls_support_disabled;
|
||||
extern const MSAudioDiffParams audio_cmp_params;
|
||||
extern const char *liblinphone_tester_mire_id;
|
||||
|
|
@ -164,6 +169,7 @@ typedef struct _stats {
|
|||
int number_of_LinphoneMessageDelivered;
|
||||
int number_of_LinphoneMessageNotDelivered;
|
||||
int number_of_LinphoneMessageFileTransferDone;
|
||||
int number_of_LinphoneMessageFileTransferError;
|
||||
int number_of_LinphoneMessageDeliveredToUser;
|
||||
int number_of_LinphoneMessageDisplayed;
|
||||
int number_of_LinphoneIsComposingActiveReceived;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg,
|
|||
return;
|
||||
case LinphoneChatMessageStateFileTransferError:
|
||||
counters->number_of_LinphoneMessageNotDelivered++;
|
||||
counters->number_of_LinphoneMessageFileTransferError++;
|
||||
return;
|
||||
case LinphoneChatMessageStateFileTransferDone:
|
||||
counters->number_of_LinphoneMessageFileTransferDone++;
|
||||
|
|
@ -698,10 +699,13 @@ static void file_transfer_using_external_body_url(void) {
|
|||
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1));
|
||||
if (marie->stat.last_received_chat_message) {
|
||||
cbs = linphone_chat_message_get_callbacks(marie->stat.last_received_chat_message);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
|
||||
linphone_chat_message_download_file(marie->stat.last_received_chat_message);
|
||||
}
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageExtBodyReceived, 1));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageInProgress, 1));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneMessageDelivered, 1));
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageFileTransferError, 1));
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(marie);
|
||||
}
|
||||
|
|
@ -877,6 +881,7 @@ static int enable_lime_for_message_test(LinphoneCoreManager *marie, LinphoneCore
|
|||
int ret = 0;
|
||||
char* paulineUri = NULL;
|
||||
char* marieUri = NULL;
|
||||
char *tmp;
|
||||
|
||||
if (!linphone_core_lime_available(marie->lc) || !linphone_core_lime_available(pauline->lc)) {
|
||||
ms_warning("Lime not available, skiping");
|
||||
|
|
@ -891,8 +896,12 @@ static int enable_lime_for_message_test(LinphoneCoreManager *marie, LinphoneCore
|
|||
lp_config_set_int(pauline->lc->config, "sip", "zrtp_cache_migration_done", TRUE);
|
||||
|
||||
/* create temporary cache files: setting the database_path will create and initialise the files */
|
||||
remove(bc_tester_file("tmpZIDCacheMarie.sqlite"));
|
||||
remove(bc_tester_file("tmpZIDCachePauline.sqlite"));
|
||||
tmp = bc_tester_file("tmpZIDCacheMarie.sqlite");
|
||||
remove(tmp);
|
||||
bc_free(tmp);
|
||||
tmp = bc_tester_file("tmpZIDCachePauline.sqlite");
|
||||
remove(tmp);
|
||||
bc_free(tmp);
|
||||
filepath = bc_tester_file("tmpZIDCacheMarie.sqlite");
|
||||
linphone_core_set_zrtp_secrets_file(marie->lc, filepath);
|
||||
bc_free(filepath);
|
||||
|
|
@ -920,7 +929,8 @@ static int enable_lime_for_message_test(LinphoneCoreManager *marie, LinphoneCore
|
|||
sqlite3_free(errmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ms_free(paulineUri);
|
||||
ms_free(marieUri);
|
||||
|
||||
return 0;
|
||||
#else /* SQLITE_STORAGE_ENABLED */
|
||||
|
|
@ -1787,9 +1797,8 @@ void file_transfer_io_error_base(char *server_url, bool_t destroy_room) {
|
|||
linphone_chat_room_send_chat_message(chatroom, msg);
|
||||
BC_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneMessageInProgress, 1, 1000));
|
||||
if (destroy_room) {
|
||||
//since message is orphan, we do not expect to be notified of state change
|
||||
linphone_core_delete_chat_room(marie->lc, chatroom);
|
||||
BC_ASSERT_FALSE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneMessageNotDelivered, 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneMessageNotDelivered, 1, 1000));
|
||||
} else {
|
||||
BC_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneMessageNotDelivered, 1, 3000));
|
||||
}
|
||||
|
|
@ -2422,7 +2431,7 @@ test_t message_tests[] = {
|
|||
TEST_NO_TAG("Transfer message with download io error", transfer_message_with_download_io_error),
|
||||
TEST_NO_TAG("Transfer message upload cancelled", transfer_message_upload_cancelled),
|
||||
TEST_NO_TAG("Transfer message download cancelled", transfer_message_download_cancelled),
|
||||
TEST_ONE_TAG("Transfer message using external body url", file_transfer_using_external_body_url, "LeaksMemory"),
|
||||
TEST_NO_TAG("Transfer message using external body url", file_transfer_using_external_body_url),
|
||||
TEST_NO_TAG("Transfer 2 messages simultaneously", file_transfer_2_messages_simultaneously),
|
||||
TEST_NO_TAG("Text message denied", text_message_denied),
|
||||
TEST_NO_TAG("Info message", info_message),
|
||||
|
|
@ -2482,10 +2491,20 @@ test_t message_tests[] = {
|
|||
TEST_NO_TAG("IM Encryption Engine b64", im_encryption_engine_b64)
|
||||
};
|
||||
|
||||
static int message_tester_before_suite(void) {
|
||||
liblinphone_tester_keep_uuid = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int message_tester_after_suite(void) {
|
||||
liblinphone_tester_keep_uuid = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
test_suite_t message_test_suite = {
|
||||
"Message",
|
||||
NULL,
|
||||
NULL,
|
||||
message_tester_before_suite,
|
||||
message_tester_after_suite,
|
||||
liblinphone_tester_before_each,
|
||||
liblinphone_tester_after_each,
|
||||
sizeof(message_tests) / sizeof(message_tests[0]), message_tests
|
||||
|
|
|
|||
|
|
@ -44,8 +44,9 @@
|
|||
|
||||
|
||||
static int liblinphone_tester_keep_accounts_flag = 0;
|
||||
static int liblinphone_tester_keep_record_files = FALSE;
|
||||
static int liblinphone_tester_leak_detector_disabled = FALSE;
|
||||
static bool_t liblinphone_tester_keep_record_files = FALSE;
|
||||
static bool_t liblinphone_tester_leak_detector_disabled = FALSE;
|
||||
bool_t liblinphone_tester_keep_uuid = FALSE;
|
||||
bool_t liblinphone_tester_tls_support_disabled = FALSE;
|
||||
int manager_count = 0;
|
||||
int leaked_objects_count = 0;
|
||||
|
|
@ -573,6 +574,7 @@ void liblinphone_tester_add_suites() {
|
|||
bc_tester_add_suite(&log_collection_test_suite);
|
||||
bc_tester_add_suite(&player_test_suite);
|
||||
bc_tester_add_suite(&dtmf_test_suite);
|
||||
bc_tester_add_suite(&cpim_test_suite);
|
||||
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
|
||||
bc_tester_add_suite(&video_test_suite);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue