1 /**
2 * Whiteboard session manager
3 * Jabber received message processors
4 *
5 * Authors:
6 * David Yip <yipdw@rose-hulman.edu>
7 *
8 * Copyright (c) 2005 Authors
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 extern "C" {
14 #include <loudmouth/loudmouth.h>
15 }
17 #include <glibmm/i18n.h>
19 #include "xml/session.h"
20 #include "xml/document.h"
22 #include "desktop-handles.h"
23 #include "document.h"
24 #include "message-stack.h"
26 #include "jabber_whiteboard/undo-stack-observer.h"
27 #include "jabber_whiteboard/session-manager.h"
28 #include "jabber_whiteboard/message-node.h"
29 #include "jabber_whiteboard/message-queue.h"
30 #include "jabber_whiteboard/message-processors.h"
31 #include "jabber_whiteboard/typedefs.h"
33 namespace Inkscape {
35 namespace Whiteboard {
37 // Message processors are here!
39 // TODO: Remove unnecessary status checks from processors --
40 // we do all of that in MessageHandler::_hasValidReceiveContext
42 // *********************************************************************
43 // ChangeHandler begin
44 // *********************************************************************
46 /**
47 * MessageProcessor for document change and event commit messages.
48 */
49 struct ChangeHandler : public MessageProcessor {
50 public:
51 ~ChangeHandler()
52 {
54 }
56 ChangeHandler(SessionManager* sm) : MessageProcessor(sm)
57 {
59 }
61 LmHandlerResult
62 operator()(MessageType mode, JabberMessage& p)
63 {
64 MessageNode* msgNode;
65 bool chatroom = this->_sm->session_data->status[IN_CHATROOM];
67 ReceiveMessageQueue* rmq = this->_sm->session_data->receive_queues[p.sender];
69 if (rmq != NULL) {
70 switch (mode) {
71 case CHANGE_REPEATABLE:
72 case CHANGE_NOT_REPEATABLE:
73 case DOCUMENT_BEGIN:
74 msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom);
75 rmq->insert(msgNode);
76 Inkscape::GC::release(msgNode);
77 break;
78 case DOCUMENT_END:
79 this->_sm->session_data->recipients_committed_queue.push_back(p.sender);
80 msgNode = new MessageNode(p.sequence, p.sender, "", p.body, mode, false, chatroom);
81 rmq->insert(msgNode);
82 Inkscape::GC::release(msgNode);
83 break;
84 case CHANGE_COMMIT:
85 this->_sm->session_data->recipients_committed_queue.push_back(p.sender);
86 msgNode = new MessageNode(p.sequence, p.sender, "", p.body, CHANGE_COMMIT, false, chatroom);
87 rmq->insert(msgNode);
88 Inkscape::GC::release(msgNode);
89 break;
90 case DUMMY_CHANGE:
91 default:
92 break;
93 }
94 } else {
95 g_warning("Received message from unknown sender %s", p.sender.c_str());
96 }
98 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
99 }
100 };
101 // *********************************************************************
102 // ChangeHandler end
103 // *********************************************************************
106 // *********************************************************************
107 // ConnectRequestHandler begin
108 // *********************************************************************
109 /**
110 * MessageProcessor for connection request messages.
111 */
112 struct ConnectRequestHandler : public MessageProcessor {
113 public:
114 ~ConnectRequestHandler()
115 {
117 }
119 ConnectRequestHandler(SessionManager* sm) : MessageProcessor(sm)
120 {
122 }
124 LmHandlerResult
125 operator()(MessageType mode, JabberMessage& m)
126 {
127 std::bitset< NUM_FLAGS >& status = this->_sm->session_data->status;
128 switch(mode) {
129 case CONNECT_REQUEST_USER:
130 this->_sm->receiveConnectRequest(m.sender.c_str());
131 break;
132 case CONNECT_REQUEST_RESPONSE_USER:
133 if (m.sequence == 0) {
134 this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender);
135 } else { // FIXME: this has got to be buggy...
136 this->_sm->setRecipient(m.sender.c_str());
137 this->_sm->receiveConnectRequestResponse(ACCEPT_INVITATION, m.sender);
138 }
139 break;
140 case Inkscape::Whiteboard::CONNECTED_SIGNAL:
141 if (!status[IN_CHATROOM] && !status[CONNECTING_TO_CHAT] && !status[SYNCHRONIZING_WITH_CHAT] && !status[WAITING_TO_SYNC_TO_CHAT]) {
142 this->_sm->userConnectedToWhiteboard(m.sender.c_str());
143 this->_sm->setRecipient(m.sender.c_str());
144 } else {
145 SP_DT_MSGSTACK(this->_sm->desktop())->flashF(Inkscape::INFORMATION_MESSAGE, _("<b>%s</b> has joined the chatroom."), m.sender.c_str());
146 }
147 break;
148 default:
149 break;
150 }
151 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
152 }
153 };
154 // *********************************************************************
155 // ConnectRequestHandler end
156 // *********************************************************************
161 // *********************************************************************
162 // ConnectErrorHandler begin
163 // *********************************************************************
164 /**
165 * MessageProcessor for connection error messages.
166 */
167 struct ConnectErrorHandler : public MessageProcessor {
168 public:
169 ~ConnectErrorHandler()
170 {
172 }
174 ConnectErrorHandler(SessionManager* sm) : MessageProcessor(sm)
175 {
177 }
179 LmHandlerResult
180 operator()(MessageType mode, JabberMessage& m)
181 {
182 switch(mode) {
183 case CONNECT_REQUEST_REFUSED_BY_PEER:
184 if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) {
185 this->_sm->receiveConnectRequestResponse(DECLINE_INVITATION, m.sender);
186 }
187 break;
188 case Inkscape::Whiteboard::ALREADY_IN_SESSION:
189 if (this->_sm->session_data->status[WAITING_FOR_INVITE_RESPONSE]) {
190 this->_sm->receiveConnectRequestResponse(PEER_ALREADY_IN_SESSION, m.sender);
191 }
192 break;
193 case Inkscape::Whiteboard::DISCONNECTED_FROM_USER_SIGNAL:
194 if (!this->_sm->session_data->status[IN_CHATROOM]) {
195 this->_sm->closeSession();
196 this->_sm->userDisconnectedFromWhiteboard(m.sender.c_str());
197 }
198 break;
199 default:
200 break;
201 }
202 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
203 }
204 };
205 // *********************************************************************
206 // ConnectErrorHandler end
207 // *********************************************************************
212 // *********************************************************************
213 // ChatSynchronizeHandler begin
214 // *********************************************************************
215 /**
216 * MessageProcessor for messages specific to chatroom synchronization.
217 */
218 struct ChatSynchronizeHandler : public MessageProcessor {
219 public:
220 ~ChatSynchronizeHandler()
221 {
223 }
225 ChatSynchronizeHandler(SessionManager* sm) : MessageProcessor(sm)
226 {
228 }
230 LmHandlerResult
231 operator()(MessageType mode, JabberMessage& m)
232 {
233 switch(mode) {
234 case CONNECT_REQUEST_RESPONSE_CHAT:
235 this->_sm->receiveConnectRequestResponseChat(m.sender.c_str());
236 break;
237 case CHATROOM_SYNCHRONIZE_REQUEST:
238 if (this->_sm->session_data->status[IN_CHATROOM] && this->_sm->session_data->status[IN_WHITEBOARD]) {
239 // Send response. Everyone in the chatroom will do this,
240 // but the client will accept only one response.
241 // The response is sent privately to the client
242 // <http://www.jabber.org/jeps/jep-0045.html#privatemessage>
243 this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_RESPONSE, this->_sm->session_data->sequence_number, "", m.sender.c_str(), false);
244 }
245 break;
246 case CHATROOM_SYNCHRONIZE_RESPONSE:
247 if (m.sequence != 0) {
248 // Set sequence number
249 this->_sm->session_data->sequence_number = m.sequence;
251 // Set status flags
252 this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 0);
253 this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 1);
255 // Send document synchronization request
256 this->_sm->clearDocument();
257 this->_sm->setupInkscapeInterface();
258 this->_sm->sendMessage(CONNECT_REQUEST_RESPONSE_CHAT, m.sequence, "", m.sender.c_str(), false);
259 } else {
260 this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_REQUEST, 0, "", this->_sm->session_data->recipient, true);
261 }
262 break;
263 default:
264 break;
265 }
266 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
267 }
268 };
269 // *********************************************************************
270 // ChatSynchronizeHandler end
271 // *********************************************************************
276 // *********************************************************************
277 // Initializer
278 // *********************************************************************
279 void
280 initialize_received_message_processors(SessionManager* sm, MessageProcessorMap& mpm)
281 {
282 MessageProcessor* ch = new ChangeHandler(sm);
283 MessageProcessor* crh = new ConnectRequestHandler(sm);
284 MessageProcessor* ceh = new ConnectErrorHandler(sm);
285 MessageProcessor* csh = new ChatSynchronizeHandler(sm);
287 mpm[CHANGE_REPEATABLE] = ch;
288 mpm[CHANGE_NOT_REPEATABLE] = ch;
289 mpm[DUMMY_CHANGE] = ch;
290 mpm[CHANGE_COMMIT] = ch;
291 mpm[DOCUMENT_BEGIN] = ch;
292 mpm[DOCUMENT_END] = ch;
294 mpm[CONNECT_REQUEST_USER] = crh;
295 mpm[CONNECT_REQUEST_RESPONSE_USER] = crh;
296 mpm[CONNECTED_SIGNAL] = crh;
298 mpm[CONNECT_REQUEST_REFUSED_BY_PEER] = ceh;
299 mpm[ALREADY_IN_SESSION] = ceh;
300 mpm[DISCONNECTED_FROM_USER_SIGNAL] = ceh;
302 mpm[CONNECT_REQUEST_RESPONSE_CHAT] = csh;
303 mpm[CHATROOM_SYNCHRONIZE_REQUEST] = csh;
304 mpm[CHATROOM_SYNCHRONIZE_RESPONSE] = csh;
305 }
307 /*
308 * This function is provided solely for convenience and style. You can, of course,
309 * delete every MessageProcessor in the map with your own loop.
310 */
311 void
312 destroy_received_message_processors(MessageProcessorMap& mpm)
313 {
314 mpm.clear();
315 }
317 }
319 }
321 /*
322 Local Variables:
323 mode:c++
324 c-file-style:"stroustrup"
325 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
326 indent-tabs-mode:nil
327 fill-column:99
328 End:
329 */
330 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :