1 /**
2 * Whiteboard session manager
3 *
4 * Authors:
5 * David Yip <yipdw@rose-hulman.edu>
6 *
7 * Copyright (c) 2005 Authors
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #ifndef __SESSION_MANAGER_H__
13 #define __SESSION_MANAGER_H__
15 #include <glibmm.h>
16 #include <set>
17 #include <bitset>
19 extern "C" {
20 #include <loudmouth/loudmouth.h>
21 }
23 #include "jabber_whiteboard/typedefs.h"
24 #include "jabber_whiteboard/defines.h"
25 #include "jabber_whiteboard/buddy-list-manager.h"
27 #include "gc-alloc.h"
29 struct SPDesktop;
30 struct SPDocument;
32 namespace Inkscape {
33 namespace XML {
34 class Node;
35 }
36 }
38 namespace Inkscape {
40 namespace Whiteboard {
42 class ReceiveMessageQueue;
43 class SendMessageQueue;
44 class XMLNodeTracker;
45 class SessionManager;
46 class MessageHandler;
47 class ChatMessageHandler;
48 class Callbacks;
49 class SessionFile;
50 class SessionFilePlayer;
51 class UndoStackObserver;
52 class Serializer;
53 class Deserializer;
55 /// Jabber resource name
56 #define RESOURCE_NAME "Inkboard"
58 /// connectToServer return values
59 #define CONNECT_SUCCESS 0
60 #define FAILED_TO_CONNECT 1
61 #define INVALID_AUTH 2
62 #define SSL_INITIALIZATION_ERROR 3
64 /// sendMessage return values
65 #define SEND_SUCCESS 0
66 #define CONNECTION_ERROR 1
67 #define UNKNOWN_OUTGOING_TYPE 2
68 #define NO_RECIPIENT_JID 3
70 /**
71 * Structure grouping data items pertinent to a whiteboard session.
72 *
73 * SessionData holds all session data for both 1:1 and chatroom conferences.
74 * Access to members should be controlled by first querying the status bitset
75 * to see if useful data will actually exist in that member -- i.e. checking
76 * status[IN_CHATROOM] to see if the chatters set will contain anything.
77 * It usually won't hurt to do a straight query -- there are very few members
78 * that remain uninitialized for very long -- but it's a good idea to check.
79 */
80 struct SessionData {
81 public:
82 /**
83 * Constructor.
84 *
85 * \param sm The SessionManager with which a SessionData instance should be
86 * associated with.
87 */
88 SessionData(SessionManager *sm);
90 ~SessionData();
92 /**
93 * The JID of the recipient: either another user JID or the JID of a chatroom.
94 */
95 gchar const* recipient;
97 /**
98 * Pointer to Loudmouth connection structure.
99 * Used for Loudmouth calls that require it.
100 */
101 LmConnection* connection;
103 /**
104 * SSL information structure for SSL connections.
105 */
106 LmSSL* ssl;
108 /**
109 * Flag indicating whether or not we should ignore further SSL errors for a given session.
110 */
111 bool ignoreFurtherSSLErrors;
114 /**
115 * A user's handle in a Jabber chatroom.
116 */
117 Glib::ustring chat_handle;
119 /**
120 * Name of the chatroom that a user in a chatroom is connected to.
121 */
122 Glib::ustring chat_name;
124 /**
125 * Name of the conference server.
126 */
127 Glib::ustring chat_server;
129 // Message queues
131 /**
132 * Map associating senders to receive queues.
133 */
134 RecipientToReceiveQueueMap receive_queues;
136 /**
137 * Map associating senders to commit events sent by those committers.
138 */
139 CommitsQueue recipients_committed_queue;
141 /**
142 * Pointer to queue for messages to be sent.
143 */
144 SendMessageQueue* send_queue;
146 // Message sequence numbers
148 /**
149 * The sequence number of the latest message sent by this client in a given session.
150 * Used for determining the sequence number of the next message.
151 */
152 unsigned int sequence_number;
154 //unsigned int latest_sent_transaction;
155 //RecipientToLatestTransactionMap latest_processed_transactions;
158 // Status tracking
159 /**
160 * Session state and status flags.
161 */
162 std::bitset< NUM_FLAGS > status;
164 /**
165 * Jabber buddy list data.
166 */
167 BuddyListManager buddyList;
169 /**
170 * List of participants in a Jabber chatroom.
171 */
172 ChatterList chatters;
174 /**
175 * Session file filename; blank if no session file is to be
176 * recorded.
177 */
178 Glib::ustring sessionFile;
180 private:
181 // access to containing class
182 SessionManager *_sm;
184 // noncopyable, nonassignable
185 SessionData(SessionData const&);
186 SessionData& operator=(SessionData const&);
187 };
190 // TODO: This class is huge. It might be best to refactor it into smaller,
191 // more coherent chunks.
192 //
193 // TODO: convert to pass-by-reference where appropriate. In particular, a lot of the
194 // string buffers passed to methods in the argument list can be made into references
195 // appropriately and easily.
197 /**
198 * Session management class for Inkboard.
199 *
200 * By "session management", we refer to the management of all events that an Inkboard
201 * session may need to handle: negotiating a connection to a Jabber server, negotiating
202 * sessions with users and chatrooms, sending, receiving, and parsing messages, and so
203 * forth.
204 *
205 * SessionManager instances are associated with Inkscape desktop objects on a 1:1 basis.
206 */
207 class SessionManager {
208 public:
209 /**
210 * Constructor.
211 *
212 * \param desktop The desktop with which this SessionManager is associated. */
213 SessionManager(::SPDesktop *desktop);
214 ~SessionManager();
216 // Session tracking data
218 /**
219 * Pointer to SessionData structure.
220 */
221 struct SessionData *session_data;
223 // Inkscape interface
225 /**
226 * Set the desktop with which this SessionManager is associated.
227 *
228 * @param desktop the desktop with which this SessionManager should be associated
229 */
230 void setDesktop(::SPDesktop* desktop);
232 // Session management
234 /**
235 * Connect to a Jabber server.
236 *
237 * @param server Jabber server URL
238 * @param username Jabber username
239 * @param pw password for Jabber account
240 * @param usessl use SSL for connection
241 *
242 * @return CONNECT_SUCCESS if connection successful; FAILED_TO_CONNECT if connection failed or INVALID_AUTH
243 * if authentication invalid
244 */
245 int connectToServer(Glib::ustring const& server, Glib::ustring const& port, Glib::ustring const& username, Glib::ustring const& pw, bool usessl);
247 /**
248 * Handle an SSL error by prompting the user for feedback, and continuing or aborting the connection
249 * process based on that feedback.
250 *
251 * @param ssl pointer to LmSSL structure
252 * @param status The error message
253 *
254 * @return LM_SSL_RESPONSE_CONTINUE if user wishes to continue establishing the connection or LM_SSL_RESPONSE_STOP if user wishes to abort connection
255 */
256 LmSSLResponse handleSSLError(LmSSL* ssl, LmSSLStatus status);
258 /**
259 * Disconnect from a Jabber server.
260 *
261 * This invokes disconnectFromDocument().
262 *
263 * \see Inkscape::Whiteboard::SessionManager::disconnectFromDocument
264 */
265 void disconnectFromServer();
267 /**
268 * Disconnect from a document session. The connection to the Jabber server is not
269 * broken, and may be reused to connect to a new document session.
270 *
271 */
272 void disconnectFromDocument();
274 /**
275 * Perform session teardown. This method by itself does not disconnect from a document or
276 * a Jabber server.
277 *
278 */
279 void closeSession();
281 /**
282 * Set the recipient for Inkboard messages.
283 *
284 * @param recipientJID the recipient's JID
285 */
286 void setRecipient(char const* recipientJID);
288 // Message sending utilities
290 /**
291 * Put an Inkboard message into the send queue.
292 * This method does not actually send anything to an Inkboard client.
293 *
294 * \see Inkscape::Whiteboard::SessionManager::sendMessage
295 *
296 *
297 * @param msg the message to send
298 * @param type the type of message (only CHANGE_* types permitted)
299 * @param chatroom whether or not this message is destined for a chatroom
300 */
301 void sendChange(Glib::ustring const& msg, MessageType type, std::string const& recipientJID, bool chatroom);
303 /**
304 * Send a message to an Inkboard client.
305 *
306 *
307 * @param msgtype the type of message to send
308 * @param sequence message sequence number
309 * @param msg the message to send
310 * @param recipientJID the JID of the recipient
311 * @param chatroom whether or not this message is destined for a chatroom
312 *
313 * @return SEND_SUCCESS if successful; otherwise: UNKNOWN_OUTGOING_TYPE if msgtype is not recognized, NO_RECIPIENT_JID if recipientJID is NULL or blank, CONNECTION_ERROR if Jabber connection error occurred
314 */
315 int sendMessage(MessageType msgtype, unsigned int sequence, Glib::ustring const& msg, char const* recipientJID, bool chatroom);
317 /**
318 * Inform the user of a connection error via a Gtk::MessageDialog.
319 *
320 * @param errmsg message to display
321 */
322 void connectionError(Glib::ustring const& errmsg);
324 /**
325 * Stream the contents of the document with which this SessionManager is associated with to the given recipient.
326 *
327 * @param recipientJID the JID of the recipient
328 * @param newidsbuf buffer to store IDs of new nodes
329 * @param newnodesbuf buffer to store address of new nodes
330 */
331 void resendDocument(char const* recipientJID, KeyToNodeMap& newidsbuf, NodeToKeyMap& newnodesbuf);
334 /**
335 * Send a connection request to another Inkboard client.
336 *
337 *
338 * @param recipientJID the JID to connect to
339 * @param document document message to send
340 */
341 void sendRequestToUser(std::string const& recipientJID);
343 /**
344 * Send a connection request to chatroom.
345 *
346 * @param server server to connect to
347 * @param chatroom name of chatroom
348 * @param handle chatroom handle to use
349 * @param password chatroom password; leave NULL if no password
350 */
351 void sendRequestToChatroom(Glib::ustring const& server, Glib::ustring const& chatroom, Glib::ustring const& handle, Glib::ustring const& password);
353 /**
354 * Send a connection request response to a user who requested to connect to us.
355 *
356 * @param requesterJID the JID of the user whom sent us the request
357 * @param accepted_request whether or not we accepted the request
358 */
359 void sendConnectRequestResponse(char const* requesterJID, gboolean accepted_request);
361 /**
362 * Method called when a connection request is received. This method produces a dialog
363 * that asks the user whether or not s/he would like to accept the request.
364 *
365 *
366 * @param requesterJID the JID of the user whom sent us the request
367 * @param msg the message associated with this request
368 */
369 void receiveConnectRequest(gchar const* requesterJID);
371 /**
372 * Method called when a response to a connection request is received.
373 * This method performs any necessary session setup/teardown and user notification
374 * depending on the response received.
375 *
376 *
377 * @param msg the message associated with this request
378 * @param response the response code
379 * @param sender the JID of the user whom responded to our request
380 */
381 void receiveConnectRequestResponse(InvitationResponses response, std::string& sender);
383 /**
384 * Method called when a document synchronization request is received from a new conference
385 * member in a chatroom.
386 *
387 * \param recipient the recipient JID
388 */
389 void receiveConnectRequestResponseChat(gchar const* recipient);
391 // Message parsing and passing
393 /**
394 * Processes a group of document change messages.
395 *
396 * \param changemsg The change message group to process.
397 */
398 void receiveChange(Glib::ustring const& changemsg);
400 // Logging and session file handling
401 /**
402 * Start a session log with the given filename.
403 *
404 * \param filename Full path to the file that the session log should be written to.
405 * \throw Glib::FileError Thrown if an exception is thrown during session file creation.
406 */
407 void startLog(Glib::ustring filename);
409 /**
410 * Load a session file for playback.
411 *
412 * \param filename Full path to the session file that is to be loaded.
413 */
414 void loadSessionFile(Glib::ustring filename);
416 /**
417 * Returns whether or not the session is in session file playback mode.
418 *
419 * \return Whether or not the session is in session file playback mode.
420 */
421 bool isPlayingSessionFile();
423 // User event notification
425 /**
426 * Method to notify the user that a whiteboard session to another user has been successfully
427 * established.
428 *
429 * \param JID The JID with whom the user established a session.
430 */
431 void userConnectedToWhiteboard(gchar const* JID);
433 /**
434 * Method to notify the user that the other user in a user-to-user whiteboard session
435 * has disconnected.
436 *
437 * \param JID The JID of the user who left the whiteboard session.
438 */
439 void userDisconnectedFromWhiteboard(std::string const& JID);
441 // Queue dispatching and UI setup
443 /**
444 * Start the send queue for this session.
445 */
446 void startSendQueueDispatch();
448 /**
449 * Stop the send queue for this session.
450 */
451 void stopSendQueueDispatch();
453 /**
454 * Start the receive queue for this session.
455 */
456 void startReceiveQueueDispatch();
458 /**
459 * Stop the receive queue for this session.
460 */
461 void stopReceiveQueueDispatch();
463 /**
464 * Clear all layers, definitions, and metadata from the document with which a
465 * SessionManager instance is associated.
466 *
467 * Documents are cleared to assist synchronization between two clients
468 * or a client and a chatroom.
469 */
470 void clearDocument();
472 /**
473 * Set up objects for handling actions generated by the user interacting with
474 * Inkscape. This includes marking the active session as being in a whiteboard session,
475 * starting send and receive queues, and creating an event serializer and deserializer.
476 *
477 * \see Inkscape::Whiteboard::SendMessageQueue
478 * \see Inkscape::Whiteboard::ReceiveMessageQueue
479 * \see Inkscape::Whiteboard::Serializer
480 * \see Inkscape::Whiteboard::Deserializer
481 */
482 void setupInkscapeInterface();
484 /**
485 * Reset whiteboard verbs to INITIAL state.
486 */
487 void setInitialVerbSensitivity() {
488 this->_setVerbSensitivity(INITIAL);
489 }
491 /**
492 * Set up the event commit listener.
493 *
494 * The event commit listener watches for events that are committed to the document's undo log,
495 * serializes those events, and then adds them to the message send queue.
496 *
497 * \see Inkscape::Whiteboard::SendMessageQueue
498 * \see Inkscape::Whiteboard::UndoStackObserver
499 */
500 void setupCommitListener();
502 // Private object retrieval
503 ::SPDesktop* desktop();
504 ::SPDocument* document();
505 Callbacks* callbacks();
506 Whiteboard::UndoStackObserver* undo_stack_observer();
507 Serializer* serializer();
508 XMLNodeTracker* node_tracker();
509 Deserializer* deserializer();
510 ChatMessageHandler* chat_handler();
511 SessionFilePlayer* session_player();
512 SessionFile* session_file();
514 private:
515 // Internal logging methods
516 void _log(Glib::ustring const& message);
517 void _commitLog();
518 void _closeLog();
519 void _tryToStartLog();
521 enum SensitivityMode {
522 INITIAL,
523 ESTABLISHED_CONNECTION,
524 ESTABLISHED_SESSION,
525 DISCONNECTED_FROM_SESSION
526 };
528 void _setVerbSensitivity(SensitivityMode mode);
530 bool _pollReceiveConnectRequest(Glib::ustring const recipient);
532 ::SPDesktop* _myDesktop;
533 ::SPDocument* _myDoc;
534 Whiteboard::UndoStackObserver* _myUndoObserver;
535 XMLNodeTracker* _myTracker;
536 ChatMessageHandler* _myChatHandler;
537 Callbacks* _myCallbacks;
538 SessionFile* _mySessionFile;
539 SessionFilePlayer* _mySessionPlayer;
540 MessageHandler* _myMessageHandler;
541 Serializer* _mySerializer;
542 Deserializer* _myDeserializer;
544 sigc::connection _send_queue_dispatcher;
545 sigc::connection _receive_queue_dispatcher;
546 sigc::connection _notify_incoming_request;
548 // noncopyable, nonassignable
549 SessionManager(SessionManager const&);
550 SessionManager& operator=(SessionManager const&);
551 };
553 }
555 }
557 #endif
559 /*
560 Local Variables:
561 mode:c++
562 c-file-style:"stroustrup"
563 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
564 indent-tabs-mode:nil
565 fill-column:99
566 End:
567 */
568 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :