1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2013-2014 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "dbusinterface.h"
21
22 #include <boost/shared_ptr.hpp>
23 #include <cassert>
24 #include <cstdarg>
25 #include <cstring>
26 #include <dbus/dbus.h>
27 #include <list>
28 #include <map>
29 #include <poll.h>
30
31 #include <licq/logging/log.h>
32 #include <licq/mainloop.h>
33
34 namespace LicqDbus
35 {
36
37 /**
38 * Object to handle a DBusWatch in the main loop
39 */
40 class WatchHandler : public Licq::MainLoopCallback
41 {
42 public:
43 typedef boost::shared_ptr<WatchHandler> Ptr;
44
45 WatchHandler(int id, Licq::MainLoop& mainLoop, DBusConnection* conn, DBusWatch* watch);
46 ~WatchHandler();
47 void toggle();
48
49 private:
50 // From MainLoopCallback
51 void rawFileEvent(int id, int fd, int revents);
52
53 int myId;
54 Licq::MainLoop& myMainLoop;
55 DBusConnection* myConn;
56 DBusWatch* myWatch;
57 };
58
59
60 /**
61 * Object to handle a DBusTimeout in the main loop
62 */
63 class TimeoutHandler : public Licq::MainLoopCallback
64 {
65 public:
66 typedef boost::shared_ptr<TimeoutHandler> Ptr;
67
68 TimeoutHandler(int id, Licq::MainLoop& mainLoop, DBusConnection* conn, DBusTimeout* timeout);
69 ~TimeoutHandler();
70 void toggle();
71
72 private:
73 // From MainLoopCallback
74 void timeoutEvent(int id);
75
76 int myId;
77 Licq::MainLoop& myMainLoop;
78 DBusConnection* myConn;
79 DBusTimeout* myTimeout;
80 };
81
82
83 typedef std::map<DBusWatch*,WatchHandler::Ptr> WatchMap;
84 typedef std::map<DBusTimeout*,TimeoutHandler::Ptr> TimeoutMap;
85
86
87 /**
88 * DbusInterface internals
89 */
90 class DbusInterface::Private
91 {
92 public:
Private(DbusInterface * interface,Licq::MainLoop & mainLoop,DbusCallback * callback,bool systemBus)93 Private(DbusInterface* interface, Licq::MainLoop& mainLoop, DbusCallback* callback, bool systemBus)
94 : myInterface(interface), myMainLoop(mainLoop), myCallback(callback), mySystemBus(systemBus)
95 { /* Empty */ }
96
97 // Callbacks from libdbus
98 static dbus_bool_t addWatchCb(DBusWatch* watch, void* data);
99 static void removeWatchCb(DBusWatch* watch, void* data);
100 static void toggleWatchCb(DBusWatch* watch, void* data);
101 static dbus_bool_t addTimeoutCb(DBusTimeout* timeout, void* data);
102 static void removeTimeoutCb(DBusTimeout* timeout, void* data);
103 static void toggleTimeoutCb(DBusTimeout* timeout, void* data);
104 static DBusHandlerResult handleMessage(DBusConnection* connection, DBusMessage* message, void* data);
105
106 static bool addMsgArgs(DBusMessageIter* args, const char* fmt, va_list ap);
107
108 DbusInterface* myInterface;
109 Licq::MainLoop& myMainLoop;
110 DbusCallback* myCallback;
111 DBusConnection* myConn;
112 WatchMap myWatches;
113 TimeoutMap myTimeouts;
114 int myNextWatchId;
115 int myNextTimeoutId;
116 bool mySystemBus;
117 };
118
119 } // namespace LicqDbus
120
121
122 using namespace LicqDbus;
123
124
dbusConnected()125 void DbusCallback::dbusConnected()
126 { /* Empty */ }
127
dbusDisconnected()128 void DbusCallback::dbusDisconnected()
129 { /* Empty */ }
130
dbusMethod(const char * path,const char * iface,const char * member,DBusMessage *,DBusMessageIter *,const char *)131 int DbusCallback::dbusMethod(const char* path, const char* iface, const char* member,
132 DBusMessage* /*msgref*/, DBusMessageIter* /*argref*/, const char* /*fmt*/)
133 {
134 Licq::gLog.info("Unhandled D-Bus method call '%s' to '%s' interface '%s'", member, path, iface);
135 return DbusInterface::ErrorUnknownInterface;
136 }
137
dbusSignal(const char * path,const char * iface,const char * member,DBusMessage *,DBusMessageIter *,const char *)138 void DbusCallback::dbusSignal(const char* path, const char* iface, const char* member,
139 DBusMessage* /*msgref*/, DBusMessageIter* /*argref*/, const char* /*fmt*/)
140 {
141 Licq::gLog.info("Unhandled D-Bus signal call '%s' to '%s' interface '%s'", member, path, iface);
142 }
143
144
WatchHandler(int id,Licq::MainLoop & mainLoop,DBusConnection * conn,DBusWatch * watch)145 WatchHandler::WatchHandler(int id, Licq::MainLoop& mainLoop, DBusConnection* conn, DBusWatch* watch)
146 : myId(id),
147 myMainLoop(mainLoop),
148 myConn(conn),
149 myWatch(watch)
150 {
151 toggle();
152 }
153
~WatchHandler()154 WatchHandler::~WatchHandler()
155 {
156 myMainLoop.removeCallback(this);
157 }
158
toggle()159 void WatchHandler::toggle()
160 {
161 if (dbus_watch_get_enabled(myWatch))
162 {
163 int fd = dbus_watch_get_unix_fd(myWatch);
164 unsigned int flags = dbus_watch_get_flags(myWatch);
165
166 int events = 0;
167 if (flags & DBUS_WATCH_READABLE)
168 events |= POLLIN;
169 if (flags & DBUS_WATCH_WRITABLE)
170 events |= POLLOUT;
171
172 myMainLoop.addRawFile(fd, this, events, myId);
173 }
174 else
175 {
176 myMainLoop.removeCallback(this);
177 }
178 }
179
rawFileEvent(int,int,int revents)180 void WatchHandler::rawFileEvent(int /*id*/, int /*fd*/, int revents)
181 {
182 // Convert returned poll events to flags used by dbus watch
183 unsigned int flags = 0;
184 if (revents & POLLIN) flags |= DBUS_WATCH_READABLE;
185 if (revents & POLLOUT) flags |= DBUS_WATCH_WRITABLE;
186 if (revents & POLLERR) flags |= DBUS_WATCH_ERROR;
187 if (revents & POLLHUP) flags |= DBUS_WATCH_HANGUP;
188
189 dbus_watch_handle(myWatch, flags);
190
191 while (dbus_connection_dispatch(myConn) == DBUS_DISPATCH_DATA_REMAINS)
192 { /* empty */ }
193 }
194
addWatchCb(DBusWatch * watch,void * data)195 dbus_bool_t DbusInterface::Private::addWatchCb(DBusWatch* watch, void* data)
196 {
197 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
198
199 assert(d->myWatches.count(watch) == 0);
200
201 // Reset counter if no other watches exist
202 if (d->myWatches.empty())
203 d->myNextWatchId = 1;
204
205 d->myWatches.insert(std::make_pair(watch,
206 new WatchHandler(d->myNextWatchId++, d->myMainLoop, d->myConn, watch)));
207
208 return true;
209 }
210
removeWatchCb(DBusWatch * watch,void * data)211 void DbusInterface::Private::removeWatchCb(DBusWatch* watch, void* data)
212 {
213 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
214 d->myWatches.erase(watch);
215 }
216
toggleWatchCb(DBusWatch * watch,void * data)217 void DbusInterface::Private::toggleWatchCb(DBusWatch* watch, void* data)
218 {
219 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
220
221 WatchMap::iterator iter(d->myWatches.find(watch));
222 assert(iter != d->myWatches.end());
223
224 iter->second->toggle();
225 }
226
227
TimeoutHandler(int id,Licq::MainLoop & mainLoop,DBusConnection * conn,DBusTimeout * timeout)228 TimeoutHandler::TimeoutHandler(int id, Licq::MainLoop& mainLoop, DBusConnection* conn, DBusTimeout* timeout)
229 : myId(id),
230 myMainLoop(mainLoop),
231 myConn(conn),
232 myTimeout(timeout)
233 {
234 toggle();
235 }
236
~TimeoutHandler()237 TimeoutHandler::~TimeoutHandler()
238 {
239 myMainLoop.removeCallback(this);
240 }
241
toggle()242 void TimeoutHandler::toggle()
243 {
244 if (dbus_timeout_get_enabled(myTimeout))
245 {
246 myMainLoop.addTimeout(dbus_timeout_get_interval(myTimeout), this, myId, false);
247 }
248 else
249 {
250 myMainLoop.removeCallback(this);
251 }
252 }
253
timeoutEvent(int)254 void TimeoutHandler::timeoutEvent(int /*id*/)
255 {
256 dbus_timeout_handle(myTimeout);
257
258 while (dbus_connection_dispatch(myConn) == DBUS_DISPATCH_DATA_REMAINS)
259 { /* empty */ }
260 }
261
addTimeoutCb(DBusTimeout * timeout,void * data)262 dbus_bool_t DbusInterface::Private::addTimeoutCb(DBusTimeout* timeout, void* data)
263 {
264 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
265
266 assert(d->myTimeouts.count(timeout) == 0);
267
268 // Reset counter if no other timeouts exist
269 if (d->myTimeouts.empty())
270 d->myNextTimeoutId = 1;
271
272 d->myTimeouts.insert(std::make_pair(timeout,
273 new TimeoutHandler(d->myNextTimeoutId++, d->myMainLoop, d->myConn, timeout)));
274
275 return true;
276 }
277
removeTimeoutCb(DBusTimeout * timeout,void * data)278 void DbusInterface::Private::removeTimeoutCb(DBusTimeout* timeout, void* data)
279 {
280 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
281 d->myTimeouts.erase(timeout);
282 }
283
toggleTimeoutCb(DBusTimeout * timeout,void * data)284 void DbusInterface::Private::toggleTimeoutCb(DBusTimeout* timeout, void* data)
285 {
286 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
287
288 TimeoutMap::iterator iter(d->myTimeouts.find(timeout));
289 assert(iter != d->myTimeouts.end());
290
291 iter->second->toggle();
292 }
293
handleMessage(DBusConnection *,DBusMessage * message,void * data)294 DBusHandlerResult DbusInterface::Private::handleMessage(DBusConnection* /*connection*/, DBusMessage* message, void* data)
295 {
296 // Don't forward D-Bus daemon messages to application
297 if (dbus_message_has_path(message, "/org/freedesktop/DBus"))
298 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
299
300 DbusInterface::Private* d = static_cast<DbusInterface::Private*>(data);
301
302 if (d->myCallback == NULL)
303 {
304 Licq::gLog.info("Unhandled D-Bus message");
305 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
306 }
307
308 const char* path = dbus_message_get_path(message);
309 const char* iface = dbus_message_get_interface(message);
310 const char* member = dbus_message_get_member(message);
311
312 const char* signature = NULL;
313 DBusMessageIter args;
314 if (dbus_message_iter_init(message, &args))
315 signature = dbus_message_get_signature(message);
316
317 int type = dbus_message_get_type(message);
318 int error;
319 switch (type)
320 {
321 case DBUS_MESSAGE_TYPE_METHOD_CALL:
322 if (iface == NULL)
323 error = DbusInterface::ErrorUnknownInterface;
324 else if (member == NULL)
325 error = DbusInterface::ErrorUnknownMethod;
326 else if (path == NULL)
327 error = DbusInterface::ErrorUnknownObject;
328 else if (strcmp(iface, "org.freedesktop.DBus.Introspectable") == 0 && strcmp(member, "Introspect") == 0)
329 {
330 std::string data(d->myCallback->dbusIntrospect(path));
331 if (data.empty())
332 error = DbusInterface::ErrorUnknownObject;
333 else
334 {
335 data.insert(0,
336 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
337 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">"
338 "<node>"
339 "<interface name=\"org.freedesktop.DBus.Introspectable\">"
340 "<method name=\"Introspect\">"
341 "<arg name=\"xml_data\" type=\"s\" direction=\"out\"/>"
342 "</method>"
343 "</interface>"
344 "<interface name=\"org.freedesktop.DBus.Peer\">"
345 "<method name=\"Ping\"/>"
346 "<method name=\"GetMachineId\">"
347 "<arg name=\"machine_uuid\" type=\"s\" direction=\"out\"/>"
348 "</method>"
349 "</interface>" );
350 data.append("</node>");
351 d->myInterface->sendReply(message, "s", data.c_str());
352 error = DbusInterface::MethodReplied;
353 }
354 }
355 else
356 error = d->myCallback->dbusMethod(path, iface, member, message, signature == NULL ? NULL : &args, signature);
357 break;
358 case DBUS_MESSAGE_TYPE_SIGNAL:
359 d->myCallback->dbusSignal(path, iface, member, message, signature == NULL ? NULL : &args, signature);
360 error = DbusInterface::MethodReplied;
361 break;
362 default:
363 Licq::gLog.info("Unhandled D-Bus message type %i", type);
364 // Only method calls should be replied to
365 error = DbusInterface::MethodReplied;
366 }
367 if (error != DbusInterface::MethodReplied)
368 d->myInterface->sendError(message, error, NULL);
369
370 return DBUS_HANDLER_RESULT_HANDLED;
371 }
372
373
encodeObjectPathPart(const std::string & s)374 std::string DbusInterface::encodeObjectPathPart(const std::string& s)
375 {
376 // Object paths may only contain "[A-Z][a-z][0-9]_"
377 // Use underscore as escape character similar to percent character in URIs
378 static const char allowedChars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
379
380 std::string ret;
381
382 size_t lastpos = 0;
383 size_t pos;
384 while ((pos = s.find_first_not_of(allowedChars, lastpos)) != std::string::npos)
385 {
386 // Add all allowed characters before position
387 ret.append(s, lastpos, pos-lastpos);
388
389 // Add extra character escaped
390 ret += '_';
391 ret += allowedChars[(s[pos] >> 4) & 0x0f];
392 ret += allowedChars[s[pos] & 0x0f];
393
394 lastpos = pos+1;
395 }
396 // Add remaining chararcters
397 ret.append(s, lastpos, std::string::npos);
398
399 return ret;
400 }
401
decodeObjectPathPart(const std::string & s)402 std::string DbusInterface::decodeObjectPathPart(const std::string& s)
403 {
404 std::string ret;
405 size_t lastpos = 0;
406 size_t pos;
407 // Find all escape characters (e.g. underscores)
408 while ((pos = s.find('_', lastpos)) <= s.size() - 3)
409 {
410 // Add all characters before this escape
411 ret.append(s, lastpos, pos-lastpos);
412
413 // Get the two hex digits after escape character
414 char c1 = s[pos+1];
415 char c2 = s[pos+2];
416 if (c1 < '0' || (c1 > '9' && c1 < 'A') || c1 > 'F' ||
417 c2 < '0' || (c2 > '9' && c2 < 'A') || c2 > 'F')
418 {
419 // Not a valid escape, keep underscore unmodified
420 ret += '_';
421 lastpos = pos + 1;
422 continue;
423 }
424
425 // Translate to raw byte
426 ret += (char)(((c1 - '0' - (c1 > '9' ? 7 : 0)) << 4) + (c2 - '0' - (c2 > '9' ? 7 : 0)));
427 lastpos = pos + 3;
428 }
429
430 // Add remaining characters
431 ret.append(s, lastpos, std::string::npos);
432
433 return ret;
434 }
435
DbusInterface(Licq::MainLoop & mainLoop,DbusCallback * callback,bool systemBus)436 DbusInterface::DbusInterface(Licq::MainLoop& mainLoop, DbusCallback* callback, bool systemBus)
437 : myPrivate(new Private(this, mainLoop, callback, systemBus))
438 {
439 LICQ_D();
440 d->myConn = NULL;
441 }
442
~DbusInterface()443 DbusInterface::~DbusInterface()
444 {
445 disconnect();
446 delete myPrivate;
447 }
448
connect()449 bool DbusInterface::connect()
450 {
451 LICQ_D();
452
453 if (d->myConn != NULL)
454 {
455 if (dbus_connection_get_is_connected(d->myConn))
456 return true;
457
458 // Lost connection, drop it and make a new
459 disconnect();
460 }
461
462 // Connect to DBus
463 DBusError e;
464 dbus_error_init(&e);
465 d->myConn = dbus_bus_get_private(d->mySystemBus ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &e);
466
467 if (dbus_error_is_set(&e))
468 {
469 Licq::gLog.error("Failed to get bus %s: %s", e.name, e.message);
470 dbus_error_free(&e);
471 return false;
472 }
473
474 // Don't let libdbus terminate Licq if we're disconnected
475 dbus_connection_set_exit_on_disconnect(d->myConn, false);
476
477 // Register callback functions
478 dbus_connection_set_watch_functions(d->myConn, Private::addWatchCb,
479 Private::removeWatchCb, Private::toggleWatchCb, d, NULL);
480 dbus_connection_set_timeout_functions(d->myConn, Private::addTimeoutCb,
481 Private::removeTimeoutCb, Private::toggleTimeoutCb, d, NULL);
482 dbus_connection_add_filter(d->myConn, Private::handleMessage, d, NULL);
483
484 if (d->myCallback != NULL)
485 d->myCallback->dbusConnected();
486
487 return true;
488 }
489
disconnect()490 void DbusInterface::disconnect()
491 {
492 LICQ_D();
493
494 if (d->myConn != NULL)
495 {
496 dbus_connection_close(d->myConn);
497 dbus_connection_unref(d->myConn);
498 d->myConn = NULL;
499 }
500 d->myWatches.clear();
501 d->myTimeouts.clear();
502
503 if (d->myCallback != NULL)
504 d->myCallback->dbusDisconnected();
505 }
506
flush()507 void DbusInterface::flush()
508 {
509 LICQ_D();
510
511 if (d->myConn == NULL)
512 return;
513
514 dbus_connection_flush(d->myConn);
515 }
516
requestName(const std::string & name)517 bool DbusInterface::requestName(const std::string& name)
518 {
519 LICQ_D();
520
521 if (d->myConn == NULL)
522 return false;
523
524 int ret = dbus_bus_request_name(d->myConn, name.c_str(), 0, NULL);
525 return (ret == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER || ret == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER);
526 }
527
addMsgArgs(DBusMessageIter * args,const char * fmt,va_list ap)528 bool DbusInterface::Private::addMsgArgs(DBusMessageIter* args, const char* fmt, va_list ap)
529 {
530 while (true)
531 {
532 switch (*fmt)
533 {
534 case '\0':
535 return true;
536
537 case 'i':
538 {
539 int val = va_arg(ap, int);
540 if (!dbus_message_iter_append_basic(args, DBUS_TYPE_INT32, &val))
541 return false;
542 break;
543 }
544 case 'u':
545 {
546 unsigned int val = va_arg(ap, unsigned int);
547 if (!dbus_message_iter_append_basic(args, DBUS_TYPE_UINT32, &val))
548 return false;
549 break;
550 }
551 case 's':
552 {
553 const char* val = va_arg(ap, const char*);
554 if (!dbus_message_iter_append_basic(args, DBUS_TYPE_STRING, &val))
555 return false;
556 break;
557 }
558 case 'a':
559 {
560 // Array, next character determines element type
561 switch (*(++fmt))
562 {
563 case 's':
564 case 'o':
565 {
566 DBusMessageIter subargs;
567 if (!dbus_message_iter_open_container(args, DBUS_TYPE_ARRAY,
568 (*fmt == 'o' ? DBUS_TYPE_OBJECT_PATH_AS_STRING : DBUS_TYPE_STRING_AS_STRING),
569 &subargs))
570 return false;
571
572 const std::list<std::string>* vals = va_arg(ap, const std::list<std::string>*);
573 std::list<std::string>::const_iterator i;
574 for (i = vals->begin(); i != vals->end(); ++i)
575 {
576 const char* val = (*i).c_str();
577 if (!dbus_message_iter_append_basic(&subargs,
578 (*fmt == 'o' ? DBUS_TYPE_OBJECT_PATH : DBUS_TYPE_STRING), &val))
579 return false;
580 }
581
582 if (!dbus_message_iter_close_container(args, &subargs))
583 return false;
584 break;
585 }
586 default:
587 // Unknown array type
588 return false;
589 }
590 break;
591 }
592 default:
593 // Unknown format
594 return false;
595 }
596 fmt++;
597 }
598 }
599
sendSignal(const std::string & path,const std::string & iface,const std::string & name,const char * fmt,...)600 void DbusInterface::sendSignal(const std::string& path, const std::string& iface,
601 const std::string& name, const char* fmt, ...)
602 {
603 LICQ_D();
604
605 if (d->myConn == NULL)
606 return;
607
608 DBusMessage* msg = dbus_message_new_signal(path.c_str(), iface.c_str(), name.c_str());
609 if (msg == NULL)
610 {
611 Licq::gLog.error("Failed to allocate signal");
612 return;
613 }
614
615 if (fmt != NULL)
616 {
617 // Append arguments to signal
618 DBusMessageIter args;
619 dbus_message_iter_init_append(msg, &args);
620 va_list ap;
621 va_start(ap, fmt);
622 if (!Private::addMsgArgs(&args, fmt, ap))
623 {
624 Licq::gLog.error("Failed to add signal parameters");
625 va_end(ap);
626 dbus_message_unref(msg);
627 return;
628 }
629 va_end(ap);
630 }
631
632 // Queue signal to be sent (will be handled by main loop)
633 dbus_connection_send(d->myConn, msg, NULL);
634
635 // Free message (lib will hold a reference until send is complete)
636 dbus_message_unref(msg);
637 }
638
sendReply(DBusMessage * msgref,const char * fmt,...)639 void DbusInterface::sendReply(DBusMessage* msgref, const char* fmt, ...)
640 {
641 LICQ_D();
642
643 if (d->myConn == NULL)
644 return;
645
646 DBusMessage* msg = dbus_message_new_method_return(msgref);
647 if (msg == NULL)
648 {
649 Licq::gLog.error("Failed to allocate reply message");
650 return;
651 }
652
653 if (fmt != NULL)
654 {
655 // Append arguments to signal
656 DBusMessageIter args;
657 dbus_message_iter_init_append(msg, &args);
658 va_list ap;
659 va_start(ap, fmt);
660 if (!Private::addMsgArgs(&args, fmt, ap))
661 {
662 Licq::gLog.error("Failed to add reply parameters");
663 va_end(ap);
664 dbus_message_unref(msg);
665 return;
666 }
667 va_end(ap);
668 }
669
670 // Queue signal to be sent (will be handled by main loop)
671 dbus_connection_send(d->myConn, msg, NULL);
672
673 // Free message (lib will hold a reference until send is complete)
674 dbus_message_unref(msg);
675 }
676
sendError(DBusMessage * msgref,int type,const char * message)677 void DbusInterface::sendError(DBusMessage* msgref, int type, const char* message)
678 {
679 LICQ_D();
680
681 if (d->myConn == NULL)
682 return;
683
684 const char* errname;
685 switch (type)
686 {
687 default:
688 case ErrorFailed: errname = DBUS_ERROR_FAILED; break;
689 case ErrorInvalidArgs: errname = DBUS_ERROR_INVALID_ARGS; break;
690 case ErrorInvalidSignature: errname = DBUS_ERROR_INVALID_SIGNATURE; break;
691 case ErrorNotSupported: errname = DBUS_ERROR_NOT_SUPPORTED; break;
692 case ErrorUnknownInterface: errname = DBUS_ERROR_UNKNOWN_INTERFACE; break;
693 case ErrorUnknownMethod: errname = DBUS_ERROR_UNKNOWN_METHOD; break;
694 case ErrorUnknownObject: errname = DBUS_ERROR_UNKNOWN_OBJECT; break;
695 }
696 DBusMessage* reply = dbus_message_new_error(msgref, errname, message);
697 if (reply == NULL)
698 {
699 Licq::gLog.error("Failed to allocate error message");
700 return;
701 }
702
703 // Queue signal to be sent (will be handled by main loop)
704 dbus_connection_send(d->myConn, reply, NULL);
705
706 // Free message (lib will hold a reference until send is complete)
707 dbus_message_unref(reply);
708 }
709
getNextMessageParamValue(DBusMessageIter * msgref,void * ret)710 void DbusInterface::getNextMessageParamValue(DBusMessageIter* msgref, void* ret)
711 {
712 dbus_message_iter_get_basic(msgref, ret);
713 }
714