/** * Whiteboard session manager * Jabber received message processors * * Authors: * David Yip * * Copyright (c) 2005 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ extern "C" { #include } #include #include "xml/session.h" #include "xml/document.h" #include "desktop-handles.h" #include "document.h" #include "message-stack.h" #include "jabber_whiteboard/undo-stack-observer.h" #include "jabber_whiteboard/session-manager.h" #include "jabber_whiteboard/message-node.h" #include "jabber_whiteboard/message-queue.h" #include "jabber_whiteboard/message-processors.h" #include "jabber_whiteboard/typedefs.h" namespace Inkscape { namespace Whiteboard { // Message processors are here! // TODO: Remove unnecessary status checks from processors -- // we do all of that in MessageHandler::_hasValidReceiveContext // ********************************************************************* // ChangeHandler begin // ********************************************************************* /** * MessageProcessor for document change and event commit messages. */ struct ChangeHandler : public MessageProcessor { public: ~ChangeHandler() { } ChangeHandler(SessionManager* sm) : MessageProcessor(sm) { } LmHandlerResult operator()(MessageType mode, JabberMessage& p) { MessageNode* msgNode; bool chatroom = this->_sm->session_data->status[IN_CHATROOM]; ReceiveMessageQueue* rmq = this->_sm->session_data->receive_queues[p.sender]; if (rmq != NULL) { switch (mode) { case CHANGE_REPEATABLE: case CHANGE_NOT_REPEATABLE: case DOCUMENT_BEGIN: msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom); rmq->insert(msgNode); Inkscape::GC::release(msgNode); break; case DOCUMENT_END: this->_sm->session_data->recipients_committed_queue.push_back(p.sender); msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom); rmq->insert(msgNode); Inkscape::GC::release(msgNode); break; case CHANGE_COMMIT: this->_sm->session_data->recipients_committed_queue.push_back(p.sender); msgNode = new MessageNode(p.sequence, p.sender, "", p.body, CHANGE_COMMIT, false, chatroom); rmq->insert(msgNode); Inkscape::GC::release(msgNode); break; case DUMMY_CHANGE: default: break; } } else { g_warning("Received message from unknown sender %s", p.sender.c_str()); } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } }; // ********************************************************************* // ChangeHandler end // ********************************************************************* // ********************************************************************* // ConnectRequestHandler begin // ********************************************************************* /** * MessageProcessor for connection request messages. */ struct ConnectRequestHandler : public MessageProcessor { public: ~ConnectRequestHandler() { } ConnectRequestHandler(SessionManager* sm) : MessageProcessor(sm) { } LmHandlerResult operator()(MessageType mode, JabberMessage& m) { std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status; switch(mode) { case CONNECT_REQUEST_USER: this->_sm->receiveConnectRequest(m.sender.c_str()); break; case CONNECT_REQUEST_RESPONSE_USER: if (m.sequence == 0) { this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender); } else { // FIXME: this has got to be buggy... this->_sm->setRecipient(m.sender.c_str()); this->_sm->receiveConnectRequestResponse(ACCEPT_INVITATION, m.sender); } break; case Inkscape::Whiteboard::CONNECTED_SIGNAL: if (!status[IN_CHATROOM] && !status[CONNECTING_TO_CHAT] && !status[SYNCHRONIZING_WITH_CHAT] && !status[WAITING_TO_SYNC_TO_CHAT]) { this->_sm->userConnectedToWhiteboard(m.sender.c_str()); this->_sm->setRecipient(m.sender.c_str()); } else { SP_DT_MSGSTACK(this->_sm->desktop())->flashF(Inkscape::INFORMATION_MESSAGE, _("%s has joined the chatroom."), m.sender.c_str()); } break; default: break; } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } }; // ********************************************************************* // ConnectRequestHandler end // ********************************************************************* // ********************************************************************* // ConnectErrorHandler begin // ********************************************************************* /** * MessageProcessor for connection error messages. */ struct ConnectErrorHandler : public MessageProcessor { public: ~ConnectErrorHandler() { } ConnectErrorHandler(SessionManager* sm) : MessageProcessor(sm) { } LmHandlerResult operator()(MessageType mode, JabberMessage& m) { switch(mode) { case CONNECT_REQUEST_REFUSED_BY_PEER: if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) { this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender); } break; case Inkscape::Whiteboard::ALREADY_IN_SESSION: if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) { this->_sm->receiveConnectRequestResponse(PEER_ALREADY_IN_SESSION, m.sender); } break; case Inkscape::Whiteboard::DISCONNECTED_FROM_USER_SIGNAL: if (!this->_sm->session_data->status[IN_CHATROOM]) { this->_sm->closeSession(); this->_sm->userDisconnectedFromWhiteboard(m.sender.c_str()); } break; default: break; } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } }; // ********************************************************************* // ConnectErrorHandler end // ********************************************************************* // ********************************************************************* // ChatSynchronizeHandler begin // ********************************************************************* /** * MessageProcessor for messages specific to chatroom synchronization. */ struct ChatSynchronizeHandler : public MessageProcessor { public: ~ChatSynchronizeHandler() { } ChatSynchronizeHandler(SessionManager* sm) : MessageProcessor(sm) { } LmHandlerResult operator()(MessageType mode, JabberMessage& m) { switch(mode) { case CONNECT_REQUEST_RESPONSE_CHAT: this->_sm->receiveConnectRequestResponseChat(m.sender.c_str()); break; case CHATROOM_SYNCHRONIZE_REQUEST: if (this->_sm->session_data->status[IN_CHATROOM] && this->_sm->session_data->status[IN_WHITEBOARD]) { // Send response. Everyone in the chatroom will do this, // but the client will accept only one response. // The response is sent privately to the client // this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_RESPONSE, this->_sm->session_data->sequence_number, "", m.sender.c_str(), false); } break; case CHATROOM_SYNCHRONIZE_RESPONSE: if (m.sequence != 0) { // Set sequence number this->_sm->session_data->sequence_number = m.sequence; // Set status flags this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 0); this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 1); // Send document synchronization request this->_sm->clearDocument(); this->_sm->setupInkscapeInterface(); this->_sm->sendMessage(CONNECT_REQUEST_RESPONSE_CHAT, m.sequence, "", m.sender.c_str(), false); } else { this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_REQUEST, 0, "", this->_sm->session_data->recipient, true); } break; default: break; } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } }; // ********************************************************************* // ChatSynchronizeHandler end // ********************************************************************* // ********************************************************************* // Initializer // ********************************************************************* void initialize_received_message_processors(SessionManager* sm, MessageProcessorMap& mpm) { MessageProcessor* ch = new ChangeHandler(sm); MessageProcessor* crh = new ConnectRequestHandler(sm); MessageProcessor* ceh = new ConnectErrorHandler(sm); MessageProcessor* csh = new ChatSynchronizeHandler(sm); mpm[CHANGE_REPEATABLE] = ch; mpm[CHANGE_NOT_REPEATABLE] = ch; mpm[DUMMY_CHANGE] = ch; mpm[CHANGE_COMMIT] = ch; mpm[DOCUMENT_BEGIN] = ch; mpm[DOCUMENT_END] = ch; mpm[CONNECT_REQUEST_USER] = crh; mpm[CONNECT_REQUEST_RESPONSE_USER] = crh; mpm[CONNECTED_SIGNAL] = crh; mpm[CONNECT_REQUEST_REFUSED_BY_PEER] = ceh; mpm[ALREADY_IN_SESSION] = ceh; mpm[DISCONNECTED_FROM_USER_SIGNAL] = ceh; mpm[CONNECT_REQUEST_RESPONSE_CHAT] = csh; mpm[CHATROOM_SYNCHRONIZE_REQUEST] = csh; mpm[CHATROOM_SYNCHRONIZE_RESPONSE] = csh; } /* * This function is provided solely for convenience and style. You can, of course, * delete every MessageProcessor in the map with your own loop. */ void destroy_received_message_processors(MessageProcessorMap& mpm) { mpm.clear(); } } } /* 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 :