diff options
| author | daleharvey <daleharvey@users.sourceforge.net> | 2006-06-23 13:15:16 +0000 |
|---|---|---|
| committer | daleharvey <daleharvey@users.sourceforge.net> | 2006-06-23 13:15:16 +0000 |
| commit | fcadbfb31e9e8bd463a16369e3de2ec96a413a6a (patch) | |
| tree | 41c3f39b304687f41ec169c8aa95a5984aa5910f /src/jabber_whiteboard/session-manager.cpp | |
| parent | quick g_message UndoStackObserver for tracing calls to the undo system (diff) | |
| download | inkscape-fcadbfb31e9e8bd463a16369e3de2ec96a413a6a.tar.gz inkscape-fcadbfb31e9e8bd463a16369e3de2ec96a413a6a.zip | |
manually merging the INKBOARD_PEDRO branch into trunk
(bzr r1268)
Diffstat (limited to 'src/jabber_whiteboard/session-manager.cpp')
| -rw-r--r-- | src/jabber_whiteboard/session-manager.cpp | 1449 |
1 files changed, 329 insertions, 1120 deletions
diff --git a/src/jabber_whiteboard/session-manager.cpp b/src/jabber_whiteboard/session-manager.cpp index 9ead6b60b..f8ca94612 100644 --- a/src/jabber_whiteboard/session-manager.cpp +++ b/src/jabber_whiteboard/session-manager.cpp @@ -3,1230 +3,439 @@ * * Authors: * David Yip <yipdw@rose-hulman.edu> + * Bob Jamison (Pedro port) * * Copyright (c) 2005 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ -/* -#include "inkscape.h" -*/ - -#include <cstring> +#include <functional> +#include <algorithm> +#include <iostream> +#include <gtkmm.h> #include <glibmm/i18n.h> -#include <gtkmm/dialog.h> -#include <gtkmm/messagedialog.h> -#include <gtkmm/filechooserdialog.h> -#include <gtkmm/stock.h> - -#include "gc-anchored.h" -#include "prefs-utils.h" - -#include "xml/repr.h" #include "xml/node-observer.h" -#include "util/ucompose.hpp" - -#include "message-context.h" -#include "message-stack.h" -#include "desktop-handles.h" #include "document.h" -#include "document-private.h" -#include "verbs.h" +#include "desktop.h" +#include "desktop-handles.h" -#include "jabber_whiteboard/defines.h" -#include "jabber_whiteboard/typedefs.h" -#include "jabber_whiteboard/deserializer.h" -#include "jabber_whiteboard/message-utilities.h" -#include "jabber_whiteboard/message-handler.h" -#include "jabber_whiteboard/node-tracker.h" -#include "jabber_whiteboard/jabber-handlers.h" -#include "jabber_whiteboard/callbacks.h" -#include "jabber_whiteboard/chat-handler.h" -#include "jabber_whiteboard/session-file.h" -#include "jabber_whiteboard/session-file-player.h" +#include "jabber_whiteboard/message-verifier.h" #include "jabber_whiteboard/session-manager.h" -#include "jabber_whiteboard/message-aggregator.h" -#include "jabber_whiteboard/undo-stack-observer.h" -#include "jabber_whiteboard/serializer.h" - -//#include "jabber_whiteboard/pedro/pedroxmpp.h" +#include "jabber_whiteboard/inkboard-document.h" +#include "jabber_whiteboard/new-inkboard-document.h" -#include "jabber_whiteboard/message-node.h" -#include "jabber_whiteboard/message-queue.h" +#define INKBOARD_XMLNS "http://inkscape.org/inkboard" namespace Inkscape { namespace Whiteboard { -SessionData::SessionData(SessionManager *sm) -{ - this->_sm = sm; - this->recipient = NULL; - this->connection = NULL; - this->ssl = NULL; - this->ignoreFurtherSSLErrors = false; - this->send_queue = new SendMessageQueue(sm); - this->sequence_number = 1; -} +//######################################################################### +//# S E S S I O N M A N A G E R +//######################################################################### -SessionData::~SessionData() -{ - this->receive_queues.clear(); +SessionManager *sessionManagerInstance = NULL; - if (this->send_queue) { - delete this->send_queue; - } +void SessionManager::showClient() +{ + SessionManager::instance().gui.show(); } -SessionManager::SessionManager(::SPDesktop *desktop) +SessionManager& +SessionManager::instance() { - - // Initialize private members to NULL to facilitate deletion in destructor - this->_myDoc = NULL; - this->session_data = NULL; - this->_myCallbacks = NULL; - this->_myTracker = NULL; - this->_myChatHandler = NULL; - this->_mySessionFile = NULL; - this->_mySessionPlayer = NULL; - this->_myMessageHandler = NULL; - this->_myUndoObserver = NULL; - this->_mySerializer = NULL; - this->_myDeserializer = NULL; - - this->setDesktop(desktop); - - if (this->_myDoc == NULL) { - g_error("Initializing SessionManager on null document object!"); - } - - -#ifdef WIN32 - //# lm_initialize() must be called before any network code -/* - if (!lm_initialize_called) { - lm_initialize(); - lm_initialize_called = true; - } -*/ -#endif - - this->_setVerbSensitivity(INITIAL); + if (!sessionManagerInstance) + sessionManagerInstance = new SessionManager(); + return *sessionManagerInstance; } -SessionManager::~SessionManager() +SessionManager::SessionManager() { + sequenceNumber = 0L; + getClient().addXmppEventListener(*this); - if (this->session_data) { - if (this->session_data->status[IN_WHITEBOARD]) { - // also calls closeSession - this->disconnectFromDocument(); - } - this->disconnectFromServer(); - - if (this->session_data->status[LOGGED_IN]) { - // TODO: unref message handlers - } - } - - if (this->_mySessionFile) { - delete this->_mySessionPlayer; - delete this->_mySessionFile; - } - - delete this->_myChatHandler; - - - // Deletion of _myTracker is done in closeSession; - // no need to do it here. - - // Deletion is handled separately from session teardown and server disconnection - // because some teardown methods (e.g. closeSession) require access to members that we will - // be deleting. Separating deletion from teardown means that we do not have - // to worry (as much) about proper ordering of the teardown sequence. (We still need - // to ensure that destructors in each object being deleted have access to all the - // members they need, though.) - - // Stop dispatchers - if (this->_myCallbacks) { - this->stopSendQueueDispatch(); - this->stopReceiveQueueDispatch(); - delete this->_myCallbacks; - } - - delete this->_myMessageHandler; - - delete this->session_data; - - Inkscape::GC::release(this->_myDoc); - + 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); } -void -SessionManager::setDesktop(::SPDesktop* desktop) +SessionManager::~SessionManager() { - this->_myDesktop = desktop; - if (this->_myDoc != NULL) { - Inkscape::GC::release(this->_myDoc); - } - if (sp_desktop_document(desktop) != NULL) { - this->_myDoc = sp_desktop_document(desktop); - Inkscape::GC::anchor(this->_myDoc); - } + getClient().removeXmppEventListener(*this); + getClient().disconnect(); } -int -SessionManager::initializeConnection(Glib::ustring const& server, Glib::ustring const& port, bool usessl) +unsigned long SessionManager::getSequenceNumber() { - GError* error = NULL; - - if (!this->session_data) { - this->session_data = new SessionData(this); - } - - if (!this->_myMessageHandler) { - this->_myMessageHandler = new MessageHandler(this); - } - - // Connect to server - // We need to check to see if this object already exists, because - // the user may be reusing an old connection that failed due to e.g. - // authentication failure. - if (this->session_data->connection) { - lm_connection_close(this->session_data->connection, &error); - lm_connection_unref(this->session_data->connection); - } - - this->session_data->connection = lm_connection_new(server.c_str()); - this->session_data->chat_server = server; - - lm_connection_set_port(this->session_data->connection, atoi(port.c_str())); - - g_log(NULL, G_LOG_LEVEL_DEBUG, "Opened connection to %s at port %s. Connecting...", - server.c_str(), port.c_str()); - - if (usessl) { - if (lm_ssl_is_supported()) { - this->session_data->ssl = lm_ssl_new(NULL, ssl_error_handler, reinterpret_cast< gpointer >(this), NULL); - - lm_ssl_ref(this->session_data->ssl); - } else { - return SSL_INITIALIZATION_ERROR; - } - lm_connection_set_ssl(this->session_data->connection, this->session_data->ssl); - } - - // Send authorization - //lm_connection_set_jid(this->session_data->connection, jid.c_str()); - - // TODO: - // Asynchronous connection and authentication would be nice, - // but it's a huge mess of mixing C callbacks and C++ method calls. - // I've tried to do it and only managed to severely destabilize the Jabber - // server connection routines. - // - // This, of course, is an invitation to anyone more capable than me - // to convert this from synchronous to asynchronous Loudmouth calls. - if (!lm_connection_open_and_block(this->session_data->connection, &error)) { - if (error != NULL) { - std::cout << "Failed to open: " << error->message << std::endl; - } - return FAILED_TO_CONNECT; - } - - //On successful connect, remember info - prefs_set_string_attribute("whiteboard.server", "name", server.c_str()); - prefs_set_string_attribute("whiteboard.server", "port", port.c_str()); - prefs_set_int_attribute("whiteboard.server", "ssl", (usessl) ? 1 : 0); - - return CONNECT_SUCCESS; + return sequenceNumber++; } -std::vector<Glib::ustring> -SessionManager::getRegistrationInfo() -{ - GError* error = NULL; - xmlDoc *doc = NULL; - xmlNode *root_element = NULL; - xmlNode *cur_node = NULL; - - LmMessage *reply,*request; - LmMessageNode *n; - - std::vector<Glib::ustring> registerelements; - - request = lm_message_new_with_sub_type(NULL,LM_MESSAGE_TYPE_IQ,LM_MESSAGE_SUB_TYPE_GET); - n = lm_message_node_add_child (request->node, "query", NULL); - lm_message_node_set_attributes (n, "xmlns", "jabber:iq:register", NULL); - - reply = lm_connection_send_with_reply_and_block(this->session_data->connection, request, &error); - if (error != NULL) { - return registerelements; - } - - n = lm_message_get_node(reply); - - Glib::ustring content = static_cast< Glib::ustring >(lm_message_node_to_string(lm_message_node_get_child(n,"query"))); - doc = xmlReadMemory(content.c_str(),content.size(), "noname.xml", NULL, 0); - - if (doc == NULL) { - g_warning("Failed to parse document\n"); - return registerelements; - } - - root_element = xmlDocGetRootElement(doc); - - for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { - Glib::ustring name = static_cast< Glib::ustring >((char const *)cur_node->name); - if (cur_node->type == XML_ELEMENT_NODE && name != "instructions" - && name != "username" && name != "password" ) { - registerelements.push_back(name); - } - } - - xmlFreeDoc(doc); - xmlCleanupParser(); - - return registerelements; +bool +SessionManager::send(const Glib::ustring &destJid, + const MessageType type, + const Glib::ustring &data) +{ + Pedro::DOMString xmlData = Pedro::Parser::encode(data); + char *fmt= + "<message type='chat' from='%s' to='%s' id='ink_%d'>" + "<inkboard xmlns='%s' " + "protocol='%d' type='%d' seq='%d'><x:inkboard-data>%s</x:inkboard-data></inkboard>" + "<body></body>" + "</message>"; + if (!getClient().write(fmt, + getClient().getJid().c_str(), + destJid.c_str(), + getClient().getMsgId(), + INKBOARD_XMLNS, + 2, + (MessageType)type, + getSequenceNumber(), + xmlData.c_str() + )) + { + return false; + } + + return true; } -int -SessionManager::registerWithServer(Glib::ustring const& username, Glib::ustring const& pw, - std::vector<Glib::ustring> key, std::vector<Glib::ustring> val) -{ - - GError* error = NULL; - - LmMessage *request,*reply; - LmMessageNode *n; - - request = lm_message_new_with_sub_type(NULL,LM_MESSAGE_TYPE_IQ,LM_MESSAGE_SUB_TYPE_SET); - n = lm_message_node_add_child (request->node, "query", NULL); - lm_message_node_set_attributes (n, "xmlns", "jabber:iq:register", NULL); - - lm_message_node_add_child(n,"username",username.c_str()); - lm_message_node_add_child(n,"password",pw.c_str()); - - for(unsigned i=0;i<key.size();i++) - { - lm_message_node_add_child(n, (key[i]).c_str(),(val[i]).c_str()); - } - - - reply = lm_connection_send_with_reply_and_block(this->session_data->connection, request, &error); - if (error != NULL || lm_message_get_type(reply) != LM_MESSAGE_SUB_TYPE_RESULT) { - return INVALID_AUTH; - } - - this->session_data->jid = username + "@" + (this->session_data->chat_server.c_str()) + "/" + RESOURCE_NAME; - - prefs_set_string_attribute("whiteboard.server", "username", username.c_str()); - - return this->finaliseConnection(); +bool +SessionManager::sendGroup(const Glib::ustring &groupJid, + const MessageType type, + const Glib::ustring &data) +{ + Pedro::DOMString xmlData = Pedro::Parser::encode(data); + char *fmt= + "<message type='groupchat' from='%s' to='%s' id='ink_%d'>" + "<inkboard xmlns='%s' " + "protocol='%d' type='%d' seq='%d'><x:inkboard-data>%s</x:inkboard-data></inkboard>" + "<body></body>" + "</message>"; + if (!getClient().write(fmt, + getClient().getJid().c_str(), + groupJid.c_str(), + getClient().getMsgId(), + INKBOARD_XMLNS, + 2, + type, + getSequenceNumber(), + xmlData.c_str() + )) + { + return false; + } + + return true; } -int -SessionManager::connectToServer(Glib::ustring const& server, Glib::ustring const& port, - Glib::ustring const& entered_username, Glib::ustring const& pw, bool usessl) -{ - GError* error = NULL; - Glib::ustring username; - Glib::ustring jid; - - initializeConnection(server,port,usessl); - - Glib::ustring::size_type atPos = entered_username.find('@'); - - if (atPos != Glib::ustring::npos) { - jid += entered_username; - username = entered_username.substr(0, atPos); - } else { - jid += entered_username + "@" + server + "/" + RESOURCE_NAME; - username = entered_username; - } - - this->session_data->jid = jid; - - if (!lm_connection_authenticate_and_block(this->session_data->connection, username.c_str(), pw.c_str(), RESOURCE_NAME, &error)) { - if (error != NULL) { - g_warning("Failed to authenticate: %s", error->message); - } - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - this->session_data->connection = NULL; - return INVALID_AUTH; - } - - g_log(NULL, G_LOG_LEVEL_DEBUG, "Successfully authenticated."); - - return this->finaliseConnection(); +void +SessionManager::processXmppEvent(const Pedro::XmppEvent &event) +{ + int type = event.getType(); + + switch (type) { + case Pedro::XmppEvent::EVENT_STATUS: + { + break; + } + case Pedro::XmppEvent::EVENT_ERROR: + { + break; + } + case Pedro::XmppEvent::EVENT_CONNECTED: + { + break; + } + case Pedro::XmppEvent::EVENT_DISCONNECTED: + { + break; + } + case Pedro::XmppEvent::EVENT_MESSAGE: + { + printf("## SM message:%s\n", event.getFrom().c_str()); + Pedro::Element *root = event.getDOM(); + + if (root) + { + if (root->getTagAttribute("inkboard", "xmlns") == + INKBOARD_XMLNS) + { + _processInkboardEvent(event); + } + } + break; + } + case Pedro::XmppEvent::EVENT_PRESENCE: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_MESSAGE: + { + printf("## SM MUC message:%s\n", event.getFrom().c_str()); + Pedro::Element *root = event.getDOM(); + if (root) + { + if (root->getTagAttribute("inkboard", "xmlns") == + INKBOARD_XMLNS) + { + _processInkboardEvent(event); + } + } + break; + } + case Pedro::XmppEvent::EVENT_MUC_JOIN: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_LEAVE: + { + break; + } + case Pedro::XmppEvent::EVENT_MUC_PRESENCE: + { + break; + } + default: + { + break; + } + } } -int -SessionManager::finaliseConnection() +/** + * Initiates a shared session with a user or conference room. + * + * \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. + */ +void +SessionManager::doShare(Glib::ustring const& to, SessionType type) { - - GError* error = NULL; - LmMessage* m; - LmMessageHandler* mh; - - // Register message handler for presence messages - mh = lm_message_handler_new((LmHandleMessageFunction)presence_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_PRESENCE, LM_HANDLER_PRIORITY_NORMAL); - - // Register message handler for stream error messages - mh = lm_message_handler_new((LmHandleMessageFunction)stream_error_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_STREAM_ERROR, LM_HANDLER_PRIORITY_NORMAL); - - // Register message handler for chat messages - mh = lm_message_handler_new((LmHandleMessageFunction)default_handler, reinterpret_cast< gpointer >(this->_myMessageHandler), NULL); - lm_connection_register_message_handler(this->session_data->connection, mh, LM_MESSAGE_TYPE_MESSAGE, LM_HANDLER_PRIORITY_NORMAL); - - // Send presence message to server - m = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_NOT_SET); - if (!lm_connection_send(this->session_data->connection, m, &error)) { - if (error != NULL) { - g_warning("Presence message could not be sent: %s", error->message); + SPDesktop* dt = createInkboardDesktop(to, type); + if (dt != NULL) { + InkboardDocument* doc = dynamic_cast< InkboardDocument* >(sp_desktop_document(dt)->rdoc); + if (doc != NULL) { + doc->startSessionNegotiation(); } - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - this->session_data->connection = NULL; - return FAILED_TO_CONNECT; } - - this->session_data->status.set(LOGGED_IN, 1); - - this->_myCallbacks = new Callbacks(this); - - lm_message_unref(m); - - this->_setVerbSensitivity(ESTABLISHED_CONNECTION); - - return CONNECT_SUCCESS; } -LmSSLResponse -SessionManager::handleSSLError(LmSSL* ssl, LmSSLStatus status) +/** + * 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, SessionType type) { - if (this->session_data->ignoreFurtherSSLErrors) { - return LM_SSL_RESPONSE_CONTINUE; - } - - Glib::ustring msg; - - // TODO: It'd be nice to provide the user with additional information in some cases, - // like fingerprints, hostname, etc. - switch(status) { - case LM_SSL_STATUS_NO_CERT_FOUND: - msg = _("No SSL certificate was found."); - break; - case LM_SSL_STATUS_UNTRUSTED_CERT: - msg = _("The SSL certificate provided by the Jabber server is untrusted."); - break; - case LM_SSL_STATUS_CERT_EXPIRED: - msg = _("The SSL certificate provided by the Jabber server is expired."); - break; - case LM_SSL_STATUS_CERT_NOT_ACTIVATED: - msg = _("The SSL certificate provided by the Jabber server has not been activated."); - break; - case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH: - msg = _("The SSL certificate provided by the Jabber server contains a hostname that does not match the Jabber server's hostname."); - break; - case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: - msg = _("The SSL certificate provided by the Jabber server contains an invalid fingerprint."); - break; - case LM_SSL_STATUS_GENERIC_ERROR: - msg = _("An unknown error occurred while setting up the SSL connection."); - break; - } +// 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); - // TRANSLATORS: %1 is the message that describes the specific error that occurred when - // establishing the SSL connection. - Glib::ustring mainmsg = String::ucompose(_("<span weight=\"bold\" size=\"larger\">%1</span>\n\nDo you wish to continue connecting to the Jabber server?"), msg); - - Gtk::MessageDialog dlg(mainmsg, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, false); - dlg.add_button(_("Continue connecting and ignore further errors"), 0); - dlg.add_button(_("Continue connecting, but warn me of further errors"), 1); - dlg.add_button(_("Cancel connection"), 2); - - switch(dlg.run()) { - case 0: - this->session_data->ignoreFurtherSSLErrors = true; - /* FALL-THROUGH */ - case 1: - return LM_SSL_RESPONSE_CONTINUE; + InkboardDocument* inkdoc = dynamic_cast< InkboardDocument* >(doc->rdoc); + if (inkdoc == NULL) { // this shouldn't ever happen... + return NULL; + } - default: - return LM_SSL_RESPONSE_STOP; - } +// Create desktop and attach document + SPDesktop *dt = makeInkboardDesktop(doc); + _inkboards.push_back(Inkboard_record_type(to, inkdoc)); + return dt; } void -SessionManager::disconnectFromServer() -{ - if (this->session_data->connection) - { - GError* error = NULL; - - LmMessage *m; - this->disconnectFromDocument(); - m = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNAVAILABLE); - if (!lm_connection_send(this->session_data->connection, m, &error)) { - g_warning("Could not send unavailable presence message: %s", error->message); - } - - lm_message_unref(m); - lm_connection_close(this->session_data->connection, NULL); - lm_connection_unref(this->session_data->connection); - if (this->session_data->ssl) { - lm_ssl_unref(this->session_data->ssl); - } +SessionManager::terminateInkboardSession(Glib::ustring const& to) +{ + std::cout << "Terminating Inkboard session to " << to << std::endl; + Inkboards_type::iterator i = _inkboards.begin(); + for(; i != _inkboards.end(); ++i) { + if ((*i).first == to) { + break; + } + } - this->session_data->connection = NULL; - this->session_data->ssl = NULL; - this->_setVerbSensitivity(INITIAL); - } + if (i != _inkboards.end()) { + std::cout << "Erasing Inkboard session to " << to << std::endl; + (*i).second->terminateSession(); + _inkboards.erase(i); + } } -void -SessionManager::disconnectFromDocument() +InkboardDocument* +SessionManager::getInkboardSession(Glib::ustring const& to) { - if (this->session_data->status[IN_WHITEBOARD] || !this->session_data->status[IN_CHATROOM]) { - this->sendMessage(DISCONNECTED_FROM_USER_SIGNAL, 0, "", this->session_data->recipient, false); - } - this->closeSession(); - this->_setVerbSensitivity(DISCONNECTED_FROM_SESSION); + Inkboards_type::iterator i = _inkboards.begin(); + for(; i != _inkboards.end(); ++i) { + if ((*i).first == to) { + return (*i).second; + } + } + return NULL; } void -SessionManager::closeSession() +SessionManager::_processInkboardEvent(Pedro::XmppEvent const& event) { + Pedro::Element* root = event.getDOM(); - if (this->session_data->status[IN_WHITEBOARD]) { - this->session_data->status.set(IN_WHITEBOARD, 0); - this->session_data->receive_queues.clear(); - this->session_data->send_queue->clear(); - this->stopSendQueueDispatch(); - this->stopReceiveQueueDispatch(); - } - - if (this->_myUndoObserver) { - this->_myDoc->removeUndoObserver(*this->_myUndoObserver); + if (root == NULL) { + g_warning("Received null DOM; ignoring message."); + return; } - delete this->_myUndoObserver; - delete this->_mySerializer; - delete this->_myDeserializer; - - this->_myUndoObserver = NULL; - this->_mySerializer = NULL; - this->_myDeserializer = NULL; - - if (this->_myTracker) { - delete this->_myTracker; - this->_myTracker = NULL; - } + Pedro::DOMString type = root->getTagAttribute("inkboard", "type"); + Pedro::DOMString seq = root->getTagAttribute("inkboard", "seq"); + Pedro::DOMString protover = root->getTagAttribute("inkboard", "protocol"); + if (type.empty() || seq.empty() || protover.empty()) { + g_warning("Received incomplete Inkboard message (missing type, protocol, or sequence number); ignoring message."); + return; + } - this->setRecipient(NULL); -} + MessageType mtype = static_cast< MessageType >(atoi(type.c_str())); -void -SessionManager::setRecipient(char const* recipientJID) -{ - if (this->session_data->recipient) { - free(const_cast< gchar* >(this->session_data->recipient)); - } - - if (recipientJID == NULL) { - this->session_data->recipient = NULL; - } else { - this->session_data->recipient = g_strdup(recipientJID); - } -} + // 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()); -void -SessionManager::sendChange(Glib::ustring const& msg, MessageType type, std::string const& recipientJID, bool chatroom) -{ - if (!this->session_data->status[IN_WHITEBOARD]) { - return; - } +// NOTE: This line refers to a class that hasn't been written yet +// MessageValidityTestResult res = MessageVerifier::verifyMessageValidity(event, mtype, doc); - std::string& recipient = const_cast< std::string& >(recipientJID); - if (recipient.empty()) { - recipient = this->session_data->recipient; - } - + MessageValidityTestResult res = RESULT_INVALID; - switch (type) { - case DOCUMENT_BEGIN: - case DOCUMENT_END: - case CHANGE_NOT_REPEATABLE: - case CHANGE_REPEATABLE: - case CHANGE_COMMIT: + switch (res) { + case RESULT_VALID: { - MessageNode *newNode = new MessageNode(this->session_data->sequence_number++, this->session_data->jid, recipient, msg, type, false, chatroom); - this->session_data->send_queue->insert(newNode); - Inkscape::GC::release(newNode); + switch (mtype) { + case CONNECT_REQUEST_USER: + case CONNECT_REQUEST_REFUSED_BY_PEER: + case UNSUPPORTED_PROTOCOL_VERSION: + case ALREADY_IN_SESSION: + _handleSessionEvent(mtype, event); + break; + case DISCONNECTED_FROM_USER_SIGNAL: + break; + default: + if (doc != NULL) { + unsigned int seqnum = atoi(seq.c_str()); + doc->processInkboardEvent(mtype, seqnum, event.getData()); + } + break; + } break; } + case RESULT_INVALID: default: - g_warning("Cannot insert MessageNode with unknown change type into send queue; discarding message. This may lead to desynchronization!"); + // FIXME: better warning message + g_warning("Received message in invalid context."); break; } } - -// FIXME: -// This method needs a massive, massive, massive overhaul. -int -SessionManager::sendMessage(MessageType msgtype, unsigned int sequence, Glib::ustring const& msg, char const* recipientJID, bool chatroom) +void +SessionManager::_handleSessionEvent(MessageType mtype, Pedro::XmppEvent const& event) { - LmMessage* m; - GError* error = NULL; - char* type, * seq; - - if (recipientJID == NULL || recipientJID == "") { - g_warning("Null recipient JID specified; not sending message."); - return NO_RECIPIENT_JID; - } else { - } - - // create message - m = lm_message_new(recipientJID, LM_MESSAGE_TYPE_MESSAGE); - - // add sender - lm_message_node_set_attribute(m->node, "from", this->session_data->jid.c_str()); - - // set message subtype according to whether or not this is - // destined for a chatroom - if (chatroom) { - lm_message_node_set_attribute(m->node, "type", "groupchat"); - } else { - lm_message_node_set_attribute(m->node, "type", "chat"); - } - - // set protocol version; - // we are currently fixed at version 1 - lm_message_node_add_child(m->node, MESSAGE_PROTOCOL_VER, MESSAGE_PROTOCOL_V1); - - // add message type - type = (char *)calloc(TYPE_FIELD_SIZE, sizeof(char)); - snprintf(type, TYPE_FIELD_SIZE, "%i", msgtype); - lm_message_node_add_child(m->node, MESSAGE_TYPE, type); - free(type); - - // add message body - if (!msg.empty()) { - lm_message_node_add_child(m->node, MESSAGE_BODY, msg.c_str()); - } else { - } - - // add sequence number - switch(msgtype) { - case CHANGE_REPEATABLE: - case CHANGE_NOT_REPEATABLE: - case DUMMY_CHANGE: - case CHANGE_COMMIT: - case DOCUMENT_BEGIN: - case DOCUMENT_END: - case CONNECT_REQUEST_RESPONSE_CHAT: - case CONNECT_REQUEST_RESPONSE_USER: - case CHATROOM_SYNCHRONIZE_RESPONSE: - seq = (char* )calloc(SEQNUM_FIELD_SIZE, sizeof(char)); - sprintf(seq, "%u", sequence); - lm_message_node_add_child(m->node, MESSAGE_SEQNUM, seq); - free(seq); - break; - + switch (mtype) { case CONNECT_REQUEST_USER: - case CONNECTED_SIGNAL: - case DISCONNECTED_FROM_USER_SIGNAL: + _handleIncomingInvitation(event.getFrom()); break; - - // Error messages and synchronization requests do not need a sequence number - case CHATROOM_SYNCHRONIZE_REQUEST: case CONNECT_REQUEST_REFUSED_BY_PEER: - case UNSUPPORTED_PROTOCOL_VERSION: + _handleInvitationResponse(event.getFrom(), DECLINE_INVITATION); + break; case ALREADY_IN_SESSION: + _handleInvitationResponse(event.getFrom(), PEER_ALREADY_IN_SESSION); + break; + case UNSUPPORTED_PROTOCOL_VERSION: + _handleInvitationResponse(event.getFrom(), UNSUPPORTED_PROTOCOL); break; - default: - g_warning("Outgoing message type not recognized; not sending."); - lm_message_unref(m); - return UNKNOWN_OUTGOING_TYPE; - } - - // We want to log messages even if they were not successfully sent, - // since the user may opt to re-synchronize a session using the session - // file record. - if (!msg.empty()) { - this->_log(msg); - this->_commitLog(); - } - - // send message - - if (!lm_connection_send(this->session_data->connection, m, &error)) { - g_warning("Send failed: %s", error->message); - lm_message_unref(m); - return CONNECTION_ERROR; - } - - lm_message_unref(m); - return SEND_SUCCESS; -} - -void -SessionManager::connectionError(Glib::ustring const& errmsg) -{ - Gtk::MessageDialog dlg(errmsg, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE); - dlg.run(); -// sp_whiteboard_connect_dialog(const_cast< gchar* >(errmsg)); -} - -void -SessionManager::resendDocument(char const* recipientJID, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf) -{ - Glib::ustring docbegin = MessageUtilities::makeTagWithContent(MESSAGE_DOCBEGIN, ""); - this->sendChange(docbegin, DOCUMENT_BEGIN, recipientJID, false); - - Inkscape::XML::Node* root = sp_document_repr_root(this->_myDoc); - - if(root == NULL) { - return; - } - - NewChildObjectMessageList newchildren; - MessageAggregator& agg = MessageAggregator::instance(); - Glib::ustring buf; - - for ( Inkscape::XML::Node *child = root->firstChild() ; child != NULL ; child = child->next() ) { - // TODO: replace with Serializer methods - MessageUtilities::newObjectMessage(&buf, newidsbuf, newnodesbuf, newchildren, this->_myTracker, child); - - NewChildObjectMessageList::iterator j = newchildren.begin(); - Glib::ustring aggbuf; - - for(; j != newchildren.end(); j++) { - if (!agg.addOne(*j, aggbuf)) { - this->sendChange(aggbuf, CHANGE_REPEATABLE, recipientJID, false); - aggbuf.clear(); - agg.addOne(*j, aggbuf); - } - } - - // send remaining changes - if (!aggbuf.empty()) { - this->sendChange(aggbuf, CHANGE_REPEATABLE, recipientJID, false); - aggbuf.clear(); - } - - newchildren.clear(); - buf.clear(); - } - - Glib::ustring commit = MessageUtilities::makeTagWithContent(MESSAGE_COMMIT, ""); - this->sendChange(commit, CHANGE_COMMIT, recipientJID, false); - Glib::ustring docend = MessageUtilities::makeTagWithContent(MESSAGE_DOCEND, ""); - this->sendChange(docend, DOCUMENT_END, recipientJID, false); -} - -void -SessionManager::receiveChange(Glib::ustring const& changemsg) -{ - - struct Node part; - - Glib::ustring msgcopy = changemsg.c_str(); - - - while(MessageUtilities::getFirstMessageTag(part, msgcopy) != false) { - // TODO: - // Yikes. This is ugly. - if (part.tag == MESSAGE_CHANGE) { - this->_myDeserializer->deserializeEventChgAttr(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_NEWOBJ) { - this->_myDeserializer->deserializeEventAdd(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DELETE) { - this->_myDeserializer->deserializeEventDel(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCUMENT) { - // no special handler, just keep going with the rest of the message - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_NODECONTENT) { - this->_myDeserializer->deserializeEventChgContent(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_ORDERCHANGE) { - this->_myDeserializer->deserializeEventChgOrder(part.data); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_COMMIT) { - // Retrieve the deserialized event log, node actions, and nodes with updated attributes - XML::Event* log = this->_myDeserializer->getEventLog(); - KeyToNodeActionList& node_changes = this->_myDeserializer->getNodeTrackerActions(); - AttributesUpdatedSet& updated = this->_myDeserializer->getUpdatedAttributeNodeSet(); - - // Make document insensitive to undo - gboolean saved = sp_document_get_undo_sensitive(this->_myDoc); - sp_document_set_undo_sensitive(this->_myDoc, FALSE); - - // Replay the log and push it onto the undo stack - sp_repr_replay_log(log); - - // Call updateRepr on changed nodes - // This is required for some tools to function properly, i.e. text tool - // (TODO: we don't need to update _all_ changed nodes, just their parents) - AttributesUpdatedSet::iterator i = updated.begin(); - for(; i != updated.end(); i++) { - SPObject* updated = this->_myDoc->getObjectByRepr(*i); - if (updated) { - updated->updateRepr(); - } - } - - // merge the events generated by updateRepr - sp_repr_coalesce_log(this->_myDoc->priv->partial, log); - this->_myDoc->priv->partial = NULL; - - this->_myDoc->priv->undo = g_slist_prepend(this->_myDoc->priv->undo, log); - - // Restore undo sensitivity - sp_document_set_undo_sensitive(this->_myDoc, saved); - - // Add or delete nodes to/from the tracker - this->_myTracker->process(node_changes); - - // Reset deserializer state - this->_myDeserializer->reset(); break; - - } else if (part.tag == MESSAGE_UNDO) { - this->_myUndoObserver->lockObserverFromSending(UndoStackObserver::UNDO_EVENT); - sp_document_undo(this->_myDoc); - this->_myUndoObserver->unlockObserverFromSending(UndoStackObserver::UNDO_EVENT); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_REDO) { - this->_myUndoObserver->lockObserverFromSending(UndoStackObserver::REDO_EVENT); - sp_document_redo(this->_myDoc); - this->_myUndoObserver->unlockObserverFromSending(UndoStackObserver::REDO_EVENT); - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCBEGIN) { - msgcopy.erase(0, part.next_pos); - - } else if (part.tag == MESSAGE_DOCEND) { - // Set this to be the new original state of the document - sp_document_done(this->document()); - sp_document_clear_redo(this->document()); - sp_document_clear_undo(this->document()); - this->setupCommitListener(); - msgcopy.erase(0, part.next_pos); - - } else { - msgcopy.erase(0, part.next_pos); - - } - } - - this->_log(changemsg); - - this->_commitLog(); -} - -bool -SessionManager::isPlayingSessionFile() -{ - return this->session_data->status[PLAYING_SESSION_FILE]; -} - -void -SessionManager::loadSessionFile(Glib::ustring filename) -{ - if (!this->session_data || !this->session_data->status[IN_WHITEBOARD]) { - try { - if (this->_mySessionFile) { - delete this->_mySessionFile; - } - this->_mySessionFile = new SessionFile(filename, true, false); - - // Initialize objects needed for session playback - if (this->_mySessionPlayer == NULL) { - this->_mySessionPlayer = new SessionFilePlayer(16, this); - } else { - this->_mySessionPlayer->load(this->_mySessionFile); - } - - if (this->_myTracker == NULL) { - this->_myTracker = new XMLNodeTracker(this); - } else { - this->_myTracker->reset(); - } - - if (!this->session_data) { - this->session_data = new SessionData(this); - } - - if (!this->_myDeserializer) { - this->_myDeserializer = new Deserializer(this->node_tracker()); - } - - if (!this->_myUndoObserver) { - this->setupCommitListener(); - } - - this->session_data->status.set(PLAYING_SESSION_FILE, 1); - - - } catch (Glib::FileError e) { - g_warning("Could not load session file: %s", e.what().data()); - } - } -} - -void -SessionManager::userConnectedToWhiteboard(gchar const* JID) -{ - sp_desktop_message_stack(this->_myDesktop)->flashF(Inkscape::INFORMATION_MESSAGE, _("Established whiteboard session with <b>%s</b>."), JID); -} - - -void -SessionManager::userDisconnectedFromWhiteboard(std::string const& JID) -{ - - sp_desktop_message_stack(this->_myDesktop)->flashF(Inkscape::INFORMATION_MESSAGE, _("<b>%s</b> has <b>left</b> the whiteboard session."), JID.c_str()); - - // Inform the user - // TRANSLATORS: %1 is the name of the user that disconnected, %2 is the name of the user whom the disconnected user disconnected from. - // This message is not used in a chatroom context. - Glib::ustring primary = String::ucompose(_("<span weight=\"bold\" size=\"larger\">The user <b>%1</b> has left the whiteboard session.</span>\n\n"), JID); - // TRANSLATORS: %1 and %2 are userids - Glib::ustring secondary = String::ucompose(_("You are still connected to a Jabber server as <b>%2</b>, and may establish a new session to <b>%1</b> or a different user."), JID, this->session_data->jid); - - // TODO: parent this dialog to the active desktop - Gtk::MessageDialog dialog(primary + secondary, true, Gtk::MESSAGE_INFO, Gtk::BUTTONS_CLOSE, false); - /* - dialog.set_message(primary, true); - dialog.set_secondary_text(secondary, true); - */ - dialog.run(); -} - -void -SessionManager::startSendQueueDispatch() -{ - this->_send_queue_dispatcher = Glib::signal_timeout().connect(sigc::mem_fun(*(this->_myCallbacks), &Callbacks::dispatchSendQueue), SEND_TIMEOUT); -} - -void -SessionManager::stopSendQueueDispatch() -{ - if (this->_send_queue_dispatcher) { - this->_send_queue_dispatcher.disconnect(); - } -} - -void -SessionManager::startReceiveQueueDispatch() -{ - this->_receive_queue_dispatcher = Glib::signal_timeout().connect(sigc::mem_fun(*(this->_myCallbacks), &Callbacks::dispatchReceiveQueue), SEND_TIMEOUT); -} - -void -SessionManager::stopReceiveQueueDispatch() -{ - if (this->_receive_queue_dispatcher) { - this->_receive_queue_dispatcher.disconnect(); - } -} - -void -SessionManager::clearDocument() -{ - // clear all layers, definitions, and metadata - XML::Node* rroot = this->_myDoc->rroot; - - // clear definitions - XML::Node* defs = SP_OBJECT_REPR((SPDefs*)SP_DOCUMENT_DEFS(this->_myDoc)); - g_assert(SP_ROOT(this->_myDoc->root)->defs); - - for(XML::Node* child = defs->firstChild(); child; child = child->next()) { - defs->removeChild(child); - } - - // clear layers - for(XML::Node* child = rroot->firstChild(); child; child = child->next()) { - if (strcmp(child->name(), "svg:g") == 0) { - rroot->removeChild(child); - } } - - // clear metadata - for(XML::Node* child = rroot->firstChild(); child; child = child->next()) { - if (strcmp(child->name(), "svg:metadata") == 0) { - rroot->removeChild(child); - } - } - -// sp_document_done(this->_myDoc); } void -SessionManager::setupInkscapeInterface() +SessionManager::_handleIncomingInvitation(Glib::ustring const& from) { - this->session_data->status.set(IN_WHITEBOARD, 1); - this->startSendQueueDispatch(); - this->startReceiveQueueDispatch(); - if (!this->_myTracker) { - this->_myTracker = new XMLNodeTracker(this); - } - - this->_mySerializer = new Serializer(this->node_tracker()); - this->_myDeserializer = new Deserializer(this->node_tracker()); - - // We're in a whiteboard session now, so set verb sensitivity accordingly - this->_setVerbSensitivity(ESTABLISHED_SESSION); -} - -void -SessionManager::setupCommitListener() -{ - this->_myUndoObserver = new Whiteboard::UndoStackObserver(this); - this->_myDoc->addUndoObserver(*this->_myUndoObserver); -} - -::SPDesktop* -SessionManager::desktop() -{ - return this->_myDesktop; -} - -::SPDocument* -SessionManager::document() -{ - return this->_myDoc; -} - -Callbacks* -SessionManager::callbacks() -{ - return this->_myCallbacks; -} - -Whiteboard::UndoStackObserver* -SessionManager::undo_stack_observer() -{ - return this->_myUndoObserver; -} - -Serializer* -SessionManager::serializer() -{ - return this->_mySerializer; -} - -XMLNodeTracker* -SessionManager::node_tracker() -{ - return this->_myTracker; -} - - -ChatMessageHandler* -SessionManager::chat_handler() -{ - return this->_myChatHandler; -} - -SessionFilePlayer* -SessionManager::session_player() -{ - return this->_mySessionPlayer; -} - -SessionFile* -SessionManager::session_file() -{ - return this->_mySessionFile; -} - -void -SessionManager::_log(Glib::ustring const& message) -{ - if (this->_mySessionFile && !this->_mySessionFile->isReadOnly()) { - this->_mySessionFile->addMessage(message); - } -} - -void -SessionManager::_commitLog() -{ - if (this->_mySessionFile && !this->_mySessionFile->isReadOnly()) { - this->_mySessionFile->commit(); + // don't insert duplicate invitations + if (std::find(_pending_invitations.begin(), _pending_invitations.end(), from) != _pending_invitations.end()) { + return; } -} -void -SessionManager::_closeLog() -{ - if (this->_mySessionFile) { - this->_mySessionFile->close(); - } -} + // 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 _checkInvitationQueue. + _pending_invitations.push_back(from); -void -SessionManager::startLog(Glib::ustring filename) -{ - try { - this->_mySessionFile = new SessionFile(filename, false, false); - } catch (Glib::FileError e) { - g_warning("Caught I/O error %s while attemping to open file %s for session recording.", e.what().c_str(), filename.c_str()); - throw; - } } void -SessionManager::_tryToStartLog() +SessionManager::_handleInvitationResponse(Glib::ustring const& from, InvitationResponses resp) { - if (this->session_data) { - if (!this->session_data->sessionFile.empty()) { - bool undecided = true; - while(undecided) { - try { - this->startLog(this->session_data->sessionFile); - undecided = false; - } catch (Glib::FileError e) { - undecided = true; - Glib::ustring msg = String::ucompose(_("Could not open file %1 for session recording.\nThe error encountered was: %2.\n\nYou may select a different location to record the session, or you may opt to not record this session."), this->session_data->sessionFile, e.what()); - Gtk::MessageDialog dlg(msg, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, false); - dlg.add_button(_("Choose a different location"), 0); - dlg.add_button(_("Skip session recording"), 1); - switch (dlg.run()) { - case 0: - { - Gtk::FileChooserDialog sessionfiledlg(_("Select a location and filename"), Gtk::FILE_CHOOSER_ACTION_SAVE); - sessionfiledlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - sessionfiledlg.add_button(_("Set filename"), Gtk::RESPONSE_OK); - int result = sessionfiledlg.run(); - switch (result) { - case Gtk::RESPONSE_OK: - { - this->session_data->sessionFile = sessionfiledlg.get_filename(); - break; - } - case Gtk::RESPONSE_CANCEL: - default: - undecided = false; - break; - } - break; - } - case 1: - default: - undecided = false; - break; - } - } - } - } + // 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; } -} - -void -SessionManager::_setVerbSensitivity(SensitivityMode mode) -{ - return; - - switch (mode) { - case ESTABLISHED_CONNECTION: - // Upon successful connection, we can disconnect from the server. - // We can also start sharing a document with a user or chatroom. - // We cannot, however, connect to a new server without first disconnecting. - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_CONNECT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, true); - break; - case ESTABLISHED_SESSION: - // When we have established a session, we should not permit the user to go and - // establish another session from the same document without first disconnecting. - // - // TODO: Well, actually, we probably _should_, but there's no real reconnection logic just yet. - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, true); - break; - case DISCONNECTED_FROM_SESSION: - // Upon disconnecting from a session, we can establish a new session and disconnect - // from the server, but we cannot disconnect from a session (since we just left it.) - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, true); - - case INITIAL: - default: - // Upon construction, there is no active connection, so we cannot do the following: - // (1) disconnect from a session - // (2) disconnect from a server - // (3) share with a user - // (4) share with a chatroom - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_CONNECT)->sensitive(this->_myDoc, true); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHUSER)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_SHAREWITHCHAT)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SESSION)->sensitive(this->_myDoc, false); - Inkscape::Verb::get(SP_VERB_DIALOG_WHITEBOARD_DISCONNECT_FROM_SERVER)->sensitive(this->_myDoc, false); - break; - }; -} - -/* -void -SessionManager::Listener::processXmppEvent(Pedro::XmppEvent const& event) -{ - int type = event.getType(); - - switch (type) { - case Pedro::XmppEvent::EVENT_STATUS: - break; - case Pedro::XmppEvent::EVENT_ERROR: - break; - case Pedro::XmppEvent::EVENT_CONNECTED: - break; - case Pedro::XmppEvent::EVENT_DISCONNECTED: - break; - case Pedro::XmppEvent::EVENT_MESSAGE: - break; - case Pedro::XmppEvent::EVENT_PRESENCE: - break; - case Pedro::XmppEvent::EVENT_MUC_MESSAGE: - break; - case Pedro::XmppEvent::EVENT_MUC_JOIN: - break; - case Pedro::XmppEvent::EVENT_MUC_LEAVE: - break; - case Pedro::XmppEvent::EVENT_MUC_PRESENCE: - break; - } -} -*/ + // 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)); } -} +} // namespace Whiteboard + +} // namespace Inkscape /* |
