1 /* Copyright (C) 2007 One Laptop Per Child
2 * Author: Marc Maurer <uwog@uwog.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "SugarUnixAccountHandler.h"
21 #include "SugarBuddy.h"
22 #include <account/xp/AccountEvent.h>
23 #include <account/xp/Event.h>
24 #include <core/account/xp/SessionEvent.h>
25 #include <session/xp/AbiCollabSessionManager.h>
26 #include <session/xp/AbiCollab.h>
27 #include <ev_EditMethod.h>
28 #include <xap_App.h>
29 #include <fv_View.h>
30
31 // some fucntion prototype declarations
32 static bool s_offerTube(AV_View* v, EV_EditMethodCallData *d);
33 static bool s_joinTube(AV_View* v, EV_EditMethodCallData *d);
34 static bool s_disconnectTube(AV_View* v, EV_EditMethodCallData *d);
35 static bool s_buddyJoined(AV_View* v, EV_EditMethodCallData *d);
36 static bool s_buddyLeft(AV_View* v, EV_EditMethodCallData *d);
37 static DBusHandlerResult s_dbus_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data);
38
39 #define INTERFACE "com.abisource.abiword.abicollab.olpc"
40 #define SEND_ALL_METHOD "SendAll"
41 #define SEND_ONE_METHOD "SendOne"
42
43 SugarAccountHandler* SugarAccountHandler::m_pHandler = NULL;
getHandler()44 SugarAccountHandler* SugarAccountHandler::getHandler() { return m_pHandler; }
45
SugarAccountHandler()46 SugarAccountHandler::SugarAccountHandler()
47 : AccountHandler(),
48 m_pTube(NULL),
49 m_bIsInSession(false)
50 {
51 UT_DEBUGMSG(("SugarAccountHandler::SugarAccountHandler()\n"));
52 m_pHandler = this;
53 _registerEditMethods();
54 }
55
~SugarAccountHandler()56 SugarAccountHandler::~SugarAccountHandler()
57 {
58 m_pHandler = NULL;
59 disconnect();
60 }
61
getDescription()62 UT_UTF8String SugarAccountHandler::getDescription()
63 {
64 return "Sugar Presence Service";
65 }
66
getDisplayType()67 UT_UTF8String SugarAccountHandler::getDisplayType()
68 {
69 return "Sugar Presence Service";
70 }
71
getStaticStorageType()72 UT_UTF8String SugarAccountHandler::getStaticStorageType()
73 {
74 return SUGAR_STATIC_STORAGE_TYPE;
75 }
76
loadProperties()77 void SugarAccountHandler::loadProperties()
78 {
79 // no need to implement this as we will be getting
80 // all our info always directly from sugar
81 }
82
storeProperties()83 void SugarAccountHandler::storeProperties()
84 {
85 // no need to implement this as we will be getting
86 // all our info always directly from sugar
87 }
88
connect()89 ConnectResult SugarAccountHandler::connect()
90 {
91 UT_ASSERT_HARMLESS(UT_NOT_REACHED);
92 return CONNECT_SUCCESS;
93 }
94
disconnect()95 bool SugarAccountHandler::disconnect()
96 {
97 if (m_pTube)
98 {
99 dbus_connection_unref(m_pTube);
100 m_pTube = NULL;
101 }
102 return true;
103 }
104
isOnline()105 bool SugarAccountHandler::isOnline()
106 {
107 return true;
108 }
109
constructBuddy(const PropertyMap & props)110 BuddyPtr SugarAccountHandler::constructBuddy(const PropertyMap& props)
111 {
112 UT_DEBUGMSG(("SugarAccountHandler::constructBuddy()\n"));
113
114 PropertyMap::const_iterator cit = props.find("dbusAddress");
115 UT_return_val_if_fail(cit != props.end(), SugarBuddyPtr());
116 UT_return_val_if_fail(cit->second.size() > 0, SugarBuddyPtr());
117
118 UT_DEBUGMSG(("Constructing SugarBuddy (dbusAddress: %s)\n", cit->second.c_str()));
119 // NOTE: the buddy name must uniquely identify a buddy, and I can't
120 // guarantee at the moment that the name we could get from the sugar
121 // presence framework would always be unique to one buddy; hence the
122 // dbus address will do for now
123 return boost::shared_ptr<SugarBuddy>(new SugarBuddy(this, cit->second.c_str()));
124 }
125
constructBuddy(const std::string & descriptor,BuddyPtr)126 BuddyPtr SugarAccountHandler::constructBuddy(const std::string& descriptor, BuddyPtr /*pBuddy*/)
127 {
128 UT_DEBUGMSG(("SugarAccountHandler::constructBuddy() - descriptor: %s\n", descriptor.c_str()));
129
130 std::string uri_id = "sugar://";
131 UT_return_val_if_fail(descriptor.size() > uri_id.size(), SugarBuddyPtr());
132
133 std::string dbusAddress = descriptor.substr(uri_id.size());
134 SugarBuddyPtr pBuddy = getBuddy(dbusAddress.c_str());
135 UT_return_val_if_fail(pBuddy, SugarBuddyPtr());
136
137 return pBuddy;
138 }
139
recognizeBuddyIdentifier(const std::string & identifier)140 bool SugarAccountHandler::recognizeBuddyIdentifier(const std::string& identifier)
141 {
142 std::string uri_id = "sugar://";
143
144 if (identifier.compare(0, uri_id.size(), uri_id) != 0)
145 return false;
146
147 // The rest of the buddy descriptor contains the dbus address, which we
148 // can't really check.
149
150 return true;
151 }
152
handleEvent(Session &)153 void SugarAccountHandler::handleEvent(Session& /*pSession*/)
154 {
155 // TODO: implement me
156 }
157
signal(const Event & event,BuddyPtr pSource)158 void SugarAccountHandler::signal(const Event& event, BuddyPtr pSource)
159 {
160 UT_DEBUGMSG(("SugarAccountHandler::signal()\n"));
161
162 AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
163 UT_return_if_fail(pManager);
164
165 switch (event.getClassType())
166 {
167 case PCT_CloseSessionEvent:
168 {
169 UT_DEBUGMSG(("Got a PCT_CloseSessionEvent\n"));
170 const CloseSessionEvent cse = static_cast<const CloseSessionEvent&>(event);
171 UT_return_if_fail(!pSource); // we shouldn't receive these events over the wire on this backend
172
173 // If the session that is closed was started by us, then disconnect from
174 // the tube. Otherwise, just drop the event on the floor....
175
176 if (cse.getSessionId() == m_sSessionId)
177 {
178 UT_DEBUGMSG(("We host session %s, disconnecting...\n", cse.getSessionId().utf8_str()));
179 disconnect();
180 }
181 }
182 break;
183
184 case PCT_AccountBuddyAddDocumentEvent:
185 {
186 // Prevent joining other dochandles that come over the wire after having
187 // already joined the one we received just now. This should ofcourse never
188 // happen, but it will in practice because of a Write/Activity bug.
189 // See ... for details.
190 if (m_bIsInSession)
191 {
192 UT_DEBUGMSG(("Received a bogus AccountBuddyAddDocumentEvent: we are already connected to a session.\n"));
193 return;
194 }
195
196 // We've received a document handle from the other side. This obviously only
197 // makes sense for a joining party, not an offering one: the offering party
198 // should never even receive such an event
199
200 UT_DEBUGMSG(("We received a document handle from an offering party; let's join it immediately!\n"));
201 AccountBuddyAddDocumentEvent& abade = (AccountBuddyAddDocumentEvent&)event;
202
203 // FIXME: should we check if we were waiting for a document to come our way?
204
205 DocHandle* pDocHandle = abade.getDocHandle();
206 UT_return_if_fail(pDocHandle);
207
208 UT_DEBUGMSG(("Got dochandle, going to initiate a join on it!\n"));
209 pManager->joinSessionInitiate(pSource, pDocHandle);
210 m_bIsInSession = true;
211 }
212 break;
213
214 default:
215 AccountHandler::signal(event, pSource);
216 break;
217 }
218 }
219
send(const Packet * pPacket)220 bool SugarAccountHandler::send(const Packet* pPacket)
221 {
222 UT_DEBUGMSG(("SugarAccountHandler::send(const Packet* pPacket)\n"));
223 UT_return_val_if_fail(pPacket, false);
224 UT_return_val_if_fail(m_pTube, false);
225
226 return _send(pPacket, NULL);
227 }
228
send(const Packet * pPacket,BuddyPtr pBuddy)229 bool SugarAccountHandler::send(const Packet* pPacket, BuddyPtr pBuddy)
230 {
231 UT_DEBUGMSG(("SugarAccountHandler::send(const Packet* pPacket, const Buddy& buddy)\n"));
232 UT_return_val_if_fail(pPacket, false);
233 UT_return_val_if_fail(m_pTube, false);
234
235 SugarBuddyPtr pSugarBuddy = boost::static_pointer_cast<SugarBuddy>(pBuddy);
236 UT_DEBUGMSG(("Sending packet to sugar buddy on dbus addess: %s\n", pSugarBuddy->getDBusAddress().utf8_str()));
237
238 return _send(pPacket, pSugarBuddy->getDBusAddress().utf8_str());
239 }
240
createPacket(const std::string & packet,BuddyPtr pBuddy)241 Packet* SugarAccountHandler::createPacket(const std::string& packet, BuddyPtr pBuddy)
242 {
243 return _createPacket(packet, pBuddy);
244 }
245
_send(const Packet * pPacket,const char * dbusAddress)246 bool SugarAccountHandler::_send(const Packet* pPacket, const char* dbusAddress)
247 {
248 UT_DEBUGMSG(("SugarAccountHandler::_send() - dbusAddress: %s\n", dbusAddress ? dbusAddress : "(broadcast)"));
249 UT_return_val_if_fail(pPacket, false);
250 UT_return_val_if_fail(m_pTube, false);
251
252 DBusMessage* pMessage = dbus_message_new_method_call(dbusAddress, "/org/laptop/Sugar/Presence/Buddies", INTERFACE, SEND_ONE_METHOD);
253 if (dbusAddress)
254 {
255 // TODO: isn't this redudant? we already set a destination in dbus_message_new_method_call()
256 if (!dbus_message_set_destination(pMessage, dbusAddress))
257 {
258 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
259 dbus_message_unref(pMessage);
260 return false;
261 }
262 UT_DEBUGMSG(("Destination (%s) set on message\n", dbusAddress));
263 }
264
265 // we don't want replies, because then then easily run into dbus timeout problems
266 // when sending large packets
267 // TODO: this means we should probably use signals though
268 dbus_message_set_no_reply(pMessage, TRUE);
269
270 // make to-be-send-stream once
271 std::string data;
272 _createPacketStream( data, pPacket );
273
274 const char* packet_contents = &data[0];
275 if (!dbus_message_append_args(pMessage, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &packet_contents, data.size(), DBUS_TYPE_INVALID))
276 {
277 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
278 dbus_message_unref(pMessage);
279 return false;
280 }
281
282 UT_DEBUGMSG(("Appended packet contents\n"));
283
284 bool sent = dbus_connection_send(m_pTube, pMessage, NULL);
285 UT_ASSERT_HARMLESS(sent);
286 if (sent)
287 dbus_connection_flush(m_pTube);
288 dbus_message_unref(pMessage);
289
290 return sent;
291 }
292
_registerEditMethods()293 void SugarAccountHandler::_registerEditMethods()
294 {
295 UT_DEBUGMSG(("SugarAccountHandler::_registerEditMethods()\n"));
296
297 // First we need to get a pointer to the application itself.
298 XAP_App *pApp = XAP_App::getApp();
299 EV_EditMethodContainer* pEMC = pApp->getEditMethodContainer();
300
301 EV_EditMethod *emOfferTube = new EV_EditMethod (
302 "com.abisource.abiword.abicollab.olpc.offerTube", // name of callback function
303 s_offerTube, // callback function itself.
304 0, // no additional data required.
305 "" // description -- allegedly never used for anything
306 );
307 pEMC->addEditMethod(emOfferTube);
308
309 EV_EditMethod *emJoinTube = new EV_EditMethod (
310 "com.abisource.abiword.abicollab.olpc.joinTube", // name of callback function
311 s_joinTube, // callback function itself.
312 0, // no additional data required.
313 "" // description -- allegedly never used for anything
314 );
315 pEMC->addEditMethod(emJoinTube);
316
317 EV_EditMethod *emDisconnectTube = new EV_EditMethod (
318 "com.abisource.abiword.abicollab.olpc.disconnectTube", // name of callback function
319 s_disconnectTube, // callback function itself.
320 0, // no additional data required.
321 "" // description -- allegedly never used for anything
322 );
323 pEMC->addEditMethod(emDisconnectTube);
324
325 EV_EditMethod *emBuddyJoined = new EV_EditMethod (
326 "com.abisource.abiword.abicollab.olpc.buddyJoined", // name of callback function
327 s_buddyJoined, // callback function itself.
328 0, // no additional data required.
329 "" // description -- allegedly never used for anything
330 );
331 pEMC->addEditMethod(emBuddyJoined);
332
333 EV_EditMethod *emBuddyLeft = new EV_EditMethod (
334 "com.abisource.abiword.abicollab.olpc.buddyLeft", // name of callback function
335 s_buddyLeft, // callback function itself.
336 0, // no additional data required.
337 "" // description -- allegedly never used for anything
338 );
339 pEMC->addEditMethod(emBuddyLeft);
340
341 }
342
_handlePacket(Packet * packet,BuddyPtr buddy)343 void SugarAccountHandler::_handlePacket(Packet* packet, BuddyPtr buddy)
344 {
345 UT_DEBUGMSG(("SugarAccountHandler::_handlePacket()\n"));
346
347 UT_return_if_fail(packet);
348 UT_return_if_fail(buddy);
349
350 switch (packet->getClassType())
351 {
352 case PCT_JoinSessionRequestResponseEvent:
353 {
354 JoinSessionRequestResponseEvent* jsre = static_cast<JoinSessionRequestResponseEvent*>( packet );
355 m_sSessionId = jsre->getSessionId();
356 // Let the AccountHandler::_handlePacket() call below handle the actual joining.
357 // This could mean that when the actual joining fails (unlikely), we have
358 // a bogus session ID stored. I doubt it will ever really be a problem though.
359 break;
360 }
361
362 default:
363 break;
364 }
365
366 AccountHandler::_handlePacket(packet, buddy);
367 }
368
offerTube(FV_View * pView,const UT_UTF8String & tubeDBusAddress)369 bool SugarAccountHandler::offerTube(FV_View* pView, const UT_UTF8String& tubeDBusAddress)
370 {
371 UT_DEBUGMSG(("SugarAccountHandler::offerTube()\n"));
372 UT_return_val_if_fail(pView, false);
373
374 AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
375 UT_return_val_if_fail(pManager, false);
376
377 // TODO: check that we aren't already in a session; this backend can only host one session at a time (for now)
378
379 PD_Document * pDoc = pView->getDocument();
380 UT_return_val_if_fail(pDoc, false);
381
382 UT_DEBUGMSG(("Got tube address: %s\n", tubeDBusAddress.utf8_str()));
383
384 m_pTube = dbus_connection_open(tubeDBusAddress.utf8_str(), NULL);
385 UT_return_val_if_fail(m_pTube, false);
386
387 UT_DEBUGMSG(("Opened a dbus connection for tube: %s\n", tubeDBusAddress.utf8_str()));
388
389 UT_DEBUGMSG(("Adding dbus handlers to the main loop\n"));
390 dbus_connection_setup_with_g_main(m_pTube, NULL);
391
392 UT_DEBUGMSG(("Adding message filter\n"));
393 dbus_connection_add_filter(m_pTube, s_dbus_handle_message, this, NULL);
394
395 // start hosting a session on the current document
396 UT_return_val_if_fail(m_sSessionId == "", false);
397 AbiCollab* pSession = pManager->startSession(pDoc, m_sSessionId, this, true, NULL, "");
398 UT_return_val_if_fail(pSession, false);
399
400 // we are "connected" now, time to start sending out, and listening to messages (such as events)
401 pManager->registerEventListener(this);
402
403 m_bIsInSession = true;
404
405 return true;
406 }
407
joinTube(FV_View * pView,const UT_UTF8String & tubeDBusAddress)408 bool SugarAccountHandler::joinTube(FV_View* pView, const UT_UTF8String& tubeDBusAddress)
409 {
410 UT_DEBUGMSG(("SugarAccountHandler::joinTube()\n"));
411 UT_return_val_if_fail(pView, false);
412
413 AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
414 UT_return_val_if_fail(pManager, false);
415
416 // TODO: check that we aren't already in a session; this backend can only join one session at a time (for now)
417
418 m_pTube = dbus_connection_open(tubeDBusAddress.utf8_str(), NULL);
419 UT_return_val_if_fail(m_pTube, false);
420
421 UT_DEBUGMSG(("Opened a dbus connection for tube: %s\n", tubeDBusAddress.utf8_str()));
422
423 UT_DEBUGMSG(("Adding dbus handlers to the main loop\n"));
424 dbus_connection_setup_with_g_main(m_pTube, NULL);
425
426 UT_DEBUGMSG(("Adding message filter\n"));
427 dbus_connection_add_filter(m_pTube, s_dbus_handle_message, this, NULL);
428
429 // we are "connected" now, time to start sending out, and listening to messages (such as events)
430 pManager->registerEventListener(this);
431
432 // broadcast a request for sessions; if everything is alright then we should
433 // receive exactly 1 session in all the responses combined
434 UT_DEBUGMSG(("Sending a broadcast GetSessionsEvent\n"));
435 GetSessionsEvent event;
436 send(&event);
437
438 return true;
439 }
440
disconnectTube(FV_View * pView)441 bool SugarAccountHandler::disconnectTube(FV_View* pView)
442 {
443 UT_DEBUGMSG(("SugarAccountHandler::disconnectTube()\n"));
444 UT_return_val_if_fail(pView, false);
445
446 AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
447 UT_return_val_if_fail(pManager, false);
448
449 PD_Document * pDoc = pView->getDocument();
450 UT_return_val_if_fail(pDoc, false);
451
452 AbiCollab* pSession = pManager->getSession(pDoc);
453 UT_return_val_if_fail(pSession, false);
454 pManager->disconnectSession(pSession);
455
456 return true;
457 }
458
joinBuddy(FV_View * pView,const UT_UTF8String & buddyDBusAddress)459 bool SugarAccountHandler::joinBuddy(FV_View* pView, const UT_UTF8String& buddyDBusAddress)
460 {
461 UT_DEBUGMSG(("SugarAccountHandler::joinBuddy() - buddyDBusAddress: %s\n", buddyDBusAddress.utf8_str()));
462 UT_return_val_if_fail(pView, false);
463
464 SugarBuddyPtr pBuddy = boost::shared_ptr<SugarBuddy>(new SugarBuddy(this, buddyDBusAddress));
465 addBuddy(pBuddy);
466
467 return true;
468 }
469
disjoinBuddy(FV_View * pView,const UT_UTF8String & buddyDBusAddress)470 bool SugarAccountHandler::disjoinBuddy(FV_View* pView, const UT_UTF8String& buddyDBusAddress)
471 {
472 UT_DEBUGMSG(("SugarAccountHandler::disjoinBuddy()\n"));
473 UT_return_val_if_fail(pView, false);
474
475 AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
476 UT_return_val_if_fail(pManager, false);
477
478 PD_Document * pDoc = pView->getDocument();
479 UT_return_val_if_fail(pDoc, false);
480
481 m_ignoredBuddies.erase( buddyDBusAddress ); // buddy name is buddyDBusAddress!
482
483 BuddyPtr pBuddy = getBuddy(buddyDBusAddress);
484 UT_return_val_if_fail(pBuddy, false);
485
486 pManager->removeBuddy(pBuddy, false);
487
488 // TODO: shouldn't we remove this buddy from our own buddy list?
489
490 return true;
491 }
492
forceDisconnectBuddy(BuddyPtr pBuddy)493 void SugarAccountHandler::forceDisconnectBuddy(BuddyPtr pBuddy)
494 {
495 UT_return_if_fail(pBuddy);
496 m_ignoredBuddies.insert(pBuddy->getDescriptor(false));
497 }
498
hasAccess(const std::vector<std::string> &,BuddyPtr pBuddy)499 bool SugarAccountHandler::hasAccess(const std::vector<std::string>& /*vAcl*/, BuddyPtr pBuddy)
500 {
501 UT_DEBUGMSG(("SugarAccountHandler::hasAccess() - pBuddy: %s\n", pBuddy->getDescriptor(false).utf8_str()));
502 UT_return_val_if_fail(pBuddy, false);
503
504 // The sugar presence service is responsible for access control. Just do a quick
505 // check here to see if we know the buddy on this account, and
506 // then be done with it.
507 SugarBuddyPtr pSugarBuddy = boost::dynamic_pointer_cast<SugarBuddy>(pBuddy);
508 UT_return_val_if_fail(pSugarBuddy, false);
509
510 SugarBuddyPtr pExistingBuddy = getBuddy(pSugarBuddy->getDBusAddress());
511 if (!pExistingBuddy)
512 return false;
513
514 return true;
515 }
516
getBuddy(const UT_UTF8String & dbusAddress)517 SugarBuddyPtr SugarAccountHandler::getBuddy(const UT_UTF8String& dbusAddress)
518 {
519 for (std::vector<BuddyPtr>::iterator it = getBuddies().begin(); it != getBuddies().end(); it++)
520 {
521 SugarBuddyPtr pBuddy = boost::static_pointer_cast<SugarBuddy>(*it);
522 UT_continue_if_fail(pBuddy);
523 if (pBuddy->getDBusAddress() == dbusAddress)
524 return pBuddy;
525 }
526 return SugarBuddyPtr();
527 }
528
s_offerTube(AV_View * v,EV_EditMethodCallData * d)529 static bool s_offerTube(AV_View* v, EV_EditMethodCallData *d)
530 {
531 UT_DEBUGMSG(("s_offerTube()\n"));
532 UT_return_val_if_fail(v, false);
533 UT_return_val_if_fail(d && d->m_pData && d->m_dataLength > 0, false);
534
535 FV_View* pView = static_cast<FV_View *>(v);
536 UT_UTF8String tubeDBusAddress(d->m_pData, d->m_dataLength);
537
538 SugarAccountHandler* pHandler = SugarAccountHandler::getHandler();
539 UT_return_val_if_fail(pHandler, false);
540 return pHandler->offerTube(pView, tubeDBusAddress);
541 }
542
s_joinTube(AV_View * v,EV_EditMethodCallData * d)543 static bool s_joinTube(AV_View* v, EV_EditMethodCallData *d)
544 {
545 UT_DEBUGMSG(("s_joinTube()\n"));
546 UT_return_val_if_fail(v, false);
547 UT_return_val_if_fail(d && d->m_pData && d->m_dataLength > 0, false);
548
549 FV_View* pView = static_cast<FV_View *>(v);
550 UT_UTF8String tubeDBusAddress(d->m_pData, d->m_dataLength);
551 UT_DEBUGMSG(("Got tube address: %s\n", tubeDBusAddress.utf8_str()));
552
553 SugarAccountHandler* pHandler = SugarAccountHandler::getHandler();
554 UT_return_val_if_fail(pHandler, false);
555 return pHandler->joinTube(pView, tubeDBusAddress);
556 }
557
s_disconnectTube(AV_View * v,EV_EditMethodCallData *)558 static bool s_disconnectTube(AV_View* v, EV_EditMethodCallData */*d*/)
559 {
560 UT_DEBUGMSG(("s_disconnectTube()\n"));
561 UT_return_val_if_fail(v, false);
562 FV_View* pView = static_cast<FV_View *>(v);
563
564 SugarAccountHandler* pHandler = SugarAccountHandler::getHandler();
565 UT_return_val_if_fail(pHandler, false);
566 return pHandler->disconnectTube(pView);
567 }
568
s_buddyJoined(AV_View * v,EV_EditMethodCallData * d)569 static bool s_buddyJoined(AV_View* v, EV_EditMethodCallData *d)
570 {
571 UT_DEBUGMSG(("s_buddyJoined()\n"));
572 UT_return_val_if_fail(SugarAccountHandler::getHandler(), false);
573 UT_return_val_if_fail(d && d->m_pData && d->m_dataLength > 0, false);
574
575 FV_View* pView = static_cast<FV_View *>(v);
576 UT_UTF8String buddyPath(d->m_pData, d->m_dataLength);
577 UT_DEBUGMSG(("Adding buddy with dbus path: %s\n", buddyPath.utf8_str()));
578
579 SugarAccountHandler* pHandler = SugarAccountHandler::getHandler();
580 UT_return_val_if_fail(pHandler, false);
581 return pHandler->joinBuddy(pView, buddyPath);
582 }
583
s_buddyLeft(AV_View * v,EV_EditMethodCallData * d)584 static bool s_buddyLeft(AV_View* v, EV_EditMethodCallData *d)
585 {
586 UT_DEBUGMSG(("s_buddyLeft()\n"));
587 UT_return_val_if_fail(SugarAccountHandler::getHandler(), false);
588 UT_return_val_if_fail(d && d->m_pData && d->m_dataLength > 0, false);
589
590 FV_View* pView = static_cast<FV_View *>(v);
591 UT_UTF8String buddyPath(d->m_pData, d->m_dataLength);
592 UT_DEBUGMSG(("Removing buddy with dbus path %s\n", buddyPath.utf8_str()));
593
594 SugarAccountHandler* pHandler = SugarAccountHandler::getHandler();
595 UT_return_val_if_fail(pHandler, false);
596
597 return pHandler->disjoinBuddy(pView, buddyPath);
598 }
599
s_dbus_handle_message(DBusConnection * connection,DBusMessage * message,void * user_data)600 DBusHandlerResult s_dbus_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data)
601 {
602 UT_DEBUGMSG(("s_dbus_handle_message()\n"));
603 UT_return_val_if_fail(connection, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
604 UT_return_val_if_fail(message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
605 UT_return_val_if_fail(user_data, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
606 SugarAccountHandler* pHandler = reinterpret_cast<SugarAccountHandler*>(user_data);
607
608 if (dbus_message_is_method_call(message, INTERFACE, SEND_ONE_METHOD))
609 {
610 UT_DEBUGMSG(("%s message accepted!\n", SEND_ONE_METHOD));
611
612 const char* senderDBusAddress = dbus_message_get_sender(message);
613
614 DBusError error;
615 dbus_error_init (&error);
616 const char* packet_data = 0;
617 int packet_size = 0;
618 if (dbus_message_get_args(message, &error,
619 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &packet_data, &packet_size,
620 DBUS_TYPE_INVALID))
621 {
622 UT_DEBUGMSG(("Received packet from %s\n", senderDBusAddress));
623
624 if (!pHandler->isIgnoredBuddy(senderDBusAddress))
625 {
626 // import the packet
627 BuddyPtr pBuddy = pHandler->getBuddy(senderDBusAddress);
628 if (!pBuddy)
629 {
630 // this can actually happen, for example when joining a tube
631 // we send out a broadcast GetSessionsEvent. Responses from
632 // that can return before joinBuddy() was called for that buddy.
633 pBuddy = boost::shared_ptr<SugarBuddy>(new SugarBuddy( pHandler, senderDBusAddress));
634 pHandler->addBuddy(pBuddy);
635 }
636
637 // FIXME: inefficient copying of data
638 std::string packet_str(packet_size, ' ');
639 memcpy(&packet_str[0], packet_data, packet_size);
640 Packet* pPacket = pHandler->createPacket(packet_str, pBuddy);
641 UT_return_val_if_fail(pPacket, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); // TODO: shouldn't we just disconnect here?
642
643 // handle!
644 pHandler->handleMessage(pPacket, pBuddy);
645 }
646
647 //dbus_free(packet);
648 return DBUS_HANDLER_RESULT_HANDLED;
649 }
650 else
651 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
652 }
653
654 UT_DEBUGMSG(("Unhandled message\n"));
655 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
656 }
657