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

IM : simplify

parent d6a2bb56
...@@ -36,43 +36,17 @@ ...@@ -36,43 +36,17 @@
namespace sfl 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) static void XMLCALL startElementCallback (void *userData, const char *name, const char **atts)
{ {
if (strcmp (name, "entry"))
return;
char attribute[100]; sfl::InstantMessaging::UriEntry entry = sfl::InstantMessaging::UriEntry();
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))); for (const char **att = atts; *att; att += 2)
} entry.insert (std::pair<std::string, std::string> (*att, *(att+1)));
list->push_back (entry);
}
(static_cast<sfl::InstantMessaging::UriList *> (userData))->push_back(entry);
} }
static void XMLCALL endElementCallback (void * /*userData*/, const char * /*name*/) static void XMLCALL endElementCallback (void * /*userData*/, const char * /*name*/)
...@@ -87,40 +61,10 @@ InstantMessaging::InstantMessaging() ...@@ -87,40 +61,10 @@ InstantMessaging::InstantMessaging()
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) 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::ofstream File;
std::string filename = "im:"; std::string filename = "im:" + id;
filename.append (id);
File.open (filename.c_str (), (std::_Ios_Openmode) mode); File.open (filename.c_str (), (std::_Ios_Openmode) mode);
if (!File.good () || !File.is_open ()) if (!File.good () || !File.is_open ())
...@@ -132,209 +76,79 @@ bool InstantMessaging::saveMessage (const std::string& message, const std::strin ...@@ -132,209 +76,79 @@ bool InstantMessaging::saveMessage (const std::string& message, const std::strin
return true; return true;
} }
std::string InstantMessaging::receive (const std::string& message, const std::string& /*author*/, const std::string& /*id*/) void InstantMessaging::sip_send (pjsip_inv_session *session, const std::string& id, const std::string& text)
{
// 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)
{ {
pjsip_method msg_method;
const pj_str_t type = STR_TEXT;
const pj_str_t subtype = STR_PLAIN;
pjsip_tx_data *tdata; 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); pjsip_dlg_inc_lock (dialog);
// Create the message request pjsip_method msg_method = { PJSIP_OTHER_METHOD, pj_str((char*)"MESSAGE") };
status = pjsip_dlg_create_request (dialog, &msg_method, -1, &tdata); if (pjsip_dlg_create_request (dialog, &msg_method, -1, &tdata) != PJ_SUCCESS) {
PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1); 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); tdata->msg->body = pjsip_msg_body_create (tdata->pool, &type, &subtype, &message);
// Create the Require header to handle recipient-list Content-Disposition type pjsip_dlg_send_request (dialog, tdata, -1, NULL);
// 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_dec_lock (dialog); pjsip_dlg_dec_lock (dialog);
// Archive the message saveMessage (text, "Me", id);
this->saveMessage (text, "Me", id);
return PJ_SUCCESS;
} }
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)
{ {
std::vector<std::string> msgs = split_message (message);
/* Check the length of the message */ std::vector<std::string>::const_iterator iter;
if (message.length() < getMessageMaximumSize()) { for (iter = msgs.begin(); iter != msgs.end(); ++iter)
/* No problem here */ sip_send (session, id, *iter);
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;
} }
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) iax_send_text(session, message.c_str()) != -1;
return true;
else
return false;
} }
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)
{ {
std::vector<std::string> msgs = split_message (message);
bool ret; std::vector<std::string>::const_iterator iter;
for (iter = msgs.begin(); iter != msgs.end(); ++iter)
/* Check the length of the message */ iax_send(session, id, *iter);
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> InstantMessaging::split_message (const std::string& text) std::vector<std::string> InstantMessaging::split_message(std::string text)
{ {
std::vector<std::string> messages; std::vector<std::string> messages;
std::string text_to_split = text; size_t len = getMessageMaximumSize();
/* Iterate over the message length */ while (text.length() > len - 2) {
while (text_to_split.length() > getMessageMaximumSize()) { messages.push_back (text.substr(len - 2) + "\n\n");
/* The remaining string is still too long */ text = text.substr(len - 2);
/* 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());
} }
/* Push the last message */ messages.push_back (text);
/* 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; return messages;
} }
std::string InstantMessaging::generateXmlUriList (UriList& list) 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\"?>"; for (UriList::iterator iter = list.begin(); iter != list.end(); ++iter)
xmlbuffer.append ("<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\" xmlns:cp=\"urn:ietf:params:xml:ns:copycontrol\">"); xmlbuffer += "<entry uri=" + (*iter)[sfl::IM_XML_URI] + " cp:copyControl=\"to\" />";
xmlbuffer.append ("<list>");
// An iterator over xml attribute
UriEntry::iterator iterAttr;
// An iterator over list entries return xmlbuffer + "</list></resource-lists>";
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;
} }
...@@ -357,20 +171,13 @@ InstantMessaging::UriList InstantMessaging::parseXmlUriList (std::string& urilis ...@@ -357,20 +171,13 @@ InstantMessaging::UriList InstantMessaging::parseXmlUriList (std::string& urilis
std::string InstantMessaging::appendUriList (std::string text, UriList& list) std::string InstantMessaging::appendUriList (std::string text, UriList& list)
{ {
return
std::string formatedText = "--boundary Content-Type: text/plain"; "--boundary Content-Type: text/plain" +
text +
formatedText.append (text); "--boundary Content-Type: application/resource-lists+xml" +
formatedText.append ("--boundary Content-Type: application/resource-lists+xml"); "Content-Disposition: recipient-list" +
formatedText.append ("Content-Disposition: recipient-list"); generateXmlUriList (list) +
"--boundary--";
std::string recipientlist = generateXmlUriList (list);
formatedText.append (recipientlist);
formatedText.append ("--boundary--");
return formatedText;
} }
std::string InstantMessaging::findTextUriList (std::string& text) std::string InstantMessaging::findTextUriList (std::string& text)
...@@ -405,21 +212,15 @@ 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 InstantMessaging::findTextMessage (std::string& text)
{ {
std::string ctype = "Content-Type: text/plain"; 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 size_t pos = text.find (ctype);
if ( (pos = text.find (ctype)) == std::string::npos) if (pos == std::string::npos)
throw InstantMessageException ("Could not find Content-Type tag while parsing sip message for text"); 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) size_t begin = pos+ctype.size();
begin = pos+ctype.size();
// retrive end of the text content size_t end = text.find ("--boundary", begin);
if ( (end = text.find (boundary, begin)) == std::string::npos) if (end == std::string::npos)
throw InstantMessageException ("Could not find end of text \"boundary\" while parsing sip message for text"); throw InstantMessageException ("Could not find end of text \"boundary\" while parsing sip message for text");
return text.substr (begin, end-begin); return text.substr (begin, end-begin);
......
...@@ -50,11 +50,7 @@ ...@@ -50,11 +50,7 @@
#include <iax-client.h> #include <iax-client.h>
#define EMPTY_MESSAGE pj_str((char*)"") #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 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_APPEND std::ios::out || std::ios::app
#define MODE_TEST std::ios::out #define MODE_TEST std::ios::out
...@@ -90,11 +86,6 @@ class InstantMessaging ...@@ -90,11 +86,6 @@ class InstantMessaging
*/ */
~InstantMessaging(); ~InstantMessaging();
/*
* Register and initialize instant messaging support
*/
bool init ();
/** /**
* Set maximum size fo this module. * Set maximum size fo this module.
*/ */
...@@ -110,21 +101,6 @@ class InstantMessaging ...@@ -110,21 +101,6 @@ class InstantMessaging
return messageMaxSize; 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 * 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 * 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 ...@@ -135,40 +111,21 @@ class InstantMessaging
*/ */
bool saveMessage (const std::string& message, const std::string& author, const std::string& id, int mode = MODE_APPEND); 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 * Send a SIP string message inside a call
* *
* @param id The call ID we will retrieve the invite session from * @param id The call ID we will retrieve the invite session from
* @param message The string message, as sent by the client * @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&); std::vector<std::string> split_message(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*/);
/** /**
......
...@@ -47,7 +47,6 @@ using std::endl; ...@@ -47,7 +47,6 @@ using std::endl;
void InstantMessagingTest::setUp() void InstantMessagingTest::setUp()
{ {
_im = new sfl::InstantMessaging (); _im = new sfl::InstantMessaging ();
_im->init ();
} }
void InstantMessagingTest::testSaveSingleMessage () void InstantMessagingTest::testSaveSingleMessage ()
......
Supports Markdown
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