1 /**
2 * Whiteboard session manager
3 * Message dispatch devices and timeout triggers
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 "message-stack.h"
20 #include "document.h"
21 #include "desktop-handles.h"
23 #include "jabber_whiteboard/undo-stack-observer.h"
24 #include "jabber_whiteboard/jabber-handlers.h"
25 #include "jabber_whiteboard/defines.h"
26 #include "jabber_whiteboard/typedefs.h"
27 #include "jabber_whiteboard/session-manager.h"
28 #include "jabber_whiteboard/message-queue.h"
29 #include "jabber_whiteboard/message-handler.h"
30 #include "jabber_whiteboard/message-node.h"
31 #include "jabber_whiteboard/callbacks.h"
33 namespace Inkscape {
35 namespace Whiteboard {
37 Callbacks::Callbacks(SessionManager* sm) : _sm(sm)
38 {
39 this->_sd = this->_sm->session_data;
40 }
42 Callbacks::~Callbacks()
43 {
44 }
46 bool
47 Callbacks::dispatchSendQueue()
48 {
49 // If we're not in a whiteboard session, don't dispatch anything
50 if (!(this->_sd->status[IN_WHITEBOARD])) {
51 return false;
52 }
54 // If the connection is not open, inform the user that an error has occurred
55 // and stop the queue
56 LmConnectionState state = lm_connection_get_state(this->_sd->connection);
58 if (state != LM_CONNECTION_STATE_OPEN && state != LM_CONNECTION_STATE_AUTHENTICATED) {
59 SP_DT_MSGSTACK(this->_sm->desktop())->flash(Inkscape::INFORMATION_MESSAGE, _("Jabber connection lost."));
60 return false;
61 }
63 // If there's nothing to send, don't do anything
64 if (this->_sd->send_queue->empty()) {
65 return true;
66 }
68 // otherwise, send out the first change
69 MessageNode* first = this->_sd->send_queue->first();
71 SP_DT_MSGSTACK(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE,
72 ngettext("Sending message; %u message remaining in send queue.",
73 "Sending message; %u messages remaining in send queue.",
74 this->_sd->send_queue->size()),
75 this->_sd->send_queue->size());
77 if (this->_sd->send_queue->empty()) {
78 SP_DT_MSGSTACK(this->_sm->desktop())->flash(Inkscape::NORMAL_MESSAGE, _("Receive queue empty."));
79 }
81 switch (first->type()) {
82 case CHANGE_REPEATABLE:
83 case CHANGE_NOT_REPEATABLE:
84 case CHANGE_COMMIT:
85 case DOCUMENT_BEGIN:
86 case DOCUMENT_END:
87 this->_sm->sendMessage(first->type(), first->sequence(), first->message(), first->recipient().c_str(), first->chatroom());
88 break;
89 default:
90 g_warning("MessageNode with unknown change type found in send queue; discarding message. This may lead to desynchronization!");
91 break;
92 }
94 this->_sd->send_queue->popFront();
96 return true;
97 }
99 bool
100 Callbacks::dispatchReceiveQueue()
101 {
102 CommitsQueue& rcq = this->_sd->recipients_committed_queue;
103 // See if we have any commits submitted.
104 if (!rcq.empty()) {
105 // Pick the first one off the queue.
106 ReceivedCommitEvent& committer = rcq.front();
108 // Find the commit event sender's receive queue.
109 ReceiveMessageQueue* rmq = this->_sd->receive_queues[committer];
111 if (rmq != NULL) {
112 if (!rmq->empty()) {
113 // Get the first message off the sender's receive queue.
114 MessageNode* msg = rmq->first();
116 // There are a few message change types that demand special processing;
117 // handle them here.
118 //
119 // TODO: clean this up. This should be a simple dispatching routine,
120 // and should not be performing operations like it's doing right now.
121 // These really should go into connection-establishment.cpp
122 // (although that should only happen after SessionManager itself
123 // is cleaned up).
124 switch(msg->type()) {
125 case CHANGE_COMMIT:
126 rcq.pop_front();
127 break;
128 case DOCUMENT_BEGIN:
129 if (this->_sm->session_data->status[WAITING_TO_SYNC_TO_CHAT]) {
130 this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 0);
131 this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 1);
132 }
133 break;
134 case DOCUMENT_END:
135 rcq.pop_front();
136 if (this->_sm->session_data->status[SYNCHRONIZING_WITH_CHAT]) {
137 this->_sm->sendMessage(CONNECTED_SIGNAL, 0, "", this->_sm->session_data->recipient, true);
138 this->_sm->session_data->status.set(SYNCHRONIZING_WITH_CHAT, 0);
139 this->_sm->session_data->status.set(IN_CHATROOM, 1);
140 } else {
141 this->_sm->sendMessage(CONNECTED_SIGNAL, 0, "", msg->sender().c_str(), false);
142 }
143 break;
144 case CHANGE_REPEATABLE:
145 case CHANGE_NOT_REPEATABLE:
146 default:
147 break;
148 }
151 // Pass the message to the received change handler.
152 this->_sm->receiveChange(msg->message());
153 SP_DT_MSGSTACK(this->_sm->desktop())->flashF(Inkscape::NORMAL_MESSAGE,
154 ngettext("Receiving change; %u change left to process.",
155 "Receiving change; %u changes left to process.",
156 rmq->size()),
157 rmq->size());
160 // Register this message as the latest message received from this
161 // sender.
162 rmq->setLatestProcessedPacket(msg->sequence());
164 // Pop this message off the receive queue.
165 rmq->popFront();
166 return true;
167 } else {
168 // This really shouldn't happen.
169 // If we have a commit request from a valid sender, there should
170 // be something in the receive queue to process. However,
171 // if a client is buggy or has managed to trick us into accepting
172 // a commit, we should handle the event gracefully.
173 g_warning("Processing commit, but no changes to commit were found; ignoring commit event.");
175 // Remove this sender from the commit list. If they want to commit
176 // later, they can.
177 rcq.pop_front();
178 return true;
179 }
180 } else {
181 // If the receive queue returned is NULL, then we don't know about
182 // this sender. Remove the sender from the commit list.
183 g_warning("Attempting to process commit from unknown sender; ignoring.");
184 rcq.pop_front();
185 return true;
186 }
187 } else {
188 return true;
189 }
190 }
192 }
194 }
197 /*
198 Local Variables:
199 mode:c++
200 c-file-style:"stroustrup"
201 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
202 indent-tabs-mode:nil
203 fill-column:99
204 End:
205 */
206 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :