Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
savoirfairelinux
jami-daemon
Commits
a713ae92
Commit
a713ae92
authored
Aug 30, 2010
by
Emmanuel Milou
Browse files
[#3619] Split messages that exceed a limit size + Unit tests
parent
b00dd446
Changes
5
Hide whitespace changes
Inline
Side-by-side
sflphone-common/src/sip/im/InstantMessaging.cpp
View file @
a713ae92
...
...
@@ -3,127 +3,174 @@
namespace
sfl
{
InstantMessaging
::
InstantMessaging
()
:
imFiles
()
{}
InstantMessaging
::
InstantMessaging
()
:
imFiles
()
{}
InstantMessaging
::~
InstantMessaging
()
{}
InstantMessaging
::~
InstantMessaging
()
{}
bool
InstantMessaging
::
init
()
{
return
true
;
}
bool
InstantMessaging
::
init
()
{
return
true
;
}
int
InstantMessaging
::
openArchive
(
CallID
&
id
)
{
int
InstantMessaging
::
openArchive
(
CallID
&
id
)
{
// Create a new file stream
std
::
ofstream
File
(
id
.
c_str
(),
std
::
ios
::
out
|
std
::
ios
::
app
);
imFiles
[
id
]
=
&
File
;
// Create a new file stream
std
::
ofstream
File
(
id
.
c_str
(),
std
::
ios
::
out
|
std
::
ios
::
app
);
imFiles
[
id
]
=
&
File
;
// Attach it to the call ID
return
(
int
)
imFiles
.
size
();
}
// Attach it to the call ID
return
(
int
)
imFiles
.
size
();
}
int
InstantMessaging
::
closeArchive
(
CallID
&
id
)
{
int
InstantMessaging
::
closeArchive
(
CallID
&
id
)
{
// Erase it from the map
imFiles
.
erase
(
id
);
return
(
int
)
imFiles
.
size
();
}
// Erase it from the map
imFiles
.
erase
(
id
);
return
(
int
)
imFiles
.
size
();
}
bool
InstantMessaging
::
saveMessage
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
CallID
&
id
,
int
mode
)
{
bool
InstantMessaging
::
saveMessage
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
CallID
&
id
,
int
mode
)
{
// We need here to write the text message in the right file.
// We will use the Call ID
// We need here to write the text message in the right file.
// We will use the Call ID
std
::
ofstream
File
;
std
::
string
filename
=
"sip:"
;
std
::
ofstream
File
;
std
::
string
filename
=
"sip:"
;
filename
.
append
(
id
);
File
.
open
(
filename
.
c_str
(),
(
std
::
_Ios_Openmode
)
mode
);
filename
.
append
(
id
);
File
.
open
(
filename
.
c_str
(),
(
std
::
_Ios_Openmode
)
mode
);
if
(
!
File
.
good
()
||
!
File
.
is_open
())
return
false
;
if
(
!
File
.
good
()
||
!
File
.
is_open
())
return
false
;
File
<<
"["
<<
author
<<
"] "
<<
message
<<
'\n'
;
File
.
close
();
File
<<
"["
<<
author
<<
"] "
<<
message
<<
'\n'
;
File
.
close
();
return
true
;
}
return
true
;
}
std
::
string
InstantMessaging
::
receive
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
CallID
&
id
)
{
std
::
string
InstantMessaging
::
receive
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
CallID
&
id
)
{
// We just receive a TEXT message. Before sent it to the recipient, we must assure that the message is complete.
// We should use a queue to push these messages in
// We just receive a TEXT message. Before sent it to the recipient, we must assure that the message is complete.
// We should use a queue to push these messages in
_debug
(
"New message : %s"
,
message
.
c_str
());
_debug
(
"New message : %s"
,
message
.
c_str
());
// TODO Security check
// TODO String cleaning
// TODO Security check
// TODO String cleaning
// Archive the message
this
->
saveMessage
(
message
,
author
,
id
);
// Archive the message
this
->
saveMessage
(
message
,
author
,
id
);
return
message
;
return
message
;
}
}
pj_status_t
InstantMessaging
::
notify
(
CallID
&
id
)
{
pj_status_t
InstantMessaging
::
notify
(
CallID
&
id
)
{
// Notify the clients through a D-Bus signal
return
PJ_SUCCESS
;
}
// Notify the clients through a D-Bus signal
return
PJ_SUCCESS
;
pj_status_t
InstantMessaging
::
send
(
pjsip_inv_session
*
session
,
CallID
&
id
,
const
std
::
string
&
text
)
{
}
pjsip_method
msg_method
;
const
pj_str_t
type
=
STR_TEXT
;
const
pj_str_t
subtype
=
STR_PLAIN
;
pjsip_tx_data
*
tdata
;
pj_status_t
status
;
pjsip_dialog
*
dialog
;
pj_str_t
message
;
pj_status_t
InstantMessaging
::
send
(
pjsip_inv_session
*
session
,
CallID
&
id
,
const
std
::
string
&
text
)
{
msg_method
.
id
=
PJSIP_OTHER_METHOD
;
msg_method
.
name
=
METHOD_NAME
;
pjsip_method
msg_method
;
const
pj_str_t
type
=
STR_TEXT
;
const
pj_str_t
subtype
=
STR_PLAIN
;
pjsip_tx_data
*
tdata
;
pj_status_t
status
;
pjsip_dialog
*
dialog
;
pj_str_t
message
;
// Get the dialog associated to the call
dialog
=
session
->
dlg
;
// Convert the text into a format readable by pjsip
message
=
pj_str
(
(
char
*
)
text
.
c_str
());
msg_method
.
id
=
PJSIP_OTHER_METHOD
;
msg_method
.
name
=
METHOD_NAME
;
// Must lock dialog
pjsip_dlg_inc_lock
(
dialog
)
;
// Get the dialog associated to the call
dialog
=
session
->
dlg
;
// Convert the text into a format readable by pjsip
message
=
pj_str
(
(
char
*
)
text
.
c_str
());
// Create the message request
status
=
pjsip_dlg_create_request
(
dialog
,
&
msg_method
,
-
1
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
// Must lock dialog
pjsip_dlg_inc_lock
(
dialog
);
// Attach "text/plain" body
tdata
->
msg
->
body
=
pjsip_msg_body_create
(
tdata
->
pool
,
&
type
,
&
subtype
,
&
message
);
// Create the messag
e request
status
=
pjsip_dlg_
create
_request
(
dialog
,
&
msg_method
,
-
1
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
// Send th
e request
status
=
pjsip_dlg_
send
_request
(
dialog
,
tdata
,
-
1
,
NULL
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
// Attach "text/plain" body
tdata
->
msg
->
body
=
pjsip_msg_body_create
(
tdata
->
pool
,
&
type
,
&
subtype
,
&
message
);
// Done
pjsip_dlg_dec_lock
(
dialog
);
// Send the request
status
=
pjsip_dlg_send_request
(
dialog
,
tdata
,
-
1
,
NULL
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
// Archive the message
this
->
saveMessage
(
text
,
"Me"
,
id
);
// Done
pjsip_dlg_dec_lock
(
dialog
);
printf
(
"SIPVoIPLink::sendTextMessage %s %s
\n
"
,
id
.
c_str
(),
text
.
c_str
());
return
PJ_SUCCESS
;
}
// Archive the
message
this
->
saveMessage
(
text
,
"Me"
,
id
);
pj_status_t
InstantMessaging
::
send_message
(
pjsip_inv_session
*
session
,
CallID
&
id
,
const
std
::
string
&
message
)
{
printf
(
"SIPVoIPLink::sendTextMessage %s %s
\n
"
,
id
.
c_str
(),
text
.
c_str
());
/* Check the length of the message */
if
(
message
.
length
()
<
MAXIMUM_MESSAGE_LENGTH
)
{
/* No problem here */
send
(
session
,
id
,
message
);
}
return
PJ_SUCCESS
;
}
else
{
/* It exceeds the size limit of a SIP MESSAGE (1300 bytes), o plit it and send multiple messages */
std
::
vector
<
std
::
string
>
multiple_messages
=
split_message
(
message
);
/* Send multiple messages */
int
size
=
multiple_messages
.
size
();
int
i
=
0
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
send
(
session
,
id
,
multiple_messages
[
i
]);
}
}
return
PJ_SUCCESS
;
}
std
::
vector
<
std
::
string
>
InstantMessaging
::
split_message
(
const
std
::
string
&
text
)
{
std
::
vector
<
std
::
string
>
messages
;
std
::
string
text_to_split
=
text
;
/* Iterate over the message length */
while
(
text_to_split
.
length
()
>
MAXIMUM_MESSAGE_LENGTH
)
{
/* The remaining string is still too long */
/* Compute the substring */
std
::
string
split_message
=
text_to_split
.
substr
(
0
,
(
size_t
)
MAXIMUM_MESSAGE_LENGTH
);
/* Append our split character \n\n */
split_message
.
append
(
DELIMITER_CHAR
);
/* Append in the vector */
messages
.
push_back
(
split_message
);
/* Use the remaining string to not loop forever */
text_to_split
=
text_to_split
.
substr
((
size_t
)
MAXIMUM_MESSAGE_LENGTH
);
}
/* Push the last message */
/* If the message length does not exceed the maximum size of a SIP MESSAGE, we go directly here */
messages
.
push_back
(
text_to_split
);
return
messages
;
}
}
sflphone-common/src/sip/im/InstantMessaging.h
View file @
a713ae92
...
...
@@ -16,6 +16,8 @@
#define STR_TEXT pj_str((char*)"text")
#define STR_PLAIN pj_str((char*)"plain")
#define METHOD_NAME pj_str((char*)"MESSAGE")
#define MAXIMUM_MESSAGE_LENGTH 10
/* ~1300/8 */
#define DELIMITER_CHAR "\n\n"
#define MODE_APPEND std::ios::out || std::ios::app
#define MODE_TEST std::ios::out
...
...
@@ -85,6 +87,11 @@ namespace sfl {
*/
pj_status_t
send
(
pjsip_inv_session
*
,
CallID
&
id
,
const
std
::
string
&
);
pj_status_t
send_message
(
pjsip_inv_session
*
,
CallID
&
id
,
const
std
::
string
&
);
std
::
vector
<
std
::
string
>
split_message
(
const
std
::
string
&
);
/**
* Notify the clients, through D-Bus, that a new message has arrived
*
...
...
@@ -92,6 +99,7 @@ namespace sfl {
*/
pj_status_t
notify
(
CallID
&
id
);
/*
* Add a pair file stream / call ID to the private std::map
*/
...
...
sflphone-common/src/sip/sipvoiplink.cpp
View file @
a713ae92
...
...
@@ -1073,7 +1073,7 @@ SIPVoIPLink::sendTextMessage (const std::string& callID, const std::string& mess
if
(
call
)
{
/* Send IM message */
status
=
imModule
->
send
(
call
->
getInvSession
(),
(
CallID
&
)
callID
,
message
);
status
=
imModule
->
send
_message
(
call
->
getInvSession
(),
(
CallID
&
)
callID
,
message
);
}
else
{
/* Notify the client of an error */
/*Manager::instance ().incomingMessage ( "",
...
...
sflphone-common/test/instantmessagingtest.cpp
View file @
a713ae92
...
...
@@ -34,65 +34,104 @@
#include
"instantmessagingtest.h"
#define MAXIMUM_SIZE 10
#define DELIMITER_CHAR "\n\n"
using
std
::
cout
;
using
std
::
endl
;
void
InstantMessagingTest
::
setUp
()
{
_im
=
new
sfl
::
InstantMessaging
();
_im
->
init
();
_im
=
new
sfl
::
InstantMessaging
();
_im
->
init
();
}
void
InstantMessagingTest
::
testSaveSingleMessage
()
{
_debug
(
"-------------------- InstantMessagingTest::testSaveSingleMessage --------------------
\n
"
);
_debug
(
"-------------------- InstantMessagingTest::testSaveSingleMessage --------------------
\n
"
);
std
::
string
input
,
tmp
;
std
::
string
callID
=
"testfile1.txt"
;
std
::
string
input
,
tmp
;
std
::
string
callID
=
"testfile1.txt"
;
// Open a file stream and try to write in it
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Bonjour, c'est un test d'archivage de message"
,
"Manu"
,
callID
,
std
::
ios
::
out
)
==
true
);
// Open a file stream and try to write in it
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Bonjour, c'est un test d'archivage de message"
,
"Manu"
,
callID
,
std
::
ios
::
out
)
==
true
);
// Read it to check it has been successfully written
std
::
ifstream
testfile
(
callID
.
c_str
(),
std
::
ios
::
in
);
CPPUNIT_ASSERT
(
testfile
.
is_open
()
==
true
);
// Read it to check it has been successfully written
std
::
ifstream
testfile
(
callID
.
c_str
(),
std
::
ios
::
in
);
CPPUNIT_ASSERT
(
testfile
.
is_open
()
==
true
);
while
(
!
testfile
.
eof
())
{
std
::
getline
(
testfile
,
tmp
);
input
.
append
(
tmp
);
}
while
(
!
testfile
.
eof
())
{
std
::
getline
(
testfile
,
tmp
);
input
.
append
(
tmp
);
}
testfile
.
close
();
CPPUNIT_ASSERT
(
input
==
"[Manu] Bonjour, c'est un test d'archivage de message"
);
testfile
.
close
();
CPPUNIT_ASSERT
(
input
==
"[Manu] Bonjour, c'est un test d'archivage de message"
);
}
void
InstantMessagingTest
::
testSaveMultipleMessage
()
{
_debug
(
"-------------------- InstantMessagingTest::testSaveMultipleMessage --------------------
\n
"
);
_debug
(
"-------------------- InstantMessagingTest::testSaveMultipleMessage --------------------
\n
"
);
std
::
string
input
,
tmp
;
std
::
string
callID
=
"testfile2.txt"
;
std
::
string
input
,
tmp
;
std
::
string
callID
=
"testfile2.txt"
;
// Open a file stream and try to write in it
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Bonjour, c'est un test d'archivage de message"
,
"Manu"
,
callID
,
std
::
ios
::
out
)
==
true
);
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Cool"
,
"Alex"
,
callID
,
std
::
ios
::
out
||
std
::
ios
::
app
)
==
true
);
// Open a file stream and try to write in it
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Bonjour, c'est un test d'archivage de message"
,
"Manu"
,
callID
,
std
::
ios
::
out
)
==
true
);
CPPUNIT_ASSERT
(
_im
->
saveMessage
(
"Cool"
,
"Alex"
,
callID
,
std
::
ios
::
out
||
std
::
ios
::
app
)
==
true
);
// Read it to check it has been successfully written
std
::
ifstream
testfile
(
callID
.
c_str
(),
std
::
ios
::
in
);
CPPUNIT_ASSERT
(
testfile
.
is_open
()
==
true
);
// Read it to check it has been successfully written
std
::
ifstream
testfile
(
callID
.
c_str
(),
std
::
ios
::
in
);
CPPUNIT_ASSERT
(
testfile
.
is_open
()
==
true
);
while
(
!
testfile
.
eof
())
{
std
::
getline
(
testfile
,
tmp
);
input
.
append
(
tmp
);
}
while
(
!
testfile
.
eof
())
{
std
::
getline
(
testfile
,
tmp
);
input
.
append
(
tmp
);
}
testfile
.
close
();
printf
(
"%s
\n
"
,
input
.
c_str
());
CPPUNIT_ASSERT
(
input
==
"[Manu] Bonjour, c'est un test d'archivage de message[Alex] Cool"
);
}
void
InstantMessagingTest
::
testSplitMessage
()
{
testfile
.
close
();
printf
(
"%s
\n
"
,
input
.
c_str
());
CPPUNIT_ASSERT
(
input
==
"[Manu] Bonjour, c'est un test d'archivage de message[Alex] Cool"
);
/* A message that does not need to be split */
std
::
string
short_message
=
"Salut"
;
std
::
vector
<
std
::
string
>
messages
=
_im
->
split_message
(
short_message
);
CPPUNIT_ASSERT
(
messages
.
size
()
==
short_message
.
length
()
/
MAXIMUM_SIZE
+
1
);
CPPUNIT_ASSERT
(
messages
[
0
]
==
short_message
);
/* A message that needs to be split into two messages */
std
::
string
long_message
=
"A message too long"
;
messages
=
_im
->
split_message
(
long_message
);
int
size
=
messages
.
size
();
int
i
=
0
;
CPPUNIT_ASSERT
(
size
==
(
int
)
long_message
.
length
()
/
MAXIMUM_SIZE
+
1
);
/* If only one element, do not enter the loop */
for
(
i
=
0
;
i
<
size
-
1
;
i
++
)
{
CPPUNIT_ASSERT
(
messages
[
i
]
==
long_message
.
substr
((
MAXIMUM_SIZE
*
i
),
MAXIMUM_SIZE
)
+
DELIMITER_CHAR
);
}
/* Works for the last element, or for the only element */
CPPUNIT_ASSERT
(
messages
[
size
-
1
]
==
long_message
.
substr
(
MAXIMUM_SIZE
*
(
size
-
1
)));
/* A message that needs to be split into four messages */
std
::
string
very_long_message
=
"A message that needs to be split into many messages"
;
messages
=
_im
->
split_message
(
very_long_message
);
size
=
messages
.
size
();
/* If only one element, do not enter the loop */
for
(
i
=
0
;
i
<
size
-
1
;
i
++
)
{
CPPUNIT_ASSERT
(
messages
[
i
]
==
very_long_message
.
substr
((
MAXIMUM_SIZE
*
i
),
MAXIMUM_SIZE
)
+
DELIMITER_CHAR
);
}
/* Works for the last element, or for the only element */
CPPUNIT_ASSERT
(
messages
[
size
-
1
]
==
very_long_message
.
substr
(
MAXIMUM_SIZE
*
(
size
-
1
)));
}
void
InstantMessagingTest
::
tearDown
()
{
delete
_im
;
_im
=
0
;
delete
_im
;
_im
=
0
;
}
sflphone-common/test/instantmessagingtest.h
View file @
a713ae92
...
...
@@ -55,6 +55,7 @@ class InstantMessagingTest : public CppUnit::TestCase {
CPPUNIT_TEST_SUITE
(
InstantMessagingTest
);
CPPUNIT_TEST
(
testSaveSingleMessage
);
CPPUNIT_TEST
(
testSaveMultipleMessage
);
CPPUNIT_TEST
(
testSplitMessage
);
CPPUNIT_TEST_SUITE_END
();
public:
...
...
@@ -75,6 +76,8 @@ class InstantMessagingTest : public CppUnit::TestCase {
void
testSaveSingleMessage
();
void
testSaveMultipleMessage
();
void
testSplitMessage
();
private:
sfl
::
InstantMessaging
*
_im
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment