0ba733a0c06c589dac944d233c02705b9f2ac0ec
1 /**
2 * Whiteboard session manager
3 * Chatroom message handler
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 #include <glibmm/i18n.h>
15 //#include <boost/lexical_cast.hpp>
17 #include "message-stack.h"
18 #include "desktop-handles.h"
19 #include "document.h"
21 #include "util/ucompose.hpp"
23 #include "xml/node.h"
25 #include "jabber_whiteboard/typedefs.h"
26 #include "jabber_whiteboard/message-utilities.h"
27 #include "jabber_whiteboard/message-queue.h"
28 #include "jabber_whiteboard/jabber-handlers.h"
29 #include "jabber_whiteboard/defines.h"
30 #include "jabber_whiteboard/session-manager.h"
31 #include "jabber_whiteboard/node-tracker.h"
32 #include "jabber_whiteboard/chat-handler.h"
33 #include "jabber_whiteboard/error-codes.h"
36 namespace Inkscape {
38 namespace Whiteboard {
40 ChatMessageHandler::ChatMessageHandler(SessionManager* sm) : _sm(sm)
41 {
43 }
45 ChatMessageHandler::~ChatMessageHandler()
46 {
48 }
50 LmHandlerResult
51 ChatMessageHandler::parse(LmMessage* message)
52 {
53 // Retrieve the message type
54 LmMessageType mtype = lm_message_get_type(message);
56 // Retrieve root node of message
57 LmMessageNode* root = lm_message_get_node(message);
58 if (root == NULL) {
59 g_warning("Received a chat message with NULL root node; discarding.");
60 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
61 }
63 LmMessageSubType msubtype;
66 msubtype = lm_message_get_sub_type(message);
68 switch (mtype) {
69 case LM_MESSAGE_TYPE_MESSAGE:
70 switch(msubtype) {
71 case LM_MESSAGE_SUB_TYPE_ERROR:
72 {
73 LmMessageNode* error = lm_message_node_get_child(root, "error");
74 if (error != NULL) {
75 this->_handleError(lm_message_node_get_attribute(error, "code"));
76 }
77 break;
78 }
79 case LM_MESSAGE_SUB_TYPE_GROUPCHAT:
80 {
81 // FIXME: We should be checking to see if we're in a room in the presence stanzas as indicated in
82 // <http://www.jabber.org/jeps/jep-0045.html#enter-pres> but current versions of mu-conference
83 // don't broadcast presence in the correct order.
84 //
85 // Therefore we need to use some sort of hacked-up method to make this work. We listen for
86 // the sentinel value in a groupchat message -- currently it is '[username] INKBOARD-JOINED' --
87 // and begin processing that way.
89 //LmMessageNode* body = lm_message_node_get_child(root, "body");
90 //if (body != NULL) {
91 //gchar const* val = lm_message_node_get_value(body);
92 //g_warning("hey - %s",val);
93 //if (strcmp(val, String::ucompose("%1 entered the room.", this->_sm->session_data->chat_handle).c_str()) == 0) {
94 // return this->_finishConnection(); break;
95 //} else {
96 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
97 break;
98 //}
99 //} else {
100 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
101 break;
102 //}
103 }
105 default:
106 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
107 break;
108 }
109 break;
110 case LM_MESSAGE_TYPE_PRESENCE:
111 // Retrieve the subtype.
112 switch (msubtype) {
113 case LM_MESSAGE_SUB_TYPE_ERROR:
114 {
115 g_warning("Could not connect to chatroom");
116 // Extract error type
117 LmMessageNode* error = lm_message_node_get_child(root, "error");
118 if (error != NULL) {
119 this->_handleError(lm_message_node_get_attribute(error, "code"));
120 }
121 // Reset status bits
122 this->_sm->session_data->status.set(CONNECTING_TO_CHAT, 0);
123 this->_sm->session_data->recipient = "";
124 this->_sm->session_data->chat_handle = "";
126 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
127 break;
128 }
130 case LM_MESSAGE_SUB_TYPE_AVAILABLE:
131 {
132 // Extract the handle
133 // (see JEP-0045, section 6.3.3 - <http://www.jabber.org/jeps/jep-0045.html#enter-pres>)
134 Glib::ustring sender = lm_message_node_get_attribute(root, MESSAGE_FROM);
135 Glib::ustring chatter = sender.substr(sender.find_last_of('/') + 1, sender.length());
136 if (chatter != this->_sm->session_data->chat_handle) {
137 this->_sm->session_data->chatters.insert(g_strdup(chatter.data()));
138 // Make a receive queue for this chatter
139 this->_sm->session_data->receive_queues[sender.raw()] = new ReceiveMessageQueue(this->_sm);
141 } else {
142 return this->_finishConnection(); break;
143 //g_warning("hmm, who is chatting %s",chatter);
144 // If the presence message is from ourselves, then we know that we
145 // have successfully entered the chatroom _and_ have received the entire room roster,
146 // and can therefore decide whether we need to synchronize with the rest of the room.
147 // (see JEP-0045, section 6.3.3 - <http://www.jabber.org/jeps/jep-0045.html#enter-pres>)
148 }
149 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
150 }
152 case LM_MESSAGE_SUB_TYPE_UNAVAILABLE:
153 {
154 Glib::ustring sender = lm_message_node_get_attribute(root, MESSAGE_FROM);
155 Glib::ustring chatter = sender.substr(sender.find_last_of('/') + 1, sender.length());
156 this->_sm->session_data->chatters.erase(chatter.data());
158 // Delete the message queue used by this sender
159 this->_sm->session_data->receive_queues.erase(sender.raw());
161 sp_desktop_message_stack(this->_sm->desktop())->flashF(Inkscape::INFORMATION_MESSAGE, _("<b>%s</b> has left the chatroom."), sender.c_str());
162 }
164 default:
165 // no idea what this message is; discard it
166 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
167 break;
168 }
169 break;
170 default:
171 break;
172 }
174 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
175 }
177 LmHandlerResult
178 ChatMessageHandler::_finishConnection()
179 {
180 if (this->_sm->session_data->status[CONNECTING_TO_CHAT]) {
181 this->_sm->session_data->status.set(CONNECTING_TO_CHAT, 0);
183 if (this->_sm->session_data->chatters.empty()) {
184 // We are the only one in the chatroom, so there is no
185 // need for synchronization
186 this->_sm->session_data->status.set(IN_CHATROOM, 1);
188 // Populate node tracker
189 KeyToNodeMap newids;
190 NodeToKeyMap newnodes;
191 NewChildObjectMessageList newchildren;
193 XML::Node* root = this->_sm->document()->rroot;
195 this->_sm->setupInkscapeInterface();
196 this->_sm->setupCommitListener();
198 for ( Inkscape::XML::Node *child = root->firstChild() ; child != NULL ; child = child->next() ) {
199 MessageUtilities::newObjectMessage(NULL, newids, newnodes, newchildren, this->_sm->node_tracker(), child, true);
200 }
202 this->_sm->node_tracker()->put(newids, newnodes);
203 // this->_sm->node_tracker()->dump();
205 } else {
206 this->_sm->session_data->status.set(WAITING_TO_SYNC_TO_CHAT, 1);
207 // Send synchronization request to chatroom
208 this->_sm->sendMessage(CHATROOM_SYNCHRONIZE_REQUEST, 0, "", this->_sm->session_data->recipient, true);
209 }
210 }
211 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
212 }
214 void
215 ChatMessageHandler::_handleError(char const* errcode)
216 {
217 // try {
218 unsigned int code = atoi(errcode);
220 // unsigned int code = boost::lexical_cast< unsigned int >(errcode);
222 Glib::ustring buf;
223 switch (code) {
224 case ErrorCodes::CHAT_HANDLE_IN_USE:
225 buf = String::ucompose(_("Nickname %1 is already in use. Please choose a different nickname."), this->_sm->session_data->chat_handle);
226 this->_sm->connectionError(buf);
227 break;
228 case ErrorCodes::SERVER_CONNECT_FAILED:
229 buf = _("An error was encountered while attempting to connect to the server.");
230 this->_sm->connectionError(buf);
231 break;
232 default:
233 break;
234 }
235 // } catch (boost::bad_lexical_cast&) {
237 // }
238 }
240 }
242 }
244 /*
245 Local Variables:
246 mode:c++
247 c-file-style:"stroustrup"
248 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
249 indent-tabs-mode:nil
250 fill-column:99
251 End:
252 */
253 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :