Commit d81435fa authored by Rafaël Carré's avatar Rafaël Carré

IM : simplify

parent d6a2bb56
......@@ -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);
sfl::InstantMessaging::UriEntry entry = sfl::InstantMessaging::UriEntry();
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*/)
{
// 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)
void 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;
// 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 ());
pjsip_dialog* dialog = session->dlg;
// 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 (ctype);
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);
......
......@@ -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);
/**
......
......@@ -47,7 +47,6 @@ using std::endl;
void InstantMessagingTest::setUp()
{
_im = new sfl::InstantMessaging ();
_im->init ();
}
void InstantMessagingTest::testSaveSingleMessage ()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment