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