From 32a37f97c0a72ef087ecef32e01c8d3aa05f2f99 Mon Sep 17 00:00:00 2001 From: daleharvey Date: Wed, 2 Aug 2006 18:36:41 +0000 Subject: [PATCH] refactored session establishment --- src/jabber_whiteboard/Makefile_insert | 3 - src/jabber_whiteboard/defines.cpp | 12 +- src/jabber_whiteboard/defines.h | 20 +- src/jabber_whiteboard/inkboard-document.cpp | 6 +- src/jabber_whiteboard/inkboard-document.h | 5 +- src/jabber_whiteboard/invitation-handlers.cpp | 150 ------ .../new-inkboard-document.cpp | 94 ---- src/jabber_whiteboard/new-inkboard-document.h | 33 -- src/jabber_whiteboard/pedrogui.cpp | 4 +- src/jabber_whiteboard/session-manager.cpp | 454 ++++++++---------- src/jabber_whiteboard/session-manager.h | 162 ++----- 11 files changed, 275 insertions(+), 668 deletions(-) delete mode 100644 src/jabber_whiteboard/invitation-handlers.cpp delete mode 100644 src/jabber_whiteboard/new-inkboard-document.cpp delete mode 100644 src/jabber_whiteboard/new-inkboard-document.h diff --git a/src/jabber_whiteboard/Makefile_insert b/src/jabber_whiteboard/Makefile_insert index 1f2d26671..bea89e803 100644 --- a/src/jabber_whiteboard/Makefile_insert +++ b/src/jabber_whiteboard/Makefile_insert @@ -23,13 +23,10 @@ jabber_whiteboard_SOURCES = \ jabber_whiteboard/message-tags.h \ jabber_whiteboard/message-utilities.cpp \ jabber_whiteboard/message-utilities.h \ - jabber_whiteboard/new-inkboard-document.cpp \ - jabber_whiteboard/new-inkboard-document.h \ jabber_whiteboard/inkboard-document.cpp \ jabber_whiteboard/inkboard-document.h \ jabber_whiteboard/invitation-confirm-dialog.cpp \ jabber_whiteboard/invitation-confirm-dialog.h \ - jabber_whiteboard/invitation-handlers.cpp \ jabber_whiteboard/session-file-selector.cpp \ jabber_whiteboard/session-file-selector.h \ jabber_whiteboard/session-manager.cpp \ diff --git a/src/jabber_whiteboard/defines.cpp b/src/jabber_whiteboard/defines.cpp index 3e3895ea0..43a75cb7c 100644 --- a/src/jabber_whiteboard/defines.cpp +++ b/src/jabber_whiteboard/defines.cpp @@ -27,12 +27,12 @@ namespace Message { Wrapper CONFIGURE = "configure"; Wrapper MOVE = "move"; - Message CONNECT_REQUEST = ""; - Message CONNECTED = ""; - Message ACCEPT_INVITATION = ""; - Message DECLINE_INVITATION = ""; - Message DOCUMENT_BEGIN = ""; - Message DOCUMENT_END = ""; + Message CONNECT_REQUEST = "connect-request"; + Message CONNECTED = "connected"; + Message ACCEPT_INVITATION = "accept-invitation"; + Message DECLINE_INVITATION = "decline-invitation"; + Message DOCUMENT_BEGIN = "document-begin"; + Message DOCUMENT_END = "document-end"; } namespace Vars { diff --git a/src/jabber_whiteboard/defines.h b/src/jabber_whiteboard/defines.h index a5d2d2ce6..e08d876a6 100644 --- a/src/jabber_whiteboard/defines.h +++ b/src/jabber_whiteboard/defines.h @@ -101,17 +101,20 @@ namespace State { typedef char const* SessionState; } +namespace Dialog { + +enum DialogReply { + + ACCEPT_INVITATION = 0, + DECLINE_INVITATION = 1 +}; + +} + // message types // explicitly numbered to aid protocol description later on -// Responses to whiteboard invitations -enum InvitationResponses { - ACCEPT_INVITATION, - DECLINE_INVITATION, - PEER_ALREADY_IN_SESSION, - UNSUPPORTED_PROTOCOL -}; // Message handler modes enum HandlerMode { @@ -182,6 +185,9 @@ typedef std::list< ReceivedCommitEvent > CommitsQueue; // Message serialization typedef std::list< Glib::ustring > SerializedEventList; + + //typedef std::pair< Glib::ustring, InvitationResponses > Invitation_response_type; + //typedef std::list< Invitation_response_type > Invitation_responses_type; // Error handling -- someday // TODO: finish and integrate this //typedef boost::function< LmHandlerResult (unsigned int code) > ErrorHandlerFunctor; diff --git a/src/jabber_whiteboard/inkboard-document.cpp b/src/jabber_whiteboard/inkboard-document.cpp index 5f0d27e89..bf72d3c2a 100644 --- a/src/jabber_whiteboard/inkboard-document.cpp +++ b/src/jabber_whiteboard/inkboard-document.cpp @@ -74,9 +74,9 @@ InkboardDocument::terminateSession() } void -InkboardDocument::processInkboardEvent(Message::Wrapper mtype, unsigned int seqnum, Glib::ustring const& data) +InkboardDocument::processInkboardEvent(Message::Wrapper mtype, Glib::ustring const& data) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing Inkboard event: mtype=%s seqnum=%d data=%s\n", mtype, seqnum, data.c_str()); + g_log(NULL, G_LOG_LEVEL_DEBUG, "Processing Inkboard event: mtype=%s data=%s\n",mtype,data.c_str()); } bool @@ -87,7 +87,7 @@ InkboardDocument::sendProtocol(const Glib::ustring &destJid, Message::Wrapper wr "" "" "<%s>" - "%s" + "<%s />" "" "" " " diff --git a/src/jabber_whiteboard/inkboard-document.h b/src/jabber_whiteboard/inkboard-document.h index 0b0e5baed..71de75e19 100644 --- a/src/jabber_whiteboard/inkboard-document.h +++ b/src/jabber_whiteboard/inkboard-document.h @@ -16,7 +16,7 @@ #include "xml/document.h" #include "xml/simple-node.h" - +#include "jabber_whiteboard/defines.h" #include "jabber_whiteboard/keynode.h" #include "jabber_whiteboard/session-manager.h" @@ -24,6 +24,7 @@ namespace Inkscape { namespace Whiteboard { + class InkboardDocument : public XML::SimpleNode, public XML::Document { public: @@ -42,7 +43,7 @@ public: void startSessionNegotiation(); void terminateSession(); - void processInkboardEvent(Message::Wrapper mtype, unsigned int seqnum, Glib::ustring const& data); + void processInkboardEvent(Message::Wrapper mtype, Glib::ustring const& data); bool sendProtocol(const Glib::ustring &destJid, Message::Wrapper mwrapper, Message::Message message); diff --git a/src/jabber_whiteboard/invitation-handlers.cpp b/src/jabber_whiteboard/invitation-handlers.cpp deleted file mode 100644 index 1ddf479e0..000000000 --- a/src/jabber_whiteboard/invitation-handlers.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Whiteboard session manager - invitation handling methods - * - * Authors: - * David Yip - * Bob Jamison (Pedro port) - * - * Copyright (c) 2005 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include - -#include "util/ucompose.hpp" - -#include "document.h" -#include "desktop-handles.h" - -#include "jabber_whiteboard/inkboard-document.h" -#include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/invitation-confirm-dialog.h" -#include "jabber_whiteboard/defines.h" - -namespace Inkscape { - -namespace Whiteboard { - -bool -SessionManager::_checkInvitationQueue() -{ - int x, y; - Gdk::ModifierType mt; - Gdk::Display::get_default()->get_pointer(x, y, mt); - if (mt & GDK_BUTTON1_MASK) { - // The user is currently busy with an action. Defer invitation processing - // until the user is free. - return true; - } - - if (_pending_invitations.size() > 0) { - // There's an invitation to process; process it. - Glib::ustring from = _pending_invitations.front(); - - Glib::ustring primary = "" + String::ucompose(_("%1 has invited you to a whiteboard session."), from) + "\n\n"; - primary += String::ucompose(_("Do you wish to accept %1's whiteboard session invitation?"), from); - - InvitationConfirmDialog dialog(primary); - - dialog.add_button(_("Accept invitation"), ACCEPT_INVITATION); - dialog.add_button(_("Decline invitation"), DECLINE_INVITATION); - - InvitationResponses resp = static_cast< InvitationResponses >(dialog.run()); - - switch (resp) { - case ACCEPT_INVITATION: - { - SPDesktop* dt = createInkboardDesktop(from, State::WHITEBOARD_PEER); - InkboardDocument* idoc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); - //sendProtocol(from, Message::PROTOCOL, " "); - break; - } - case DECLINE_INVITATION: - { - break; - } - default: - //sendProtocol(from, Message::PROTOCOL, " "); - break; - } - - _pending_invitations.pop_front(); - } - - return true; -} - - -bool -SessionManager::_checkInvitationResponseQueue() -{ - int x, y; - Gdk::ModifierType mt; - Gdk::Display::get_default()->get_pointer(x, y, mt); - if (mt & GDK_BUTTON1_MASK) { - // The user is currently busy with an action. Defer invitation response processing - // until the user is free. - return true; - } - - if (_invitation_responses.size() > 0) { - Invitation_response_type response = _invitation_responses.front(); - - switch (response.second) { - case ACCEPT_INVITATION: - { - break; - } - case DECLINE_INVITATION: - { - Glib::ustring primary = String::ucompose(_("The user %1 has refused your whiteboard invitation.\n\n"), response.first); - - // TRANSLATORS: %1 is the peer whom refused our invitation, %2 is our Jabber identity. - Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as %2, and may send an invitation to %1 again, or you may send an invitation to a different user."), response.first, this->getClient().getJid()); - - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - dialog.run(); - terminateInkboardSession(response.first); - break; - } - case PEER_ALREADY_IN_SESSION: - break; - - case UNSUPPORTED_PROTOCOL: - { - Glib::ustring primary = String::ucompose(_("The user %1 is using an incompatible version of Inkboard.\n\n"), response.first); - - // TRANSLATORS: %1 is the peer whom refused our invitation, %2 is our Jabber identity. - Glib::ustring secondary = String::ucompose(_("Inkscape cannot connect to %1.\n\nYou are still connected to a Jabber server as %2."), response.first, this->getClient().getJid()); - - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - dialog.run(); - terminateInkboardSession(response.first); - break; - } - default: - break; - } - - _invitation_responses.pop_front(); - } - - return true; -} - -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/jabber_whiteboard/new-inkboard-document.cpp b/src/jabber_whiteboard/new-inkboard-document.cpp deleted file mode 100644 index 3e47554bb..000000000 --- a/src/jabber_whiteboard/new-inkboard-document.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * new-inkboard-document.h - * Functions to create new Inkboard documents, based off of sp_document_new / - * sp_file_new - * - * Authors: - * David Yip - * - * Copyright (c) 2006 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include -#include -#include - -#include "document.h" -#include "document-private.h" -#include "desktop.h" -#include "desktop-handles.h" -#include "interface.h" -#include "sp-namedview.h" -#include "desktop-handles.h" - -#include "gc-anchored.h" - -#include "ui/view/view-widget.h" - -#include "application/application.h" -#include "application/editor.h" - -#include "util/ucompose.hpp" - -#include "xml/node.h" -#include "xml/repr.h" - -#include "jabber_whiteboard/inkboard-document.h" -#include "jabber_whiteboard/new-inkboard-document.h" - -namespace Inkscape { - -namespace Whiteboard { - -SPDocument* -makeInkboardDocument(int code, gchar const* rootname, State::SessionType type, Glib::ustring const& to) -{ - SPDocument* doc; - InkboardDocument* rdoc = new InkboardDocument(g_quark_from_static_string("xml"), type, to); - rdoc->setAttribute("version", "1.0"); - rdoc->setAttribute("standalone", "no"); - XML::Node *comment = sp_repr_new_comment(" Created with Inkscape (http://www.inkscape.org/) "); - rdoc->appendChild(comment); - GC::release(comment); - - XML::Node* root = sp_repr_new(rootname); - rdoc->appendChild(root); - GC::release(root); - - Glib::ustring name = String::ucompose(_("Inkboard session (%1 to %2)"), SessionManager::instance().getClient().getJid(), to); - - doc = sp_document_create(rdoc, NULL, NULL, name.c_str(), TRUE); - return doc; -} - -// TODO: When the switchover to the new GUI is complete, this function should go away -// and be replaced with a call to Inkscape::NSApplication::Editor::createDesktop. -// It currently only exists to correctly mimic the desktop creation functionality -// in file.cpp. -// -// \see sp_file_new -SPDesktop* -makeInkboardDesktop(SPDocument* doc) -{ - SPDesktop* dt; - - if (NSApplication::Application::getNewGui()) { - dt = NSApplication::Editor::createDesktop(doc); - } else { - SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); - g_return_val_if_fail(dtw != NULL, NULL); - sp_document_unref(doc); - - sp_create_window(dtw, TRUE); - dt = static_cast(dtw->view); - sp_namedview_window_from_document(dt); - } - - return dt; -} - -} - -} diff --git a/src/jabber_whiteboard/new-inkboard-document.h b/src/jabber_whiteboard/new-inkboard-document.h deleted file mode 100644 index ead55ef70..000000000 --- a/src/jabber_whiteboard/new-inkboard-document.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * new-inkboard-document.h - * Functions to create new Inkboard documents, based off of sp_document_new / - * sp_file_new - * - * Authors: - * David Yip - * - * Copyright (c) 2006 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef __INKSCAPE_WHITEBOARD_NEW_DOCUMENT_H__ -#define __INKSCAPE_WHITEBOARD_NEW_DOCUMENT_H__ - -#include - -class SPDocument; -class SPDesktop; - -namespace Inkscape { - -namespace Whiteboard { - -SPDocument* makeInkboardDocument(int code, gchar const* rootname, State::SessionType type, Glib::ustring const& to); -SPDesktop* makeInkboardDesktop(SPDocument* doc); - -} - -} - -#endif diff --git a/src/jabber_whiteboard/pedrogui.cpp b/src/jabber_whiteboard/pedrogui.cpp index fc58dc349..64578f9af 100644 --- a/src/jabber_whiteboard/pedrogui.cpp +++ b/src/jabber_whiteboard/pedrogui.cpp @@ -2472,14 +2472,14 @@ void PedroGui::doShare(const DOMString &jid) { Inkscape::Whiteboard::SessionManager& sm = Inkscape::Whiteboard::SessionManager::instance(); - sm.doShare(jid, Inkscape::Whiteboard::State::WHITEBOARD_PEER); + sm.initialiseSession(jid, Inkscape::Whiteboard::State::WHITEBOARD_PEER); } void PedroGui::doGroupShare(const DOMString &groupJid) { Inkscape::Whiteboard::SessionManager& sm = Inkscape::Whiteboard::SessionManager::instance(); - sm.doShare(groupJid, Inkscape::Whiteboard::State::WHITEBOARD_MUC); + sm.initialiseSession(groupJid, Inkscape::Whiteboard::State::WHITEBOARD_MUC); } //################## diff --git a/src/jabber_whiteboard/session-manager.cpp b/src/jabber_whiteboard/session-manager.cpp index 856db5fe7..dd392c845 100644 --- a/src/jabber_whiteboard/session-manager.cpp +++ b/src/jabber_whiteboard/session-manager.cpp @@ -18,18 +18,31 @@ #include #include +#include "xml/node.h" +#include "xml/repr.h" + +#include "util/ucompose.hpp" + #include "xml/node-observer.h" #include "pedro/pedrodom.h" +#include "ui/view/view-widget.h" + +#include "application/application.h" +#include "application/editor.h" + +#include "document-private.h" +#include "interface.h" +#include "sp-namedview.h" #include "document.h" #include "desktop.h" #include "desktop-handles.h" +#include "jabber_whiteboard/invitation-confirm-dialog.h" #include "jabber_whiteboard/message-verifier.h" #include "jabber_whiteboard/session-manager.h" #include "jabber_whiteboard/inkboard-document.h" -#include "jabber_whiteboard/new-inkboard-document.h" #include "jabber_whiteboard/defines.h" #include "jabber_whiteboard/dialog/choose-desktop.h" @@ -59,11 +72,11 @@ SessionManager::instance() SessionManager::SessionManager() { - sequenceNumber = 0L; getClient().addXmppEventListener(*this); - this->_check_pending_invitations = Glib::signal_timeout().connect(sigc::mem_fun(*this, &SessionManager::_checkInvitationQueue), 50); - this->_check_invitation_responses = Glib::signal_timeout().connect(sigc::mem_fun(*this, &SessionManager::_checkInvitationResponseQueue), 50); + this->CheckPendingInvitations = + Glib::signal_timeout().connect(sigc::mem_fun( + *this, &SessionManager::checkInvitationQueue), 50); } SessionManager::~SessionManager() @@ -94,38 +107,21 @@ SessionManager::processXmppEvent(const Pedro::XmppEvent &event) { break; } + case Pedro::XmppEvent::EVENT_MUC_MESSAGE: case Pedro::XmppEvent::EVENT_MESSAGE: { g_warning("## SM message:%s\n", event.getFrom().c_str()); Pedro::Element *root = event.getDOM(); - if (root) - { - if (root->getTagAttribute("inkboard", "xmlns") == Vars::INKBOARD_XMLNS) - { - _processInkboardEvent(event); - } - } + if (root && root->getTagAttribute("wb", "xmlns") == Vars::INKBOARD_XMLNS) + processWhiteboardEvent(event); + break; } case Pedro::XmppEvent::EVENT_PRESENCE: { break; } - case Pedro::XmppEvent::EVENT_MUC_MESSAGE: - { - g_warning("## SM MUC message:%s\n", event.getFrom().c_str()); - Pedro::Element *root = event.getDOM(); - - if (root) - { - if (root->getTagAttribute("inkboard", "xmlns") == Vars::INKBOARD_XMLNS) - { - _processInkboardEvent(event); - } - } - break; - } case Pedro::XmppEvent::EVENT_MUC_JOIN: { break; @@ -152,14 +148,12 @@ SessionManager::processXmppEvent(const Pedro::XmppEvent &event) * \param type Type of the session; i.e. private message or group chat. */ void -SessionManager::doShare(Glib::ustring const& to, State::SessionType type) +SessionManager::initialiseSession(Glib::ustring const& to, State::SessionType type) { - SPDocument* doc = makeInkboardDocument(g_quark_from_static_string("xml"), "svg:svg", type, to); - if(doc == NULL) return; + SPDocument* doc = makeInkboardDocument(g_quark_from_static_string("xml"), "svg:svg", type, to); InkboardDocument* inkdoc = dynamic_cast< InkboardDocument* >(doc->rdoc); - if (inkdoc == NULL) return; - + if(inkdoc == NULL) return; if(type == State::WHITEBOARD_PEER) { @@ -176,273 +170,231 @@ SessionManager::doShare(Glib::ustring const& to, State::SessionType type) sp_desktop_document(desktop)->rdoc; inkdoc->root()->mergeFrom(old_doc->root(),"id"); } - } - }else{ return; } + }else { return; } + } - // Create a random session identifier - char * randomString = (char*) malloc (11); - for (int n=0; n<11; n++) - randomString[n]=rand()%26+'a'; - randomString[11]='\0'; + char * sessionId = createSessionId(10); - inkdoc->setSessionIdent(randomString); + inkdoc->setSessionIdent(sessionId); - _inkboards.push_back(Inkboard_record_type(randomString, inkdoc)); + addSession(WhiteboardRecord(sessionId, inkdoc)); inkdoc->startSessionNegotiation(); - /* - InkboardDocument* doc; - SPDesktop* dt; - - // Just create a new blank canvas for MUC sessions - if(type == State::WHITEBOARD_MUC) - { - dt = createInkboardDesktop(to, type); - - if (dt != NULL) - { - doc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); - - if (doc != NULL) - { - doc->startSessionNegotiation(); - } - } - - - // Let the user pick the document which to start a peer ro peer session - // with, or a blank one, then create a blank document, copy over the contents - // and initialise session - } else if (type== State::WHITEBOARD_PEER) { - ChooseDesktop dialog; - int result = dialog.run(); - - if(result == Gtk::RESPONSE_OK) - { - SPDesktop *desktop = dialog.getDesktop(); - dt = createInkboardDesktop(to, type); - - if (dt != NULL) - { - doc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); - - if (doc != NULL) - { - if(desktop != NULL) - { - Inkscape::XML::Document *old_doc = - sp_desktop_document(desktop)->rdoc; - doc->root()->mergeFrom(old_doc->root(),"id"); - } - - doc->startSessionNegotiation(); - } - } - } - } - */ -} - -/** - * Clone of sp_file_new and all related subroutines and functions, - * with appropriate modifications to use the Inkboard document class. - * - * \param to The JID to which this Inkboard document will be connected. - * \return A pointer to the created desktop, or NULL if a new desktop could not be created. - */ -SPDesktop* -SessionManager::createInkboardDesktop(Glib::ustring const& to, State::SessionType type) -{ -// Create document (sp_repr_document_new clone) - SPDocument* doc = makeInkboardDocument(g_quark_from_static_string("xml"), "svg:svg", type, to); - g_return_val_if_fail(doc != NULL, NULL); - - InkboardDocument* inkdoc = dynamic_cast< InkboardDocument* >(doc->rdoc); - if (inkdoc == NULL) { // this shouldn't ever happen... - return NULL; - } - -// Create desktop and attach document - SPDesktop *dt = makeInkboardDesktop(doc); - _inkboards.push_back(Inkboard_record_type(to, inkdoc)); - return dt; } void -SessionManager::terminateInkboardSession(Glib::ustring const& to) +SessionManager::terminateSession(Glib::ustring const& sessionId) { - std::cout << "Terminating Inkboard session to " << to << std::endl; - Inkboards_type::iterator i = _inkboards.begin(); - for(; i != _inkboards.end(); ++i) { - if ((*i).first == to) { + WhiteboardList::iterator i = whiteboards.begin(); + for(; i != whiteboards.end(); ++i) { + if ((*i).first == sessionId) break; - } } - if (i != _inkboards.end()) { - std::cout << "Erasing Inkboard session to " << to << std::endl; + if (i != whiteboards.end()) { (*i).second->terminateSession(); - _inkboards.erase(i); + whiteboards.erase(i); } } +void +SessionManager::addSession(WhiteboardRecord whiteboard) +{ + whiteboards.push_back(whiteboard); +} + InkboardDocument* -SessionManager::getInkboardSession(Glib::ustring const& to) +SessionManager::getInkboardSession(Glib::ustring const& sessionId) { - Inkboards_type::iterator i = _inkboards.begin(); - for(; i != _inkboards.end(); ++i) { - if ((*i).first == to) { + WhiteboardList::iterator i = whiteboards.begin(); + for(; i != whiteboards.end(); ++i) { + if ((*i).first == sessionId) { return (*i).second; } } return NULL; } + +/** + * Handles all incoming messages from pedro within a valid namespace, CONNECT_REQUEST messages + * are handled here, as they have no InkboardDocument to be handled from, all other messages + * are passed to their appropriate Inkboard document, which is identified by the 'session' + * attribute of the 'wb' element + * + */ void -SessionManager::_processInkboardEvent(Pedro::XmppEvent const& event) +SessionManager::processWhiteboardEvent(Pedro::XmppEvent const& event) { Pedro::Element* root = event.getDOM(); + if (root == NULL) { + g_warning("Received null DOM; ignoring message."); + return; + } - if (root == NULL) { - g_warning("Received null DOM; ignoring message."); - return; - } - - Pedro::DOMString type = root->getTagAttribute("inkboard", "type"); - Pedro::DOMString seq = root->getTagAttribute("inkboard", "seq"); - Pedro::DOMString protover = root->getTagAttribute("inkboard", "protocol"); + Pedro::DOMString session = root->getTagAttribute("wb", "session"); + Pedro::DOMString domwrapper = root->getFirstChild()->getFirstChild()->getFirstChild()->getName(); - if (type.empty() || seq.empty() || protover.empty()) { - g_warning("Received incomplete Inkboard message (missing type, protocol, or sequence number); ignoring message."); + if (session.empty()) { + g_warning("Received incomplete Whiteboard message, missing session identifier; ignoring message."); return; } - MessageType mtype = static_cast< MessageType >(atoi(type.c_str())); - - // Messages that deal with the creation and destruction of sessions should be handled - // here in the SessionManager. - // - // These events are listed below, along with rationale. - // - // - CONNECT_REQUEST_USER: when we begin to process this message, we will not have an - // Inkboard session available to send the message to. Therefore, this message needs - // to be handled by the SessionManager. - // - // - CONNECT_REQUEST_REFUSED_BY_PEER: this message means that the recipient of a - // private invitation refused the invitation. In this case, we need to destroy the - // Inkboard desktop, document, and session associated with that invitation. - // Destruction of these components seems to be more naturally done in the SessionManager - // than in the Inkboard document itself (especially since the document may be associated - // with multiple desktops). - // - // - UNSUPPORTED_PROTOCOL_VERSION: this message means that the recipient of an invitation - // does not support the version of the Inkboard protocol we are using. In this case, - // we have to destroy the Inkboard desktop, document, and session associated with that - // invitation. The rationale for doing it in the SessionManager is the same as that - // given above. - // - // - ALREADY_IN_SESSION: similar rationale to above. - // - // - DISCONNECTED_FROM_USER_SIGNAL: similar rationale to above. - // - // - // All other events can be handled inside an Inkboard session. - - // The message we are handling will have come from some Jabber ID. We need to verify - // that the Inkboard session associated with that JID is in the correct state for the - // incoming message (or, in some cases, that the session correctly exists / does not - // exist). - InkboardDocument* doc = getInkboardSession(event.getFrom()); - -// NOTE: This line refers to a class that hasn't been written yet -// MessageValidityTestResult res = MessageVerifier::verifyMessageValidity(event, mtype, doc); - - MessageValidityTestResult res = RESULT_INVALID; - /* - switch (res) { - case RESULT_VALID: - { - switch (mtype) { - case CONNECT_REQUEST: - default: - if (doc != NULL) { - unsigned int seqnum = atoi(seq.c_str()); - doc->processInkboardEvent(mtype, seqnum, event.getData()); - } - break; - } - break; - } - case RESULT_INVALID: - default: - // FIXME: better warning message - g_warning("Received message in invalid context."); - break; - } - */ + if(root->exists(Message::CONNECT_REQUEST)) + handleIncomingInvitation(Invitation(event.getFrom(),session)); + + else + { + Message::Wrapper wrapper = domwrapper.c_str(); + InkboardDocument* doc = getInkboardSession(session); + doc->processInkboardEvent(wrapper, event.getData()); + } } -void -SessionManager::_handleSessionEvent(Message::Wrapper mtype, Pedro::XmppEvent const& event) +char* +SessionManager::createSessionId(int size) { - /* - switch (mtype) { - case CONNECT_REQUEST: - _handleIncomingInvitation(event.getFrom()); - break; - case INVITATION_DECLINE: - _handleInvitationResponse(event.getFrom(), DECLINE_INVITATION); - break; - default: - break; - } - */ + // Create a random session identifier + char * randomString = (char*) malloc (size); + for (int n=0; nget_pointer(x, y, mt); + if (mt & GDK_BUTTON1_MASK) + return true; + + if (invitations.size() > 0) + { + // There's an invitation to process; process it. + Invitation invitation = invitations.front(); + Glib::ustring from = invitation.first; + Glib::ustring sessionId = invitation.second; + + Glib::ustring primary = + "" + + String::ucompose(_("%1 has invited you to a whiteboard session."), from) + + "\n\n" + + String::ucompose(_("Do you wish to accept %1's whiteboard session invitation?"), from); + + InvitationConfirmDialog dialog(primary); + + dialog.add_button(_("Accept invitation"), Dialog::ACCEPT_INVITATION); + dialog.add_button(_("Decline invitation"), Dialog::DECLINE_INVITATION); + + Dialog::DialogReply reply = static_cast< Dialog::DialogReply >(dialog.run()); + + + SPDocument* doc = makeInkboardDocument(g_quark_from_static_string("xml"), "svg:svg", State::WHITEBOARD_PEER, from); + InkboardDocument* inkdoc = dynamic_cast< InkboardDocument* >(doc->rdoc); + if(inkdoc == NULL) return true; + + addSession(WhiteboardRecord(sessionId, inkdoc)); + + switch (reply) { + + case Dialog::ACCEPT_INVITATION:{ + inkdoc->sendProtocol(from, Message::PROTOCOL,Message::ACCEPT_INVITATION); + makeInkboardDesktop(doc); + break; } + + case Dialog::DECLINE_INVITATION: default: { + inkdoc->sendProtocol(from, Message::PROTOCOL,Message::DECLINE_INVITATION); + terminateSession(sessionId); + break; } + } + + invitations.pop_front(); + + } + + return true; +} + +//######################################################################### +//# HELPER FUNCTIONS +//######################################################################### + +SPDocument* +makeInkboardDocument(int code, gchar const* rootname, State::SessionType type, Glib::ustring const& to) { - // only handle one response per invitation sender - // - // TODO: this could have one huge bug: say that Alice sends an invite to Bob, but - // Bob is doing something else at the moment and doesn't want to get in an Inkboard - // session. Eve intercepts Bob's "reject invitation" message and passes a - // "accept invitation" message to Alice that comes before Bob's "reject invitation" - // message. - // - // Does XMPP prevent this sort of attack? Need to investigate that. - if (std::find_if(_invitation_responses.begin(), _invitation_responses.end(), CheckInvitationSender(from)) != _invitation_responses.end()) { - return; - } - - // We need to do the invitation confirm/deny dialog elsewhere -- - // when this method is called, we're still executing in Pedro's context, - // which causes issues when we run a dialog main loop. - // - // The invitation handling is done in a poller timeout that executes approximately - // every 50ms. It calls _checkInvitationResponseQueue. - _invitation_responses.push_back(Invitation_response_type(from, resp)); + SPDocument* doc; + + InkboardDocument* rdoc = new InkboardDocument(g_quark_from_static_string("xml"), type, to); + rdoc->setAttribute("version", "1.0"); + rdoc->setAttribute("standalone", "no"); + XML::Node *comment = sp_repr_new_comment(" Created with Inkscape (http://www.inkscape.org/) "); + rdoc->appendChild(comment); + GC::release(comment); + + XML::Node* root = sp_repr_new(rootname); + rdoc->appendChild(root); + GC::release(root); + + Glib::ustring name = String::ucompose( + _("Inkboard session (%1 to %2)"), SessionManager::instance().getClient().getJid(), to); + doc = sp_document_create(rdoc, NULL, NULL, name.c_str(), TRUE); + g_return_val_if_fail(doc != NULL, NULL); + + return doc; +} + +// TODO: When the switchover to the new GUI is complete, this function should go away +// and be replaced with a call to Inkscape::NSApplication::Editor::createDesktop. +// It currently only exists to correctly mimic the desktop creation functionality +// in file.cpp. +// +// \see sp_file_new +SPDesktop* +makeInkboardDesktop(SPDocument* doc) +{ + SPDesktop* dt; + + if (NSApplication::Application::getNewGui()) + dt = NSApplication::Editor::createDesktop(doc); + + else + { + SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); + g_return_val_if_fail(dtw != NULL, NULL); + sp_document_unref(doc); + + sp_create_window(dtw, TRUE); + dt = static_cast(dtw->view); + sp_namedview_window_from_document(dt); + } + + return dt; } } // namespace Whiteboard diff --git a/src/jabber_whiteboard/session-manager.h b/src/jabber_whiteboard/session-manager.h index 18f6239bb..1ba626685 100644 --- a/src/jabber_whiteboard/session-manager.h +++ b/src/jabber_whiteboard/session-manager.h @@ -18,6 +18,8 @@ #include #include +#include "desktop.h" + #include "jabber_whiteboard/pedrogui.h" #include "jabber_whiteboard/message-queue.h" #include "jabber_whiteboard/defines.h" @@ -25,83 +27,45 @@ #include "gc-alloc.h" +class SPDocument; class SPDesktop; + namespace Inkscape { namespace Whiteboard { -enum SessionType { - INKBOARD_PRIVATE, - INKBOARD_MUC -}; - -class SessionManager; class InkboardDocument; -class SessionManager : public Pedro::XmppEventListener { +typedef Glib::ustring from,sessionId; +typedef std::pair< Glib::ustring, InkboardDocument* > WhiteboardRecord; +typedef std::vector< WhiteboardRecord, GC::Alloc< WhiteboardRecord, GC::MANUAL > > WhiteboardList; + +typedef std::pair< from, sessionId > Invitation; +typedef std::list< Invitation > InvitationList; + +class SessionManager : public Pedro::XmppEventListener +{ + public: - /** - * - */ SessionManager(); - /** - * - */ virtual ~SessionManager(); - static void showClient(); - static SessionManager& instance(); + static void showClient(); + static SessionManager& instance(); - /** - * - */ virtual Pedro::XmppClient &getClient() { return gui.client; } /** - * + * Handles all incoming XMPP events associated with this document + * apart from CONNECT_REQUEST, which is handled in SessionManager */ virtual void processXmppEvent(const Pedro::XmppEvent &event); - /** - * The session handling has been broken out into a subclass of XML::Session. See - * Whiteboard::InkboardSession and Whiteboard::InkboardDocument, both of which - * are still under heavy construction. Don't expect them to work just yet. - * - * This (should) allow us to substitute an InkboardDocument for an - * XML::SimpleDocument (InkboardDocument uses InkboardSession), which, I think, should - * lead to a very clean way of integrating Inkboard. It should also - * give us a cleaner way of handling node tracking. Finally, - * it'll let us experiment with data models that may be more appropriate for Inkboard. - * - * SessionManager still manages sessions insofar as it receives XMPP data from Pedro and - * sends it off to the correct InkboardSession. I'd like to have it still manage - * user sessions, which is what the user sees; however, that can be confusing from - * a programmer's standpoint. This class might therefore need to be renamed - * or something. - * - * Creation of an Inkboard session should be handled in some fashion similar - * to this: - * - * (1) The user chooses a chat room or user with which she wants to share a whiteboard. - * - * (2) This invokes the appropriate doShare() method in Pedro's GUI. - * - * (3) doShare() invokes code to create a new Inkscape desktop with a blank document. - * This desktop will use InkboardDocument (and hence InkboardSession) for transaction - * management. - * - * (4) Inkboard setup and operation proceeds as it did in the Loudmouth-based code. - * - * (3) and (4) will probably need tweaking (for example, it's probably a bad idea to - * open up a new desktop if an invitation is refused). Actually, really, nothing - * here is set in stone. Feel free to modify. -- dwyip 2005-11-21 - * - */ /** * Initiates a shared session with a user or conference room. @@ -109,29 +73,22 @@ public: * \param to The recipient to which this desktop will be linked, specified as a JID. * \param type Type of the session; i.e. private message or group chat. */ - virtual void doShare(Glib::ustring const& to, State::SessionType type); + virtual void initialiseSession(Glib::ustring const& to, State::SessionType type); /** - * Creates a new desktop with an InkboardDocument. - * - * An InkboardDocument (and hence desktop) - * is identified by the recipient of the document, be it a - * conference room or another user. If an existing document is found, it will be - * returned. + * Terminates an Inkboard session to a given recipient. If the session to be + * terminated does not exist, does nothing. * - * \param to The recipient to which this desktop will be linked, specified as a JID. - * \param type Type of the session; i.e. private message or group chat. - * \return A pointer to the created SPDesktop. + * \param sessionId The session identifier to be terminated. */ - virtual SPDesktop* createInkboardDesktop(Glib::ustring const& to, State::SessionType type); + virtual void terminateSession(Glib::ustring const& sessionId); /** - * Terminates an Inkboard session to a given recipient. If the session to be - * terminated does not exist, does nothing. + * Adds a session to whiteboard * - * \param to The recipient JID identifying the session to be terminated. + * \param sessionId The session identifier to be terminated. */ - virtual void terminateInkboardSession(Glib::ustring const& to); + virtual void addSession(WhiteboardRecord whiteboard); /** * Locates an Inkboard session by recipient JID. @@ -142,58 +99,29 @@ public: */ InkboardDocument* getInkboardSession(Glib::ustring const& to); - void operator=(XmppEventListener const& other) { - } + void operator=(XmppEventListener const& other) {} + private: - - // types - typedef std::pair< Glib::ustring, InkboardDocument* > Inkboard_record_type; - typedef std::vector< Inkboard_record_type, GC::Alloc< Inkboard_record_type, GC::MANUAL > > Inkboards_type; - - typedef std::list< Glib::ustring > Pending_invitations_type; - - typedef std::pair< Glib::ustring, InvitationResponses > Invitation_response_type; - typedef std::list< Invitation_response_type > Invitation_responses_type; - - // functors - struct CheckInvitationSender { - public: - CheckInvitationSender(Glib::ustring const& x) : x(x) { } - ~CheckInvitationSender() { } - - bool operator()(SessionManager::Invitation_response_type const& y) const { - return (x == y.first); - } - private: - Glib::ustring const& x; - }; - - // objects - Pedro::PedroGui gui; - SendMessageQueue sendMessageQueue; - ReceiveMessageQueue receiveMessageQueue; - - // members - unsigned long sequenceNumber; - Inkboards_type _inkboards; - Pending_invitations_type _pending_invitations; - Invitation_responses_type _invitation_responses; - - sigc::connection _check_pending_invitations; - sigc::connection _check_invitation_responses; - - // methods - void _processInkboardEvent(Pedro::XmppEvent const& event); - void _handleSessionEvent(Message::Wrapper mtype, Pedro::XmppEvent const& event); - void _handleIncomingInvitation(Glib::ustring const& from); - void _handleInvitationResponse(Glib::ustring const& from, InvitationResponses resp); - - // methods handled externally - bool _checkInvitationQueue(); - bool _checkInvitationResponseQueue(); + + Pedro::PedroGui gui; + WhiteboardList whiteboards; + InvitationList invitations; + sigc::connection CheckPendingInvitations; + + void processWhiteboardEvent(Pedro::XmppEvent const& event); + + void handleIncomingInvitation(Invitation invitation); + + bool checkInvitationQueue(); + + char* createSessionId(int size); + }; +SPDocument* makeInkboardDocument(int code, gchar const* rootname, State::SessionType type, Glib::ustring const& to); +SPDesktop* makeInkboardDesktop(SPDocument* doc); + } // namespace Whiteboard } // namespace Inkscape -- 2.30.2