Create classes for the different types of chat rooms.

This commit is contained in:
Ghislain MARY 2017-09-11 18:03:45 +02:00
parent 5600ce3a6f
commit 8063ae024e
18 changed files with 745 additions and 193 deletions

View file

@ -36,14 +36,16 @@
#include "linphone/wrapper_utils.h"
#include "c-wrapper/c-tools.h"
#include "chat/chat-room-p.h"
#include "chat/chat-room.h"
#include "chat/basic-chat-room.h"
#include "chat/real-time-text-chat-room.h"
#include "chat/real-time-text-chat-room-p.h"
#include "utils/content-type.h"
struct _LinphoneChatRoom{
belle_sip_object_t base;
void *user_data;
LinphonePrivate::ChatRoom *cr;
LinphoneAddress *peerAddressCache;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoom);
@ -163,13 +165,20 @@ const bctbx_list_t *linphone_core_get_chat_rooms(LinphoneCore *lc) {
}
static bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from) {
return linphone_address_weak_equal(cr->cr->getPeerAddress(), from);
LinphoneAddress *addr = linphone_address_new(cr->cr->getPeerAddress().asString().c_str());
bool_t result = linphone_address_weak_equal(addr, from);
linphone_address_unref(addr);
return result;
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatRoom);
static void _linphone_chat_room_destroy(LinphoneChatRoom *cr) {
delete cr->cr;
if (cr->peerAddressCache) {
linphone_address_unref(cr->peerAddressCache);
cr->peerAddressCache = nullptr;
}
}
BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t,
@ -178,14 +187,17 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatRoom, belle_sip_object_t,
NULL, // marshal
FALSE);
LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, LinphoneAddress *addr){
LinphoneChatRoom *_linphone_core_create_chat_room_base(LinphoneCore *lc, const LinphoneAddress *addr) {
LinphoneChatRoom *cr = belle_sip_object_new(LinphoneChatRoom);
cr->cr = new LinphonePrivate::ChatRoom(lc, addr);
if (linphone_core_realtime_text_enabled(lc))
cr->cr = new LinphonePrivate::RealTimeTextChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get());
else
cr->cr = new LinphonePrivate::BasicChatRoom(lc, *L_GET_CPP_PTR_FROM_C_STRUCT(addr, Address).get());
L_GET_PRIVATE(cr->cr)->setCBackPointer(cr);
return cr;
}
static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, LinphoneAddress *addr) {
static LinphoneChatRoom *_linphone_core_create_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) {
LinphoneChatRoom *cr = _linphone_core_create_chat_room_base(lc, addr);
lc->chatrooms = bctbx_list_append(lc->chatrooms, (void *)cr);
return cr;
@ -238,7 +250,7 @@ static LinphoneChatRoom *_linphone_core_get_or_create_chat_room(LinphoneCore *lc
LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr) {
LinphoneChatRoom *ret = _linphone_core_get_chat_room(lc, addr);
if (!ret) {
ret = _linphone_core_create_chat_room(lc, linphone_address_clone(addr));
ret = _linphone_core_create_chat_room(lc, addr);
}
return ret;
}
@ -391,16 +403,20 @@ bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
return cr->cr->isRemoteComposing();
}
LinphoneCore *linphone_chat_room_get_lc(LinphoneChatRoom *cr) {
LinphoneCore *linphone_chat_room_get_lc(const LinphoneChatRoom *cr) {
return linphone_chat_room_get_core(cr);
}
LinphoneCore *linphone_chat_room_get_core(LinphoneChatRoom *cr) {
LinphoneCore *linphone_chat_room_get_core(const LinphoneChatRoom *cr) {
return cr->cr->getCore();
}
const LinphoneAddress *linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
return cr->cr->getPeerAddress();
if (cr->peerAddressCache) {
linphone_address_unref(cr->peerAddressCache);
}
cr->peerAddressCache = linphone_address_new(cr->cr->getPeerAddress().asString().c_str());
return cr->peerAddressCache;
}
LinphoneChatMessage *linphone_chat_room_create_message(LinphoneChatRoom *cr, const char *message) {
@ -599,46 +615,52 @@ void linphone_chat_message_send_display_notification(LinphoneChatMessage *cm) {
}
void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) {
L_GET_PRIVATE(cr->cr)->realtimeTextReceived(character, call);
if (linphone_core_realtime_text_enabled(lc))
L_GET_PRIVATE(static_cast<LinphonePrivate::RealTimeTextChatRoom *>(cr->cr))->realtimeTextReceived(character, call);
}
uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) {
return cr->cr->getChar();
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr)))
return static_cast<LinphonePrivate::RealTimeTextChatRoom *>(cr->cr)->getChar();
return 0;
}
LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) {
LinphoneChatRoom *cr = linphone_chat_message_get_chat_room(msg);
LinphoneCall *call = cr->cr->getCall();
LinphoneCore *lc = cr->cr->getCore();
const uint32_t new_line = 0x2028;
const uint32_t crlf = 0x0D0A;
const uint32_t lf = 0x0A;
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr))) {
LinphoneCall *call = static_cast<LinphonePrivate::RealTimeTextChatRoom *>(cr->cr)->getCall();
LinphoneCore *lc = static_cast<LinphonePrivate::RealTimeTextChatRoom *>(cr->cr)->getCore();
const uint32_t new_line = 0x2028;
const uint32_t crlf = 0x0D0A;
const uint32_t lf = 0x0A;
if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) {
return -1;
}
if (character == new_line || character == crlf || character == lf) {
if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) {
ms_debug("New line sent, forge a message with content %s", msg->message);
msg->time = ms_time(0);
msg->state = LinphoneChatMessageStateDisplayed;
msg->dir = LinphoneChatMessageOutgoing;
if (msg->from) linphone_address_unref(msg->from);
msg->from = linphone_address_new(linphone_core_get_identity(lc));
msg->storage_id = linphone_chat_message_store(msg);
ms_free(msg->message);
msg->message = NULL;
if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText)) {
return -1;
}
} else {
char *value = LinphonePrivate::Utils::utf8ToChar(character);
msg->message = ms_strcat_printf(msg->message, value);
ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message);
delete value;
}
text_stream_putchar32(reinterpret_cast<TextStream *>(linphone_call_get_stream(call, LinphoneStreamTypeText)), character);
return 0;
if (character == new_line || character == crlf || character == lf) {
if (lc && lp_config_get_int(lc->config, "misc", "store_rtt_messages", 1) == 1) {
ms_debug("New line sent, forge a message with content %s", msg->message);
msg->time = ms_time(0);
msg->state = LinphoneChatMessageStateDisplayed;
msg->dir = LinphoneChatMessageOutgoing;
if (msg->from) linphone_address_unref(msg->from);
msg->from = linphone_address_new(linphone_core_get_identity(lc));
msg->storage_id = linphone_chat_message_store(msg);
ms_free(msg->message);
msg->message = NULL;
}
} else {
char *value = LinphonePrivate::Utils::utf8ToChar(character);
msg->message = ms_strcat_printf(msg->message, value);
ms_debug("Sent RTT character: %s (%lu), pending text is %s", value, (unsigned long)character, msg->message);
delete value;
}
text_stream_putchar32(reinterpret_cast<TextStream *>(linphone_call_get_stream(call, LinphoneStreamTypeText)), character);
return 0;
}
return -1;
}
const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *cm) {
@ -650,7 +672,9 @@ void linphone_chat_room_compose(LinphoneChatRoom *cr) {
}
LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room) {
return room->cr->getCall();
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(room)))
return static_cast<LinphonePrivate::RealTimeTextChatRoom *>(room->cr)->getCall();
return nullptr;
}
void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call) {
@ -773,7 +797,10 @@ const LinphoneAddress *linphone_chat_message_get_to_address(const LinphoneChatMe
if (msg->to)
return msg->to;
if (msg->dir == LinphoneChatMessageOutgoing) {
return msg->chat_room->cr->getPeerAddress();
if (msg->chat_room->peerAddressCache)
linphone_address_unref(msg->chat_room->peerAddressCache);
msg->chat_room->peerAddressCache = linphone_address_new(msg->chat_room->cr->getPeerAddress().asString().c_str());
return msg->chat_room->peerAddressCache;
}
return NULL;
}

View file

@ -207,12 +207,12 @@ LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoo
* @deprecated use linphone_chat_room_get_core()
* @donotwrap
**/
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCore* linphone_chat_room_get_lc(const LinphoneChatRoom *cr);
/**
* Returns back pointer to #LinphoneCore object.
**/
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr);
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(const LinphoneChatRoom *cr);
/**
* When realtime text is enabled #linphone_call_params_realtime_text_enabled, #LinphoneCoreIsComposingReceivedCb is call everytime a char is received from peer.

View file

@ -28,9 +28,13 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
call/call-listener.h
call/call-p.h
call/call.h
chat/basic-chat-room.h
chat/basic-chat-room-p.h
chat/chat-message.h
chat/chat-room-p.h
chat/chat-room.h
chat/client-group-chat-room.h
chat/client-group-chat-room-p.h
chat/cpim/cpim.h
chat/cpim/header/cpim-core-headers.h
chat/cpim/header/cpim-generic-header.h
@ -41,6 +45,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
chat/cpim/parser/cpim-parser.h
chat/imdn.h
chat/is-composing.h
chat/real-time-text-chat-room.h
chat/real-time-text-chat-room-p.h
conference/conference-listener.h
conference/conference-p.h
conference/conference.h
@ -90,8 +96,10 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
c-wrapper/api/c-address.cpp
c-wrapper/api/c-event-log.cpp
call/call.cpp
chat/basic-chat-room.cpp
chat/chat-message.cpp
chat/chat-room.cpp
chat/client-group-chat-room.cpp
chat/cpim/header/cpim-core-headers.cpp
chat/cpim/header/cpim-generic-header.cpp
chat/cpim/header/cpim-header.cpp
@ -100,6 +108,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
chat/cpim/parser/cpim-parser.cpp
chat/imdn.cpp
chat/is-composing.cpp
chat/real-time-text-chat-room.cpp
conference/conference.cpp
conference/local-conference.cpp
conference/params/call-session-params.cpp

View file

@ -0,0 +1,45 @@
/*
* basic-chat-room-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 _BASIC_CHAT_ROOM_P_H_
#define _BASIC_CHAT_ROOM_P_H_
// From coreapi.
#include "private.h"
#include "basic-chat-room.h"
#include "chat/chat-room-p.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class BasicChatRoomPrivate : public ChatRoomPrivate {
public:
BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress);
virtual ~BasicChatRoomPrivate () = default;
private:
std::string dummyConferenceId;
L_DECLARE_PUBLIC(BasicChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _BASIC_CHAT_ROOM_P_H_

View file

@ -0,0 +1,70 @@
/*
* basic-chat-room.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 "basic-chat-room-p.h"
#include "logger/logger.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
BasicChatRoomPrivate::BasicChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {}
// =============================================================================
BasicChatRoom::BasicChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new BasicChatRoomPrivate(core, peerAddress)) {}
// -----------------------------------------------------------------------------
shared_ptr<Participant> BasicChatRoom::addParticipant (const Address &addr, const shared_ptr<CallSessionParams> params, bool hasMedia) {
lError() << "addParticipant() is not allowed on a BasicChatRoom";
return nullptr;
}
void BasicChatRoom::addParticipants (const list<Address> &addresses, const shared_ptr<CallSessionParams> params, bool hasMedia) {
lError() << "addParticipants() is not allowed on a BasicChatRoom";
}
const string& BasicChatRoom::getId () const {
L_D(const BasicChatRoom);
lError() << "a BasicChatRoom does not have a conference id";
return d->dummyConferenceId;
}
int BasicChatRoom::getNbParticipants () const {
return 1;
}
list<shared_ptr<Participant>> BasicChatRoom::getParticipants () const {
L_D(const BasicChatRoom);
list<shared_ptr<Participant>> l;
l.push_back(make_shared<Participant>(d->peerAddress));
return l;
}
void BasicChatRoom::removeParticipant (const shared_ptr<Participant> participant) {
lError() << "removeParticipant() is not allowed on a BasicChatRoom";
}
void BasicChatRoom::removeParticipants (const list<shared_ptr<Participant>> participants) {
lError() << "removeParticipants() is not allowed on a BasicChatRoom";
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,58 @@
/*
* basic-chat-room.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 _BASIC_CHAT_ROOM_H_
#define _BASIC_CHAT_ROOM_H_
// From coreapi
#include "private.h"
#include "chat/chat-room.h"
#include "conference/conference-interface.h"
#include "linphone/types.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class BasicChatRoomPrivate;
class BasicChatRoom : public ChatRoom {
public:
BasicChatRoom (LinphoneCore *core, const Address &peerAddress);
virtual ~BasicChatRoom () = default;
/* ConferenceInterface */
std::shared_ptr<Participant> addParticipant (const Address &addr, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
void addParticipants (const std::list<Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
const std::string& getId () const;
int getNbParticipants () const;
std::list<std::shared_ptr<Participant>> getParticipants () const;
void removeParticipant (const std::shared_ptr<Participant> participant);
void removeParticipants (const std::list<std::shared_ptr<Participant>> participants);
private:
L_DECLARE_PRIVATE(BasicChatRoom);
L_DISABLE_COPY(BasicChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _BASIC_CHAT_ROOM_H_

View file

@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE
class ChatRoomPrivate : public ObjectPrivate, public IsComposingListener {
public:
ChatRoomPrivate (LinphoneCore *core);
ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress);
virtual ~ChatRoomPrivate ();
private:
@ -62,7 +62,7 @@ public:
this->call = call;
}
private:
protected:
void sendIsComposingNotification ();
int createChatMessageFromDb (int argc, char **argv, char **colName);
@ -78,7 +78,7 @@ public:
LinphoneReason messageReceived (SalOp *op, const SalMessage *msg);
void realtimeTextReceived (uint32_t character, LinphoneCall *call);
private:
protected:
void chatMessageReceived (LinphoneChatMessage *msg);
void imdnReceived (const std::string &text);
void isComposingReceived (const std::string &text);
@ -92,8 +92,7 @@ public:
LinphoneChatRoom *cBackPointer = nullptr;
LinphoneCore *core = nullptr;
LinphoneCall *call = nullptr;
LinphoneAddress *peerAddress = nullptr;
std::string peer;
Address peerAddress;
int unreadCount = -1;
bool isComposing = false;
bool remoteIsComposing = false;

View file

@ -22,6 +22,7 @@
#include "chat-room-p.h"
#include "imdn.h"
#include "c-wrapper/c-tools.h"
#include "logger/logger.h"
#include "utils/content-type.h"
@ -33,17 +34,13 @@ using namespace std;
LINPHONE_BEGIN_NAMESPACE
ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core)
: core(core), isComposingHandler(core, this) {}
ChatRoomPrivate::ChatRoomPrivate (LinphoneCore *core, const Address &peerAddress)
: core(core), peerAddress(peerAddress), isComposingHandler(core, this) {}
ChatRoomPrivate::~ChatRoomPrivate () {
for (auto it = transientMessages.begin(); it != transientMessages.end(); it++) {
linphone_chat_message_release(*it);
}
if (!receivedRttCharacters.empty()) {
for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++)
bctbx_free(*it);
}
if (core) {
if (bctbx_list_find(core->chatrooms, cBackPointer)) {
lError() << "LinphoneChatRoom[" << cBackPointer << "] is destroyed while still being used by the LinphoneCore. " <<
@ -52,7 +49,6 @@ ChatRoomPrivate::~ChatRoomPrivate () {
core->chatrooms = bctbx_list_remove(core->chatrooms, cBackPointer);
}
}
linphone_address_unref(peerAddress);
if (pendingMessage)
linphone_chat_message_destroy(pendingMessage);
}
@ -120,7 +116,8 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) {
L_Q(ChatRoom);
const char *identity = nullptr;
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peerAddress);
LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str());
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer);
if (proxy)
identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy));
else
@ -128,11 +125,11 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) {
/* Sending out of call */
SalOp *op = sal_op_new(core->sal);
linphone_configure_op(core, op, peerAddress, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0));
linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0));
LinphoneChatMessage *msg = q->createMessage(content);
LinphoneAddress *fromAddr = linphone_address_new(identity);
linphone_chat_message_set_from_address(msg, fromAddr);
LinphoneAddress *toAddr = linphone_address_new(peer.c_str());
LinphoneAddress *toAddr = linphone_address_new(peerAddress.asString().c_str());
linphone_chat_message_set_to_address(msg, toAddr);
linphone_chat_message_set_content_type(msg, "message/imdn+xml");
@ -148,12 +145,13 @@ void ChatRoomPrivate::sendImdn (const string &content, LinphoneReason reason) {
}
if (retval <= 0) {
sal_message_send(op, identity, peer.c_str(), msg->content_type, msg->message, nullptr);
sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr);
}
linphone_chat_message_unref(msg);
linphone_address_unref(fromAddr);
linphone_address_unref(toAddr);
linphone_address_unref(peer);
sal_op_unref(op);
}
@ -165,11 +163,11 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) {
/* Optimization: do not read database if the count is already available in memory */
if (unreadOnly && unreadCount >= 0) return unreadCount;
char *peer = linphone_address_as_string_uri_only(peerAddress);
string peer = peerAddress.asStringUriOnly();
char *option = nullptr;
if (unreadOnly)
option = bctbx_strdup_printf("AND status!=%i AND direction=%i", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming);
char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer, unreadOnly ? option : "");
char *buf = sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;", peer.c_str(), unreadOnly ? option : "");
sqlite3_stmt *selectStatement;
int numrows = 0;
int returnValue = sqlite3_prepare_v2(core->db, buf, -1, &selectStatement, nullptr);
@ -180,7 +178,6 @@ int ChatRoomPrivate::getMessagesCount (bool unreadOnly) {
}
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
/* No need to test the sign of unreadCount here because it has been tested above */
if (unreadOnly) {
@ -196,7 +193,8 @@ void ChatRoomPrivate::sendIsComposingNotification () {
L_Q(ChatRoom);
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(core);
if (linphone_im_notif_policy_get_send_is_composing(policy)) {
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peerAddress);
LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str());
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, peer);
const char *identity = nullptr;
if (proxy)
@ -206,14 +204,14 @@ void ChatRoomPrivate::sendIsComposingNotification () {
/* Sending out of call */
SalOp *op = sal_op_new(core->sal);
linphone_configure_op(core, op, peerAddress, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0));
linphone_configure_op(core, op, peer, nullptr, lp_config_get_int(core->config, "sip", "chat_msg_with_contact", 0));
string content = isComposingHandler.marshal(isComposing);
if (!content.empty()) {
int retval = -1;
LinphoneAddress *fromAddr = linphone_address_new(identity);
LinphoneChatMessage *msg = q->createMessage(content);
linphone_chat_message_set_from_address(msg, fromAddr);
linphone_chat_message_set_to_address(msg, peerAddress);
linphone_chat_message_set_to_address(msg, peer);
linphone_chat_message_set_content_type(msg, "application/im-iscomposing+xml");
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(core);
@ -226,13 +224,14 @@ void ChatRoomPrivate::sendIsComposingNotification () {
}
if (retval <= 0) {
sal_message_send(op, identity, peer.c_str(), msg->content_type, msg->message, nullptr);
sal_message_send(op, identity, peerAddress.asString().c_str(), msg->content_type, msg->message, nullptr);
}
linphone_chat_message_unref(msg);
linphone_address_unref(fromAddr);
sal_op_unref(op);
}
linphone_address_unref(peer);
}
}
@ -270,15 +269,17 @@ int ChatRoomPrivate::createChatMessageFromDb (int argc, char **argv, char **colN
if (!newMessage) {
newMessage = q->createMessage(argv[4] ? argv[4] : "");
LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str());
if (atoi(argv[3]) == LinphoneChatMessageIncoming) {
newMessage->dir = LinphoneChatMessageIncoming;
linphone_chat_message_set_from(newMessage, peerAddress);
linphone_chat_message_set_from(newMessage, peer);
newMessage->to = nullptr; /* Will be filled at the end */
} else {
newMessage->dir = LinphoneChatMessageOutgoing;
newMessage->from = nullptr; /* Will be filled at the end */
linphone_chat_message_set_to(newMessage, peerAddress);
linphone_chat_message_set_to(newMessage, peer);
}
linphone_address_unref(peer);
newMessage->time = (time_t)atol(argv[9]);
newMessage->is_read = atoi(argv[6]);
@ -358,12 +359,11 @@ void ChatRoomPrivate::sqlRequestMessage (sqlite3 *db, const string &stmt) {
list<LinphoneChatMessage *> ChatRoomPrivate::findMessages (const string &messageId) {
if (!core->db)
return list<LinphoneChatMessage *>();
char *peer = linphone_address_as_string_uri_only(peerAddress);
char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer, messageId.c_str());
string peer = peerAddress.asStringUriOnly();
char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer.c_str(), messageId.c_str());
messages.clear();
sqlRequestMessage(core->db, buf);
sqlite3_free(buf);
ms_free(peer);
list<LinphoneChatMessage *> result = messages;
messages.clear();
return result;
@ -401,7 +401,9 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa
msg = q->createMessage(salMsg->text ? salMsg->text : "");
linphone_chat_message_set_content_type(msg, salMsg->content_type);
linphone_chat_message_set_from(msg, peerAddress);
LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str());
linphone_chat_message_set_from(msg, peer);
linphone_address_unref(peer);
LinphoneAddress *to = sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(core));
msg->to = to;
@ -494,59 +496,6 @@ end:
return reason;
}
void ChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) {
L_Q(ChatRoom);
const uint32_t new_line = 0x2028;
const uint32_t crlf = 0x0D0A;
const uint32_t lf = 0x0A;
if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1);
if (!pendingMessage)
pendingMessage = q->createMessage("");
cmc->value = character;
cmc->has_been_read = FALSE;
receivedRttCharacters.push_back(cmc);
remoteIsComposing = true;
linphone_core_notify_is_composing_received(core, cBackPointer);
if ((character == new_line) || (character == crlf) || (character == lf)) {
/* End of message */
lDebug() << "New line received, forge a message with content " << pendingMessage->message;
linphone_chat_message_set_from(pendingMessage, peerAddress);
if (pendingMessage->to)
linphone_address_unref(pendingMessage->to);
pendingMessage->to = linphone_call_get_dest_proxy(call)
? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address)
: linphone_address_new(linphone_core_get_identity(core));
pendingMessage->time = ms_time(0);
pendingMessage->state = LinphoneChatMessageStateDelivered;
pendingMessage->dir = LinphoneChatMessageIncoming;
if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1)
storeOrUpdateMessage(pendingMessage);
if (unreadCount < 0) unreadCount = 1;
else unreadCount++;
chatMessageReceived(pendingMessage);
linphone_chat_message_unref(pendingMessage);
pendingMessage = nullptr;
for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++)
ms_free(*it);
receivedRttCharacters.clear();
} else {
char *value = Utils::utf8ToChar(character);
pendingMessage->message = ms_strcat_printf(pendingMessage->message, value);
lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->message;
delete value;
}
}
}
// -----------------------------------------------------------------------------
void ChatRoomPrivate::chatMessageReceived (LinphoneChatMessage *msg) {
@ -589,13 +538,9 @@ void ChatRoomPrivate::isComposingRefreshNeeded () {
// =============================================================================
ChatRoom::ChatRoom (LinphoneCore *core, LinphoneAddress *peerAddress) : Object(*new ChatRoomPrivate(core)) {
L_D(ChatRoom);
d->peerAddress = peerAddress;
char *peerStr = linphone_address_as_string(d->peerAddress);
d->peer = peerStr;
ms_free(peerStr);
}
ChatRoom::ChatRoom (LinphoneCore *core, const Address &peerAddress) : Object(*new ChatRoomPrivate(core, peerAddress)) {}
ChatRoom::ChatRoom (ChatRoomPrivate &p) : Object(p) {}
// -----------------------------------------------------------------------------
@ -617,7 +562,9 @@ LinphoneChatMessage *ChatRoom::createFileTransferMessage (const LinphoneContent
cm->message = nullptr;
cm->file_transfer_information = linphone_content_copy(initialContent);
cm->dir = LinphoneChatMessageOutgoing;
linphone_chat_message_set_to(cm, d->peerAddress);
LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str());
linphone_chat_message_set_to(cm, peer);
linphone_address_unref(peer);
cm->from = linphone_address_new(linphone_core_get_identity(d->core));
/* This will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */
cm->content_type = nullptr;
@ -645,11 +592,10 @@ LinphoneChatMessage *ChatRoom::createMessage (const string &msg) {
void ChatRoom::deleteHistory () {
L_D(ChatRoom);
if (!d->core->db) return;
char *peer = linphone_address_as_string_uri_only(d->peerAddress);
char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer);
string peer = d->peerAddress.asStringUriOnly();
char *buf = sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;", peer.c_str());
d->sqlRequest(d->core->db, buf);
sqlite3_free(buf);
ms_free(peer);
if (d->unreadCount > 0) d->unreadCount = 0;
}
@ -697,20 +643,6 @@ LinphoneChatMessage * ChatRoom::findMessageWithDirection (const string &messageI
return ret;
}
uint32_t ChatRoom::getChar () const {
L_D(const ChatRoom);
if (!d->receivedRttCharacters.empty()) {
for (auto it = d->receivedRttCharacters.begin(); it != d->receivedRttCharacters.end(); it++) {
LinphoneChatMessageCharacter *cmc = *it;
if (!cmc->has_been_read) {
cmc->has_been_read = TRUE;
return cmc->value;
}
}
}
return 0;
}
list<LinphoneChatMessage *> ChatRoom::getHistory (int nbMessages) {
return getHistoryRange(0, nbMessages - 1);
}
@ -723,13 +655,13 @@ int ChatRoom::getHistorySize () {
list<LinphoneChatMessage *> ChatRoom::getHistoryRange (int startm, int endm) {
L_D(ChatRoom);
if (!d->core->db) return list<LinphoneChatMessage *>();
char *peer = linphone_address_as_string_uri_only(d->peerAddress);
string peer = d->peerAddress.asStringUriOnly();
d->messages.clear();
/* Since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf */
const int bufMaxSize = 512;
char *buf = reinterpret_cast<char *>(ms_malloc(bufMaxSize));
buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer);
buf = sqlite3_snprintf(bufMaxSize - 1, buf, "SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC", peer.c_str());
if (startm < 0) startm = 0;
if (((endm > 0) && (endm >= startm)) || ((startm == 0) && (endm == 0))) {
@ -775,7 +707,6 @@ list<LinphoneChatMessage *> ChatRoom::getHistoryRange (int startm, int endm) {
list<LinphoneChatMessage *> result = d->messages;
d->messages.clear();
ms_free(peer);
return result;
}
@ -797,8 +728,8 @@ void ChatRoom::markAsRead () {
/* Optimization: do not modify the database if no message is marked as unread */
if (getUnreadMessagesCount() == 0) return;
char *peer = linphone_address_as_string_uri_only(d->peerAddress);
char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer, LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed);
string peer = d->peerAddress.asStringUriOnly();
char *buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer.c_str(), LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed);
d->sqlRequestMessage(d->core->db, buf);
sqlite3_free(buf);
for (auto it = d->messages.begin(); it != d->messages.end(); it++) {
@ -806,10 +737,9 @@ void ChatRoom::markAsRead () {
linphone_chat_message_unref(*it);
}
d->messages.clear();
buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer, LinphoneChatMessageIncoming);
buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;", LinphoneChatMessageStateDisplayed, peer.c_str(), LinphoneChatMessageIncoming);
d->sqlRequest(d->core->db, buf);
sqlite3_free(buf);
ms_free(peer);
if (d->pendingMessage) {
linphone_chat_message_set_state(d->pendingMessage, LinphoneChatMessageStateDisplayed);
@ -822,14 +752,6 @@ void ChatRoom::markAsRead () {
void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
L_D(ChatRoom);
/* Stubed rtt */
if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) {
uint32_t new_line = 0x2028;
linphone_chat_message_put_char(msg, new_line);
linphone_chat_message_unref(msg);
return;
}
msg->dir = LinphoneChatMessageOutgoing;
/* Check if we shall upload a file to a server */
@ -847,9 +769,10 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
} else {
SalOp *op = msg->op;
LinphoneCall *call = nullptr;
const char *identity = nullptr;
string identity;
char *clearTextMessage = nullptr;
char *clearTextContentType = nullptr;
LinphoneAddress *peer = linphone_address_new(d->peerAddress.asString().c_str());
if (msg->message) {
clearTextMessage = ms_strdup(msg->message);
@ -862,7 +785,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
d->addTransientMessage(msg);
msg->time = ms_time(0);
if (lp_config_get_int(d->core->config, "sip", "chat_use_call_dialogs", 0) != 0) {
call = linphone_core_get_call_by_remote_address(d->core, d->peer.c_str());
call = linphone_core_get_call_by_remote_address(d->core, d->peerAddress.asString().c_str());
if (call) {
if (linphone_call_get_state(call) == LinphoneCallConnected || linphone_call_get_state(call) == LinphoneCallStreamsRunning ||
linphone_call_get_state(call) == LinphoneCallPaused || linphone_call_get_state(call) == LinphoneCallPausing ||
@ -874,10 +797,10 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
}
}
if (!identity) {
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, d->peerAddress);
if (identity.empty()) {
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(d->core, peer);
if (proxy) {
identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy));
identity = L_GET_CPP_PTR_FROM_C_STRUCT(linphone_proxy_config_get_identity_address(proxy), Address)->asString();
} else {
identity = linphone_core_get_primary_contact(d->core);
}
@ -886,7 +809,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
/* BUG: the file transfer message constructor sets the from, but doesn't do it as well as here */
linphone_address_unref(msg->from);
}
msg->from = linphone_address_new(identity);
msg->from = linphone_address_new(identity.c_str());
int retval = -1;
LinphoneImEncryptionEngine *imee = d->core->im_encryption_engine;
@ -904,7 +827,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
if (!op) {
/* Sending out of call */
msg->op = op = sal_op_new(d->core->sal);
linphone_configure_op(d->core, op, d->peerAddress, msg->custom_headers,
linphone_configure_op(d->core, op, peer, msg->custom_headers,
lp_config_get_int(d->core->config, "sip", "chat_msg_with_contact", 0));
sal_op_set_user_pointer(op, msg); /* If out of call, directly store msg */
}
@ -914,21 +837,20 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
d->storeOrUpdateMessage(msg);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
linphone_chat_message_unref(msg);
linphone_address_unref(peer);
return;
}
if (msg->external_body_url) {
char *content_type = ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"", msg->external_body_url);
sal_message_send(op, identity, d->peer.c_str(), content_type, nullptr, nullptr);
sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), content_type, nullptr, nullptr);
ms_free(content_type);
} else {
char *peerUri = linphone_address_as_string_uri_only(d->peerAddress);
if (msg->content_type) {
sal_message_send(op, identity, d->peer.c_str(), msg->content_type, msg->message, peerUri);
sal_message_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->content_type, msg->message, d->peerAddress.asStringUriOnly().c_str());
} else {
sal_text_send(op, identity, d->peer.c_str(), msg->message);
sal_text_send(op, identity.c_str(), d->peerAddress.asString().c_str(), msg->message);
}
ms_free(peerUri);
}
if (msg->message && clearTextMessage && strcmp(msg->message, clearTextMessage) != 0) {
@ -955,6 +877,7 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
if (clearTextContentType) {
ms_free(clearTextContentType);
}
linphone_address_unref(peer);
if (call && linphone_call_get_op(call) == op) {
/* In this case, chat delivery status is not notified, so unrefing chat message right now */
@ -973,11 +896,6 @@ void ChatRoom::sendMessage (LinphoneChatMessage *msg) {
// -----------------------------------------------------------------------------
LinphoneCall *ChatRoom::getCall () const {
L_D(const ChatRoom);
return d->call;
}
LinphoneCore *ChatRoom::getCore () const {
L_D(const ChatRoom);
return d->core;
@ -985,7 +903,7 @@ LinphoneCore *ChatRoom::getCore () const {
// -----------------------------------------------------------------------------
const LinphoneAddress *ChatRoom::getPeerAddress () const {
const Address& ChatRoom::getPeerAddress () const {
L_D(const ChatRoom);
return d->peerAddress;
}

View file

@ -24,7 +24,9 @@
#include <list>
#include "address/address.h"
#include "object/object.h"
#include "conference/conference-interface.h"
#include "linphone/types.h"
@ -34,9 +36,9 @@ LINPHONE_BEGIN_NAMESPACE
class ChatRoomPrivate;
class ChatRoom : public Object {
class ChatRoom : public Object, public ConferenceInterface {
public:
ChatRoom (LinphoneCore *core, LinphoneAddress *peerAddress);
ChatRoom (LinphoneCore *core, const Address &peerAddress);
virtual ~ChatRoom () = default;
void compose ();
@ -46,19 +48,20 @@ public:
void deleteMessage (LinphoneChatMessage *msg);
LinphoneChatMessage * findMessage (const std::string& messageId);
LinphoneChatMessage * findMessageWithDirection (const std::string &messageId, LinphoneChatMessageDir direction);
uint32_t getChar () const;
std::list<LinphoneChatMessage *> getHistory (int nbMessages);
int getHistorySize ();
std::list<LinphoneChatMessage *> getHistoryRange (int startm, int endm);
int getUnreadMessagesCount ();
bool isRemoteComposing () const;
void markAsRead ();
void sendMessage (LinphoneChatMessage *msg);
virtual void sendMessage (LinphoneChatMessage *msg);
LinphoneCall *getCall () const;
LinphoneCore *getCore () const;
const LinphoneAddress *getPeerAddress () const;
const Address& getPeerAddress () const;
protected:
explicit ChatRoom (ChatRoomPrivate &p);
private:
L_DECLARE_PRIVATE(ChatRoom);

View file

@ -0,0 +1,43 @@
/*
* client-group-chat-room-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 _CLIENT_GROUP_CHAT_ROOM_P_H_
#define _CLIENT_GROUP_CHAT_ROOM_P_H_
// From coreapi.
#include "private.h"
#include "client-group-chat-room.h"
#include "chat/chat-room-p.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ClientGroupChatRoomPrivate : public ChatRoomPrivate {
public:
ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress);
virtual ~ClientGroupChatRoomPrivate () = default;
private:
L_DECLARE_PUBLIC(ClientGroupChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _CLIENT_GROUP_CHAT_ROOM_P_H_

View file

@ -0,0 +1,30 @@
/*
* client-group-chat-room.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 "client-group-chat-room-p.h"
#include "logger/logger.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const Address &peerAddress) : ChatRoomPrivate(core, peerAddress) {}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,57 @@
/*
* client-group-chat-room.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 _CLIENT_GROUP_CHAT_ROOM_H_
#define _CLIENT_GROUP_CHAT_ROOM_H_
// From coreapi
#include "private.h"
#include "chat/chat-room.h"
#include "linphone/types.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ClientGroupChatRoomPrivate;
class ClientGroupChatRoom : public ChatRoom {
public:
ClientGroupChatRoom (LinphoneCore *core, const Address &peerAddress);
virtual ~ClientGroupChatRoom () = default;
/* ConferenceInterface */
std::shared_ptr<Participant> addParticipant (const Address &addr, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
void addParticipants (const std::list<Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
const std::string& getId () const;
int getNbParticipants () const;
std::list<std::shared_ptr<Participant>> getParticipants () const;
void removeParticipant (const std::shared_ptr<Participant> participant);
void removeParticipants (const std::list<const std::shared_ptr<Participant>> participants);
private:
L_DECLARE_PRIVATE(ClientGroupChatRoom);
L_DISABLE_COPY(ClientGroupChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _CLIENT_GROUP_CHAT_ROOM_H_

View file

@ -0,0 +1,56 @@
/*
* real-time-text-chat-room-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 _REAL_TIME_TEXT_CHAT_ROOM_P_H_
#define _REAL_TIME_TEXT_CHAT_ROOM_P_H_
// From coreapi.
#include "private.h"
#include "real-time-text-chat-room.h"
#include "chat/chat-room-p.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class RealTimeTextChatRoomPrivate : public ChatRoomPrivate {
public:
RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress);
virtual ~RealTimeTextChatRoomPrivate ();
public:
void setCall (LinphoneCall *call) { this->call = call; }
public:
void realtimeTextReceived (uint32_t character, LinphoneCall *call);
public:
LinphoneCall *call = nullptr;
std::list<LinphoneChatMessageCharacter *> receivedRttCharacters;
LinphoneChatMessage *pendingMessage = nullptr;
private:
std::string dummyConferenceId;
L_DECLARE_PUBLIC(RealTimeTextChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _REAL_TIME_TEXT_CHAT_ROOM_P_H_

View file

@ -0,0 +1,175 @@
/*
* chat-room.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 "linphone/utils/utils.h"
#include "real-time-text-chat-room-p.h"
#include "logger/logger.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
RealTimeTextChatRoomPrivate::RealTimeTextChatRoomPrivate (LinphoneCore *core, const Address &peerAddress)
: ChatRoomPrivate(core, peerAddress) {}
RealTimeTextChatRoomPrivate::~RealTimeTextChatRoomPrivate () {
if (!receivedRttCharacters.empty()) {
for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++)
bctbx_free(*it);
}
if (pendingMessage)
linphone_chat_message_destroy(pendingMessage);
}
// -----------------------------------------------------------------------------
void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) {
L_Q(ChatRoom);
const uint32_t new_line = 0x2028;
const uint32_t crlf = 0x0D0A;
const uint32_t lf = 0x0A;
if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1);
if (!pendingMessage)
pendingMessage = q->createMessage("");
cmc->value = character;
cmc->has_been_read = FALSE;
receivedRttCharacters.push_back(cmc);
remoteIsComposing = true;
linphone_core_notify_is_composing_received(core, cBackPointer);
if ((character == new_line) || (character == crlf) || (character == lf)) {
/* End of message */
lDebug() << "New line received, forge a message with content " << pendingMessage->message;
LinphoneAddress *peer = linphone_address_new(peerAddress.asString().c_str());
linphone_chat_message_set_from(pendingMessage, peer);
linphone_address_unref(peer);
if (pendingMessage->to)
linphone_address_unref(pendingMessage->to);
pendingMessage->to = linphone_call_get_dest_proxy(call)
? linphone_address_clone(linphone_call_get_dest_proxy(call)->identity_address)
: linphone_address_new(linphone_core_get_identity(core));
pendingMessage->time = ms_time(0);
pendingMessage->state = LinphoneChatMessageStateDelivered;
pendingMessage->dir = LinphoneChatMessageIncoming;
if (lp_config_get_int(core->config, "misc", "store_rtt_messages", 1) == 1)
storeOrUpdateMessage(pendingMessage);
if (unreadCount < 0) unreadCount = 1;
else unreadCount++;
chatMessageReceived(pendingMessage);
linphone_chat_message_unref(pendingMessage);
pendingMessage = nullptr;
for (auto it = receivedRttCharacters.begin(); it != receivedRttCharacters.end(); it++)
ms_free(*it);
receivedRttCharacters.clear();
} else {
char *value = Utils::utf8ToChar(character);
pendingMessage->message = ms_strcat_printf(pendingMessage->message, value);
lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->message;
delete value;
}
}
}
// =============================================================================
RealTimeTextChatRoom::RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress) : ChatRoom(*new RealTimeTextChatRoomPrivate(core, peerAddress)) {}
// -----------------------------------------------------------------------------
void RealTimeTextChatRoom::sendMessage (LinphoneChatMessage *msg) {
L_D(ChatRoom);
if (d->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(d->call))) {
uint32_t new_line = 0x2028;
linphone_chat_message_put_char(msg, new_line);
linphone_chat_message_unref(msg);
}
}
// -----------------------------------------------------------------------------
uint32_t RealTimeTextChatRoom::getChar () const {
L_D(const ChatRoom);
if (!d->receivedRttCharacters.empty()) {
for (auto it = d->receivedRttCharacters.begin(); it != d->receivedRttCharacters.end(); it++) {
LinphoneChatMessageCharacter *cmc = *it;
if (!cmc->has_been_read) {
cmc->has_been_read = TRUE;
return cmc->value;
}
}
}
return 0;
}
// -----------------------------------------------------------------------------
LinphoneCall *RealTimeTextChatRoom::getCall () const {
L_D(const ChatRoom);
return d->call;
}
// -----------------------------------------------------------------------------
shared_ptr<Participant> RealTimeTextChatRoom::addParticipant (const Address &addr, const shared_ptr<CallSessionParams> params, bool hasMedia) {
lError() << "addParticipant() is not allowed on a RealTimeTextChatRoom";
return nullptr;
}
void RealTimeTextChatRoom::addParticipants (const list<Address> &addresses, const shared_ptr<CallSessionParams> params, bool hasMedia) {
lError() << "addParticipants() is not allowed on a RealTimeTextChatRoom";
}
const string& RealTimeTextChatRoom::getId () const {
L_D(const RealTimeTextChatRoom);
lError() << "a RealTimeTextChatRoom does not have a conference id";
return d->dummyConferenceId;
}
int RealTimeTextChatRoom::getNbParticipants () const {
return 1;
}
list<shared_ptr<Participant>> RealTimeTextChatRoom::getParticipants () const {
L_D(const RealTimeTextChatRoom);
list<shared_ptr<Participant>> l;
l.push_back(make_shared<Participant>(d->peerAddress));
return l;
}
void RealTimeTextChatRoom::removeParticipant (const shared_ptr<Participant> participant) {
lError() << "removeParticipant() is not allowed on a RealTimeTextChatRoom";
}
void RealTimeTextChatRoom::removeParticipants (const list<shared_ptr<Participant>> participants) {
lError() << "removeParticipants() is not allowed on a RealTimeTextChatRoom";
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,62 @@
/*
* real-time-text-chat-room.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 _REAL_TIME_TEXT_CHAT_ROOM_H_
#define _REAL_TIME_TEXT_CHAT_ROOM_H_
// From coreapi
#include "private.h"
#include "chat/chat-room.h"
#include "linphone/types.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class RealTimeTextChatRoomPrivate;
class RealTimeTextChatRoom : public ChatRoom {
public:
RealTimeTextChatRoom (LinphoneCore *core, const Address &peerAddress);
virtual ~RealTimeTextChatRoom () = default;
void sendMessage (LinphoneChatMessage *msg);
uint32_t getChar () const;
LinphoneCall *getCall () const;
/* ConferenceInterface */
std::shared_ptr<Participant> addParticipant (const Address &addr, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
void addParticipants (const std::list<Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
const std::string& getId () const;
int getNbParticipants () const;
std::list<std::shared_ptr<Participant>> getParticipants () const;
void removeParticipant (const std::shared_ptr<Participant> participant);
void removeParticipants (const std::list<std::shared_ptr<Participant>> participants);
private:
L_DECLARE_PRIVATE(RealTimeTextChatRoom);
L_DISABLE_COPY(RealTimeTextChatRoom);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _REAL_TIME_TEXT_CHAT_ROOM_H_

View file

@ -33,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE
class ConferenceInterface {
public:
virtual std::shared_ptr<Participant> addParticipant (const Address &addr, const std::shared_ptr<CallSessionParams> params, bool hasMedia) = 0;
virtual void addParticipants (const std::list<const Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia) = 0;
virtual void addParticipants (const std::list<Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia) = 0;
virtual const std::string& getId () const = 0;
virtual int getNbParticipants () const = 0;
virtual std::list<std::shared_ptr<Participant>> getParticipants () const = 0;

View file

@ -109,7 +109,7 @@ shared_ptr<Participant> Conference::addParticipant (const Address &addr, const s
return d->activeParticipant;
}
void Conference::addParticipants (const list<const Address> &addresses, const shared_ptr<CallSessionParams> params, bool hasMedia) {
void Conference::addParticipants (const list<Address> &addresses, const shared_ptr<CallSessionParams> params, bool hasMedia) {
// TODO
}

View file

@ -46,7 +46,7 @@ public:
/* ConferenceInterface */
virtual std::shared_ptr<Participant> addParticipant (const Address &addr, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
virtual void addParticipants (const std::list<const Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
virtual void addParticipants (const std::list<Address> &addresses, const std::shared_ptr<CallSessionParams> params, bool hasMedia);
virtual const std::string& getId () const;
virtual int getNbParticipants () const;
virtual std::list<std::shared_ptr<Participant>> getParticipants () const;