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
d81435fa
Commit
d81435fa
authored
Sep 16, 2011
by
Rafaël Carré
Browse files
IM : simplify
parent
d6a2bb56
Changes
3
Show whitespace changes
Inline
Side-by-side
daemon/src/im/InstantMessaging.cpp
View file @
d81435fa
...
...
@@ -36,43 +36,17 @@
namespace
sfl
{
static
inline
char
*
duplicateString
(
char
dst
[],
const
char
src
[],
size_t
len
)
{
memcpy
(
dst
,
src
,
len
);
dst
[
len
]
=
0
;
return
dst
;
}
static
void
XMLCALL
startElementCallback
(
void
*
userData
,
const
char
*
name
,
const
char
**
atts
)
{
if
(
strcmp
(
name
,
"entry"
))
return
;
char
attribute
[
100
];
char
value
[
100
];
const
char
**
att
;
// _debug ("InstantMessaging: StartElement Callback: %s", name);
if
(
strcmp
(
name
,
"entry"
)
==
0
)
{
sfl
::
InstantMessaging
::
UriList
*
list
=
static_cast
<
sfl
::
InstantMessaging
::
UriList
*>
(
userData
);
sfl
::
InstantMessaging
::
UriEntry
entry
=
sfl
::
InstantMessaging
::
UriEntry
();
for
(
att
=
atts
;
*
att
;
att
+=
2
)
{
const
char
**
val
=
att
+
1
;
duplicateString
(
attribute
,
*
att
,
strlen
(
*
att
));
duplicateString
(
value
,
*
val
,
strlen
(
*
val
));
// _debug ("InstantMessaging: attribute: %s, value: %s", attribute, value);
entry
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
std
::
string
(
attribute
),
std
::
string
(
value
)));
}
list
->
push_back
(
entry
);
}
for
(
const
char
**
att
=
atts
;
*
att
;
att
+=
2
)
entry
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
*
att
,
*
(
att
+
1
)));
(
static_cast
<
sfl
::
InstantMessaging
::
UriList
*>
(
userData
))
->
push_back
(
entry
);
}
static
void
XMLCALL
endElementCallback
(
void
*
/*userData*/
,
const
char
*
/*name*/
)
...
...
@@ -87,40 +61,10 @@ InstantMessaging::InstantMessaging()
InstantMessaging
::~
InstantMessaging
()
{}
bool
InstantMessaging
::
init
()
{
return
true
;
}
int
InstantMessaging
::
openArchive
(
std
::
string
&
id
)
{
// 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
();
}
int
InstantMessaging
::
closeArchive
(
std
::
string
&
id
)
{
// Erase it from the map
imFiles
.
erase
(
id
);
return
(
int
)
imFiles
.
size
();
}
bool
InstantMessaging
::
saveMessage
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
const
std
::
string
&
id
,
int
mode
)
{
// We need here to write the text message in the right file.
// We will use the Call ID
std
::
ofstream
File
;
std
::
string
filename
=
"im:"
;
filename
.
append
(
id
);
std
::
string
filename
=
"im:"
+
id
;
File
.
open
(
filename
.
c_str
(),
(
std
::
_Ios_Openmode
)
mode
);
if
(
!
File
.
good
()
||
!
File
.
is_open
())
...
...
@@ -132,209 +76,79 @@ bool InstantMessaging::saveMessage (const std::string& message, const std::strin
return
true
;
}
std
::
string
InstantMessaging
::
receive
(
const
std
::
string
&
message
,
const
std
::
string
&
/*author*/
,
const
std
::
string
&
/*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
_debug
(
"New message : %s"
,
message
.
c_str
());
// TODO Security check
// TODO String cleaning
// Archive the message
// TODO Deactivate this for the momment, this is an extra feature.
// this->saveMessage (message, author, id);
return
message
;
}
pj_status_t
InstantMessaging
::
notify
(
const
std
::
string
&
/*id*/
)
void
InstantMessaging
::
sip_send
(
pjsip_inv_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
text
)
{
// Notify the clients through a D-Bus signal
return
PJ_SUCCESS
;
}
pj_status_t
InstantMessaging
::
sip_send
(
pjsip_inv_session
*
session
,
const
std
::
string
&
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
;
msg_method
.
id
=
PJSIP_OTHER_METHOD
;
msg_method
.
name
=
METHOD_NAME
;
pjsip_dialog
*
dialog
=
session
->
dlg
;
// 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
());
// Must lock dialog
pjsip_dlg_inc_lock
(
dialog
);
// Create the message request
status
=
pjsip_dlg_create_request
(
dialog
,
&
msg_method
,
-
1
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
pjsip_method
msg_method
=
{
PJSIP_OTHER_METHOD
,
pj_str
((
char
*
)
"MESSAGE"
)
};
if
(
pjsip_dlg_create_request
(
dialog
,
&
msg_method
,
-
1
,
&
tdata
)
!=
PJ_SUCCESS
)
{
pjsip_dlg_dec_lock
(
dialog
);
return
;
}
// Attach "text/plain" body
const
pj_str_t
type
=
pj_str
((
char
*
)
"text"
);
const
pj_str_t
subtype
=
pj_str
((
char
*
)
"plain"
);
pj_str_t
message
=
pj_str
(
(
char
*
)
text
.
c_str
());
tdata
->
msg
->
body
=
pjsip_msg_body_create
(
tdata
->
pool
,
&
type
,
&
subtype
,
&
message
);
// Create the Require header to handle recipient-list Content-Disposition type
// pjsip_generic_string_hdr reqhdr;
// pj_str_t reqhname = pj_str ("Require");
// pj_str_t reqhvalue = pj_str ("recipient-list");
// Create the Content-Type header to handle multipart/mixed and boundary MIME types
// pj_str_t ctype = pj_str ("Content-Type");
// pj_str_t sctype = pj_str ("ctype"); // small version of the header name
// ctypehdr = pjsip_msg_find_hdr_by_names (tdata->msg, &ctype, &sctype, NULL);
// pjsip_generic_string_hdr ctypehdr;
// pj_str_t ctypehname = pj_str ("Content-Type");
// pj_str_t ctypehvalue = pj_str ("multipart/mixed;boundary=\"boundary\"");
// Add headers to the message
// pjsip_generic_string_hdr_init2 (&reqhdr, &reqhname, &reqhvalue);
// pj_list_push_back (& (tdata->msg->hdr), (pjsip_hdr*) (&reqhdr));
// pj_list_push_back (& (tdata->msg->hdr), (pjsip_hdr*) (&ctypehdr));
// Send the request
status
=
pjsip_dlg_send_request
(
dialog
,
tdata
,
-
1
,
NULL
);
// PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1);
// Done
pjsip_dlg_send_request
(
dialog
,
tdata
,
-
1
,
NULL
);
pjsip_dlg_dec_lock
(
dialog
);
// Archive the message
this
->
saveMessage
(
text
,
"Me"
,
id
);
return
PJ_SUCCESS
;
saveMessage
(
text
,
"Me"
,
id
);
}
pj_status_t
InstantMessaging
::
send_sip_message
(
pjsip_inv_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
)
void
InstantMessaging
::
send_sip_message
(
pjsip_inv_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
)
{
/* Check the length of the message */
if
(
message
.
length
()
<
getMessageMaximumSize
())
{
/* No problem here */
sip_send
(
session
,
id
,
message
);
}
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
;
// Maximum is above 1500 character
// TODO: Send every messages
sip_send
(
session
,
id
,
multiple_messages
[
i
]);
}
return
PJ_SUCCESS
;
std
::
vector
<
std
::
string
>
msgs
=
split_message
(
message
);
std
::
vector
<
std
::
string
>::
const_iterator
iter
;
for
(
iter
=
msgs
.
begin
();
iter
!=
msgs
.
end
();
++
iter
)
sip_send
(
session
,
id
,
*
iter
);
}
bool
InstantMessaging
::
iax_send
(
iax_session
*
session
,
const
std
::
string
&
/*id*/
,
const
std
::
string
&
message
)
void
InstantMessaging
::
iax_send
(
iax_session
*
session
,
const
std
::
string
&
/*id*/
,
const
std
::
string
&
message
)
{
if
(
iax_send_text
(
session
,
message
.
c_str
())
!=
-
1
)
return
true
;
else
return
false
;
iax_send_text
(
session
,
message
.
c_str
())
!=
-
1
;
}
bool
InstantMessaging
::
send_iax_message
(
iax_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
)
void
InstantMessaging
::
send_iax_message
(
iax_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
)
{
bool
ret
;
/* Check the length of the message */
if
(
message
.
length
()
<
getMessageMaximumSize
())
{
/* No problem here */
ret
=
iax_send
(
session
,
id
,
message
);
}
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
;
// Maximum is above 1500 character
// TODO: Send every messages
ret
=
iax_send
(
session
,
id
,
multiple_messages
[
i
]);
}
return
ret
;
std
::
vector
<
std
::
string
>
msgs
=
split_message
(
message
);
std
::
vector
<
std
::
string
>::
const_iterator
iter
;
for
(
iter
=
msgs
.
begin
();
iter
!=
msgs
.
end
();
++
iter
)
iax_send
(
session
,
id
,
*
iter
);
}
std
::
vector
<
std
::
string
>
InstantMessaging
::
split_message
(
const
std
::
string
&
text
)
std
::
vector
<
std
::
string
>
InstantMessaging
::
split_message
(
std
::
string
text
)
{
std
::
vector
<
std
::
string
>
messages
;
std
::
string
text_to_split
=
text
;
/* Iterate over the message length */
while
(
text_to_split
.
length
()
>
getMessageMaximumSize
())
{
/* The remaining string is still too long */
/* Compute the substring */
std
::
string
split_message
=
text_to_split
.
substr
(
0
,
(
size_t
)
getMessageMaximumSize
());
/* 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
)
getMessageMaximumSize
());
size_t
len
=
getMessageMaximumSize
();
while
(
text
.
length
()
>
len
-
2
)
{
messages
.
push_back
(
text
.
substr
(
len
-
2
)
+
"
\n\n
"
);
text
=
text
.
substr
(
len
-
2
);
}
/* 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
);
messages
.
push_back
(
text
);
return
messages
;
}
std
::
string
InstantMessaging
::
generateXmlUriList
(
UriList
&
list
)
{
std
::
string
xmlbuffer
=
"<?xml version=
\"
1.0
\"
encoding=
\"
UTF-8
\"
?>"
"<resource-lists xmlns=
\"
urn:ietf:params:xml:ns:resource-lists
\"
xmlns:cp=
\"
urn:ietf:params:xml:ns:copycontrol
\"
>"
"<list>"
;
std
::
string
xmlbuffer
=
"<?xml version=
\"
1.0
\"
encoding=
\"
UTF-8
\"
?>"
;
xmlbuffer
.
append
(
"<resource-lists xmlns=
\"
urn:ietf:params:xml:ns:resource-lists
\"
xmlns:cp=
\"
urn:ietf:params:xml:ns:copycontrol
\"
>"
);
xmlbuffer
.
append
(
"<list>"
);
// An iterator over xml attribute
UriEntry
::
iterator
iterAttr
;
for
(
UriList
::
iterator
iter
=
list
.
begin
();
iter
!=
list
.
end
();
++
iter
)
xmlbuffer
+=
"<entry uri="
+
(
*
iter
)[
sfl
::
IM_XML_URI
]
+
" cp:copyControl=
\"
to
\"
/>"
;
// An iterator over list entries
UriList
::
iterator
iterEntry
=
list
.
begin
();
while
(
iterEntry
!=
list
.
end
())
{
xmlbuffer
.
append
(
"<entry uri="
);
UriEntry
entry
=
static_cast
<
UriEntry
>
(
*
iterEntry
);
iterAttr
=
entry
.
find
(
sfl
::
IM_XML_URI
);
xmlbuffer
.
append
(
iterAttr
->
second
);
xmlbuffer
.
append
(
" cp:copyControl=
\"
to
\"
/>"
);
iterEntry
++
;
}
xmlbuffer
.
append
(
"</list>"
);
xmlbuffer
.
append
(
"</resource-lists>"
);
return
xmlbuffer
;
return
xmlbuffer
+
"</list></resource-lists>"
;
}
...
...
@@ -357,20 +171,13 @@ InstantMessaging::UriList InstantMessaging::parseXmlUriList (std::string& urilis
std
::
string
InstantMessaging
::
appendUriList
(
std
::
string
text
,
UriList
&
list
)
{
std
::
string
formatedText
=
"--boundary Content-Type: text/plain"
;
formatedText
.
append
(
text
);
formatedText
.
append
(
"--boundary Content-Type: application/resource-lists+xml"
);
formatedText
.
append
(
"Content-Disposition: recipient-list"
);
std
::
string
recipientlist
=
generateXmlUriList
(
list
);
formatedText
.
append
(
recipientlist
);
formatedText
.
append
(
"--boundary--"
);
return
formatedText
;
return
"--boundary Content-Type: text/plain"
+
text
+
"--boundary Content-Type: application/resource-lists+xml"
+
"Content-Disposition: recipient-list"
+
generateXmlUriList
(
list
)
+
"--boundary--"
;
}
std
::
string
InstantMessaging
::
findTextUriList
(
std
::
string
&
text
)
...
...
@@ -405,21 +212,15 @@ std::string InstantMessaging::findTextUriList (std::string& text)
std
::
string
InstantMessaging
::
findTextMessage
(
std
::
string
&
text
)
{
std
::
string
ctype
=
"Content-Type: text/plain"
;
std
::
string
boundary
=
"--boundary"
;
size_t
pos
=
0
;
size_t
begin
=
0
;
size_t
end
=
0
;
// find the content
type
if
(
(
pos
=
text
.
find
(
ctype
))
==
std
::
string
::
npos
)
size_t
pos
=
text
.
find
(
c
type
);
if
(
pos
==
std
::
string
::
npos
)
throw
InstantMessageException
(
"Could not find Content-Type tag while parsing sip message for text"
);
// plain text content start after content type tag (plus \n\n)
begin
=
pos
+
ctype
.
size
();
size_t
begin
=
pos
+
ctype
.
size
();
// retrive end of the text content
if
(
(
end
=
text
.
find
(
boundary
,
begin
))
==
std
::
string
::
npos
)
size_t
end
=
text
.
find
(
"--boundary"
,
begin
);
if
(
end
==
std
::
string
::
npos
)
throw
InstantMessageException
(
"Could not find end of text
\"
boundary
\"
while parsing sip message for text"
);
return
text
.
substr
(
begin
,
end
-
begin
);
...
...
daemon/src/im/InstantMessaging.h
View file @
d81435fa
...
...
@@ -50,11 +50,7 @@
#include
<iax-client.h>
#define EMPTY_MESSAGE pj_str((char*)"")
#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 1560
/* PJSIP's sip message limit */
#define DELIMITER_CHAR "\n\n"
#define MODE_APPEND std::ios::out || std::ios::app
#define MODE_TEST std::ios::out
...
...
@@ -90,11 +86,6 @@ class InstantMessaging
*/
~
InstantMessaging
();
/*
* Register and initialize instant messaging support
*/
bool
init
();
/**
* Set maximum size fo this module.
*/
...
...
@@ -110,21 +101,6 @@ class InstantMessaging
return
messageMaxSize
;
}
/*
* Open an existing file if possible or create a new one. *
* @param id The current call
* @return int The number of currently open file stream
*/
int
openArchive
(
std
::
string
&
id
);
/*
* Close the file corresponding to the specified call
*
* @param id The current call
* @return int The number of remaining open file stream
*/
int
closeArchive
(
std
::
string
&
id
);
/*
* Write the text message to the right file
* The call ID is associated to a file descriptor, so it is easy then to retrieve the right file
...
...
@@ -135,40 +111,21 @@ class InstantMessaging
*/
bool
saveMessage
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
const
std
::
string
&
id
,
int
mode
=
MODE_APPEND
);
/*
* Receive a string SIP message, for a specific call
*
* @param message The message contained in the TEXT message
* @param id The call recipient of the message
*/
std
::
string
receive
(
const
std
::
string
&
message
,
const
std
::
string
&
author
,
const
std
::
string
&
id
);
/*
* Send a SIP string message inside a call
*
* @param id The call ID we will retrieve the invite session from
* @param message The string message, as sent by the client
*
* @return pj_status_t 0 on success
* 1 otherwise
*/
pj_status_t
sip_send
(
pjsip_inv_session
*
,
const
std
::
string
&
id
,
const
std
::
string
&
);
void
sip_send
(
pjsip_inv_session
*
,
const
std
::
string
&
id
,
const
std
::
string
&
);
pj_status_t
send_sip_message
(
pjsip_inv_session
*
,
const
std
::
string
&
id
,
const
std
::
string
&
);
void
send_sip_message
(
pjsip_inv_session
*
,
const
std
::
string
&
id
,
const
std
::
string
&
);
bool
iax_send
(
iax_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
);
void
iax_send
(
iax_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
message
);
bool
send_iax_message
(
iax_session
*
session
,
const
std
::
string
&
id
,
const
std
::
string
&
);
void
send_iax_message
(
iax_session
*
session
,
const
std
::
string
&
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
*
* @param id The callID to notify (TODO: accountID?)
*/
pj_status_t
notify
(
const
std
::
string
&
/*id*/
);
std
::
vector
<
std
::
string
>
split_message
(
std
::
string
);
/**
...
...
daemon/test/instantmessagingtest.cpp
View file @
d81435fa
...
...
@@ -47,7 +47,6 @@ using std::endl;
void
InstantMessagingTest
::
setUp
()
{
_im
=
new
sfl
::
InstantMessaging
();
_im
->
init
();
}
void
InstantMessagingTest
::
testSaveSingleMessage
()
...
...
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