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