WvStreams
wvdbusmsg.cc
1 /* -*- Mode: C++ -*-
2  * Worldvisions Weaver Software:
3  * Copyright (C) 2004-2006 Net Integration Technologies, Inc.
4  *
5  * Pathfinder Software:
6  * Copyright (C) 2007, Carillon Information Security Inc.
7  *
8  * This library is licensed under the LGPL, please read LICENSE for details.
9  *
10  */
11 #include "wvdbusmsg.h"
12 #include "wvdbusconn.h"
13 #include "wvstrutils.h"
14 #undef interface // windows
15 #include <dbus/dbus.h>
16 
17 
18 class WvDBusReplyMsg : public WvDBusMsg
19 {
20 public:
27  WvDBusReplyMsg(DBusMessage *_msg);
28 
29  virtual ~WvDBusReplyMsg() {}
30 };
31 
32 
33 
34 WvDBusMsg::Iter::Iter(const WvDBusMsg &_msg)
35  : first(new DBusMessageIter), it(new DBusMessageIter)
36 {
37  dbus_message_iter_init(_msg, first);
38  rewind();
39 }
40 
41 
42 WvDBusMsg::Iter::Iter(const WvDBusMsg::Iter &_it)
43  : first(new DBusMessageIter), it(new DBusMessageIter)
44 {
45  *first = *_it.first;
46  rewind();
47 }
48 
49 
50 WvDBusMsg::Iter::Iter(const DBusMessageIter &_first)
51  : first(new DBusMessageIter), it(new DBusMessageIter)
52 {
53  *first = _first;
54  rewind();
55 }
56 
57 
58 WvDBusMsg::Iter::~Iter()
59 {
60  delete first;
61  delete it;
62 }
63 
64 
66 {
67  rewound = true;
68 }
69 
70 
72 {
73  if (rewound)
74  *it = *first;
75  else if (type() != DBUS_TYPE_INVALID)
76  dbus_message_iter_next(it);
77  rewound = false;
78  return type() != DBUS_TYPE_INVALID;
79 }
80 
81 
83 {
84  return dbus_message_iter_get_arg_type(it);
85 }
86 
87 
89 {
90  DBusMessageIter sub;
91  dbus_message_iter_recurse(it, &sub);
92  return Iter(sub);
93 }
94 
95 
97 {
98  return !rewound && type() != DBUS_TYPE_INVALID;
99 }
100 
101 
103 {
104  int items = 0;
105  for (rewind(); next() && items < 20; items++)
106  list.append(get_str());
107  if (items == 20)
108  list.append("...");
109 }
110 
111 
113 {
114  WvStringList list;
115  get_all(list);
116  return list.join(",");
117 }
118 
119 
121 {
122  char *s;
123  double d;
124 
125  switch (type())
126  {
127  case DBUS_TYPE_BYTE:
128  // Don't do this: things like vxodbc expect to be able to atoi()
129  // the resulting string!
130  //return WvString("y%s", get_int());
131  case DBUS_TYPE_BOOLEAN:
132  //return WvString("b%s", get_int());
133  case DBUS_TYPE_INT16:
134  case DBUS_TYPE_INT32:
135  case DBUS_TYPE_INT64:
136  return get_int();
137  case DBUS_TYPE_UINT16:
138  case DBUS_TYPE_UINT32:
139  case DBUS_TYPE_UINT64:
140  return get_uint();
141  case DBUS_TYPE_DOUBLE:
142  dbus_message_iter_get_basic(it, &d);
143  return d;
144  case DBUS_TYPE_STRING:
145  dbus_message_iter_get_basic(it, &s);
146  return s;
147  case DBUS_TYPE_VARIANT:
148  return WvString("{%s}", open().getnext().get_str());
149  case DBUS_TYPE_STRUCT:
150  case DBUS_TYPE_ARRAY:
151  return WvString("[%s]", open().get_all());
152  case DBUS_TYPE_INVALID:
153  return WvString();
154  default:
155  return WvString("UNKNOWN_TYPE(%c)", type());
156  }
157 }
158 
159 
161 {
162  dbus_bool_t b;
163  unsigned char c;
164  dbus_int16_t s;
165  dbus_int32_t i;
166  dbus_int64_t l;
167  char *str;
168 
169  switch (type())
170  {
171  case DBUS_TYPE_BYTE:
172  dbus_message_iter_get_basic(it, &c);
173  return c;
174 
175  case DBUS_TYPE_BOOLEAN:
176  dbus_message_iter_get_basic(it, &b);
177  return b;
178 
179  case DBUS_TYPE_INT16:
180  case DBUS_TYPE_UINT16:
181  dbus_message_iter_get_basic(it, &s);
182  return s;
183 
184  case DBUS_TYPE_INT32:
185  case DBUS_TYPE_UINT32:
186  dbus_message_iter_get_basic(it, &i);
187  return i;
188 
189  case DBUS_TYPE_INT64:
190  case DBUS_TYPE_UINT64:
191  dbus_message_iter_get_basic(it, &l);
192  return l;
193 
194  case DBUS_TYPE_STRING:
195  dbus_message_iter_get_basic(it, &str);
196  return WvString(str).num();
197 
198  case DBUS_TYPE_VARIANT:
199  return open().getnext().get_int();
200 
201  default:
202  return 0;
203  }
204 }
205 
206 
208 {
209  dbus_bool_t b;
210  unsigned char c;
211  dbus_uint16_t s;
212  dbus_uint32_t i;
213  dbus_uint64_t l;
214  char *str;
215 
216  switch (type())
217  {
218  case DBUS_TYPE_BYTE:
219  dbus_message_iter_get_basic(it, &c);
220  return c;
221 
222  case DBUS_TYPE_BOOLEAN:
223  dbus_message_iter_get_basic(it, &b);
224  return b;
225 
226  case DBUS_TYPE_INT16:
227  case DBUS_TYPE_UINT16:
228  dbus_message_iter_get_basic(it, &s);
229  return s;
230 
231  case DBUS_TYPE_INT32:
232  case DBUS_TYPE_UINT32:
233  dbus_message_iter_get_basic(it, &i);
234  return i;
235 
236  case DBUS_TYPE_INT64:
237  case DBUS_TYPE_UINT64:
238  dbus_message_iter_get_basic(it, &l);
239  return l;
240 
241  case DBUS_TYPE_STRING:
242  dbus_message_iter_get_basic(it, &str);
243  return WvString(str).num();
244 
245  case DBUS_TYPE_VARIANT:
246  return open().getnext().get_uint();
247 
248  default:
249  return 0;
250  }
251 }
252 
253 
255 {
256  dbus_bool_t b;
257  unsigned char c;
258  dbus_uint16_t s;
259  dbus_uint32_t i;
260  dbus_uint64_t l;
261  char *str;
262  double d;
263 
264  switch (type())
265  {
266  case DBUS_TYPE_DOUBLE:
267  dbus_message_iter_get_basic(it, &d);
268  return d;
269 
270  case DBUS_TYPE_BYTE:
271  dbus_message_iter_get_basic(it, &c);
272  return c;
273 
274  case DBUS_TYPE_BOOLEAN:
275  dbus_message_iter_get_basic(it, &b);
276  return b;
277 
278  case DBUS_TYPE_INT16:
279  case DBUS_TYPE_UINT16:
280  dbus_message_iter_get_basic(it, &s);
281  return s;
282 
283  case DBUS_TYPE_INT32:
284  case DBUS_TYPE_UINT32:
285  dbus_message_iter_get_basic(it, &i);
286  return i;
287 
288  case DBUS_TYPE_INT64:
289  case DBUS_TYPE_UINT64:
290  dbus_message_iter_get_basic(it, &l);
291  return l;
292 
293  case DBUS_TYPE_STRING:
294  dbus_message_iter_get_basic(it, &str);
295  return atof(str);
296 
297  case DBUS_TYPE_VARIANT:
298  return open().getnext().get_double();
299 
300  default:
301  return 0;
302  }
303 }
304 
305 
307 {
308  s = get_str();
309  return &s;
310 }
311 
312 
313 
314 
315 static DBusMessageIter *new_append_iter(WvDBusMsg &msg)
316 {
317  DBusMessageIter *it = new DBusMessageIter;
318  dbus_message_iter_init_append(msg, it);
319  return it;
320 }
321 
322 
323 WvDBusMsg::WvDBusMsg(WvStringParm busname, WvStringParm objectname,
324  WvStringParm interface, WvStringParm method)
325 {
326  msg = dbus_message_new_method_call(busname, objectname, interface, method);
327  itlist.prepend(new_append_iter(*this), true);
328 }
329 
330 
332 {
333  msg = _msg.msg;
334  dbus_message_ref(msg);
335  itlist.prepend(new_append_iter(*this), true);
336 }
337 
338 
339 WvDBusMsg::WvDBusMsg(DBusMessage *_msg)
340 {
341  msg = _msg;
342  dbus_message_ref(msg);
343  itlist.prepend(new_append_iter(*this), true);
344 }
345 
346 
347 WvDBusMsg::~WvDBusMsg()
348 {
349  dbus_message_unref(msg);
350 }
351 
352 
353 WvDBusMsg::operator DBusMessage* () const
354 {
355  return msg;
356 }
357 
358 
359 WvString WvDBusMsg::get_sender() const
360 {
361  return dbus_message_get_sender(msg);
362 }
363 
364 
365 WvString WvDBusMsg::get_dest() const
366 {
367  return dbus_message_get_destination(msg);
368 }
369 
370 
371 WvString WvDBusMsg::get_path() const
372 {
373  return dbus_message_get_path(msg);
374 }
375 
376 
377 WvString WvDBusMsg::get_interface() const
378 {
379  return dbus_message_get_interface(msg);
380 }
381 
382 
383 WvString WvDBusMsg::get_member() const
384 {
385  return dbus_message_get_member(msg);
386 }
387 
388 
389 WvString WvDBusMsg::get_error() const
390 {
391  if (iserror())
392  return dbus_message_get_error_name(msg);
393 
394  return WvString::null;
395 }
396 
397 bool WvDBusMsg::is_reply() const
398 {
399  // This used to have a hack to deal with replies to message #0.
400  // But it turns out the first message is #1, so that's not an actual
401  // problem.
402  return get_replyserial() != 0;
403 }
404 
405 
406 uint32_t WvDBusMsg::get_serial() const
407 {
408  return dbus_message_get_serial(msg);
409 }
410 
411 
412 uint32_t WvDBusMsg::get_replyserial() const
413 {
414  return dbus_message_get_reply_serial(msg);
415 }
416 
417 
418 void WvDBusMsg::get_arglist(WvStringList &list) const
419 {
420  Iter(*this).get_all(list);
421 }
422 
423 
424 WvString WvDBusMsg::get_argstr() const
425 {
426  return Iter(*this).get_all();
427 }
428 
429 
430 WvDBusMsg::operator WvString() const
431 {
432  WvString dest(get_dest());
433  if (!dest)
434  dest = "";
435  else
436  dest = WvString("%s:", dest);
437  if (is_reply())
438  {
439  if (iserror())
440  return WvString("ERR#%s->%s#%s(%s)",
441  get_serial(), dest, get_replyserial(),
442  get_argstr());
443  else
444  return WvString("REPLY#%s->%s#%s(%s)",
445  get_serial(), dest, get_replyserial(),
446  get_argstr());
447  }
448  else
449  {
450  WvString s("%s%s/%s.%s(%s)#%s",
451  dest,
452  get_path(), get_interface(), get_member(),
453  get_argstr(), get_serial());
454  s = strreplace(s, "org.freedesktop.DBus", "o.f.D");
455  s = strreplace(s, "org/freedesktop/DBus", "o/f/D");
456  return s;
457  }
458 }
459 
460 
462 {
463  assert(msg);
464  assert(s);
465  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_STRING, &s);
466  return *this;
467 }
468 
469 
471 {
472  assert(msg);
473  dbus_bool_t bb = b;
474  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BOOLEAN, &bb);
475  return *this;
476 }
477 
478 
479 WvDBusMsg &WvDBusMsg::append(signed char c)
480 {
481  assert(msg);
482  dbus_unichar_t cc = c;
483  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BYTE, &cc);
484  return *this;
485 }
486 
487 
488 WvDBusMsg &WvDBusMsg::append(unsigned char c)
489 {
490  assert(msg);
491  dbus_unichar_t cc = c;
492  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BYTE, &cc);
493  return *this;
494 }
495 
496 
497 WvDBusMsg &WvDBusMsg::append(int16_t i)
498 {
499  assert(msg);
500  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT16, &i);
501  return *this;
502 }
503 
504 
505 WvDBusMsg &WvDBusMsg::append(uint16_t i)
506 {
507  assert(msg);
508  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT16, &i);
509  return *this;
510 }
511 
512 
513 WvDBusMsg &WvDBusMsg::append(int32_t i)
514 {
515  assert(msg);
516  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT32, &i);
517  return *this;
518 }
519 
520 
521 WvDBusMsg &WvDBusMsg::append(uint32_t i)
522 {
523  assert(msg);
524  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT32, &i);
525  return *this;
526 }
527 
528 
529 WvDBusMsg &WvDBusMsg::append(int64_t i)
530 {
531  assert(msg);
532  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT64, &i);
533  return *this;
534 }
535 
536 
537 WvDBusMsg &WvDBusMsg::append(uint64_t i)
538 {
539  assert(msg);
540  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT64, &i);
541  return *this;
542 }
543 
544 
545 WvDBusMsg &WvDBusMsg::append(double d)
546 {
547  assert(msg);
548  dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_DOUBLE, &d);
549  return *this;
550 }
551 
552 
553 WvDBusMsg &WvDBusMsg::variant_start(WvStringParm element_type)
554 {
555  DBusMessageIter *parent = itlist.first();
556  DBusMessageIter *sub = new DBusMessageIter;
557  dbus_message_iter_open_container(parent,
558  DBUS_TYPE_VARIANT, element_type, sub);
559  itlist.prepend(sub, true);
560  return *this;
561 }
562 
563 
565 {
566  assert(itlist.count() >= 2);
567 
569  i.rewind(); i.next();
570  DBusMessageIter *sub = i.ptr();
571  i.next();
572  DBusMessageIter *parent = i.ptr();
573 
574  dbus_message_iter_close_container(parent, sub);
575  itlist.unlink_first();
576  return *this;
577 }
578 
579 
580 WvDBusMsg &WvDBusMsg::struct_start(WvStringParm element_type)
581 {
582  DBusMessageIter *parent = itlist.first();
583  DBusMessageIter *sub = new DBusMessageIter;
584  dbus_message_iter_open_container(parent,
585  DBUS_TYPE_STRUCT, 0, sub);
586  itlist.prepend(sub, true);
587  return *this;
588 }
589 
590 
592 {
593  return array_end(); // same thing
594 }
595 
596 
597 WvDBusMsg &WvDBusMsg::array_start(WvStringParm element_type)
598 {
599  DBusMessageIter *parent = itlist.first();
600  DBusMessageIter *sub = new DBusMessageIter;
601  dbus_message_iter_open_container(parent,
602  DBUS_TYPE_ARRAY, element_type, sub);
603  itlist.prepend(sub, true);
604  return *this;
605 }
606 
607 
609 {
610  return variant_end(); // same thing
611 }
612 
613 
614 WvDBusMsg &WvDBusMsg::varray_start(WvStringParm element_type)
615 {
616  variant_start(WvString("a%s", element_type));
617  return array_start(element_type);
618 }
619 
620 
622 {
623  assert(itlist.count() >= 3);
624  array_end();
625  return variant_end();
626 }
627 
628 
630 {
631  return WvDBusReplyMsg(*this);
632 }
633 
634 
635 bool WvDBusMsg::iserror() const
636 {
637  return dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR;
638 }
639 
640 
642 {
643  conn.send(*this);
644 }
645 
646 
648  : WvDBusMsg(dbus_message_new_method_return(_msg))
649 {
650  dbus_message_unref(msg);
651 }
652 
653 
654 WvDBusSignal::WvDBusSignal(WvStringParm objectname, WvStringParm interface,
655  WvStringParm name)
656  : WvDBusMsg(dbus_message_new_signal(objectname, interface, name))
657 {
658  dbus_message_unref(msg);
659 }
660 
661 
662 DBusMessage *WvDBusError::setup1(WvDBusMsg &in_reply_to,
663  WvStringParm errname, WvStringParm message)
664 {
665  return dbus_message_new_error(in_reply_to, errname, message);
666 }
667 
668 void WvDBusError::setup2()
669 {
670  dbus_message_unref(msg);
671 }
WvDBusMsg::send
void send(WvDBusConn &conn)
A shortcut for sending this message on the given connection.
Definition: wvdbusmsg.cc:641
WvDBusMsg::Iter::cur
bool cur() const
Returns: true if the current link is valid.
Definition: wvdbusmsg.cc:96
WvDBusMsg::iserror
bool iserror() const
Return true if this message is an error response.
Definition: wvdbusmsg.cc:635
WvDBusReplyMsg
Definition: wvdbusmsg.cc:18
WvDBusMsg::Iter::next
bool next()
Moves the iterator along the list to point to the next element.
Definition: wvdbusmsg.cc:71
WvDBusMsg::array_start
WvDBusMsg & array_start(WvStringParm element_type)
Start an array.
Definition: wvdbusmsg.cc:597
WvDBusConn::send
uint32_t send(WvDBusMsg msg)
Send a message on the bus, not expecting any reply.
Definition: wvdbusconn.cc:194
WvDBusMsg::append
WvDBusMsg & append(const char *s)
The following methods are designed to allow appending various arguments to the message.
Definition: wvdbusmsg.cc:461
WvDBusMsg::reply
WvDBusMsg reply()
Generate a message that will be a reply to this one.
Definition: wvdbusmsg.cc:629
WvDBusMsg::Iter::rewind
void rewind()
Rewinds the iterator to make it point to an imaginary element preceeding the first element of the lis...
Definition: wvdbusmsg.cc:65
WvDBusMsg::array_end
WvDBusMsg & array_end()
End an array started with array_start().
Definition: wvdbusmsg.cc:608
WvList::first
T * first() const
Returns a pointer to the first element in the linked list.
Definition: wvlinklist.h:241
WvDBusMsg
Definition: wvdbusmsg.h:28
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvDBusMsg::Iter::ptr
WvString * ptr() const
Returns a pointer to the WvString at the iterator's current location.
Definition: wvdbusmsg.cc:306
WvDBusMsg::varray_end
WvDBusMsg & varray_end()
End an array started with array_start().
Definition: wvdbusmsg.cc:621
WvDBusMsg::Iter
Definition: wvdbusmsg.h:176
WvDBusMsg::Iter::get_uint
uint64_t get_uint() const
Get the current element as a uint64_t (possible for all integer types)
Definition: wvdbusmsg.cc:207
wvstrutils.h
WvDBusMsg::Iter::get_int
int64_t get_int() const
Get the current element as an int64_t (possible for all integer types)
Definition: wvdbusmsg.cc:160
WvStringList::join
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
Definition: wvstringlist.cc:14
WvDBusReplyMsg::WvDBusReplyMsg
WvDBusReplyMsg(DBusMessage *_msg)
Constructs a new reply message (a message intended to be a reply to an existing D-Bus message).
Definition: wvdbusmsg.cc:647
WvDBusMsg::struct_end
WvDBusMsg & struct_end()
End a struct started with struct_start().
Definition: wvdbusmsg.cc:591
WvDBusMsg::Iter::get_all
WvString get_all()
Return a WvString representation of all elements in a single string.
Definition: wvdbusmsg.cc:112
WvDBusMsg::variant_end
WvDBusMsg & variant_end()
End a variant.
Definition: wvdbusmsg.cc:564
WvDBusMsg::WvDBusMsg
WvDBusMsg(WvStringParm busname, WvStringParm objectname, WvStringParm ifc, WvStringParm method)
Constructs a new WvDBus message.
Definition: wvdbusmsg.cc:323
WvListBase::count
size_t count() const
Returns the number of elements in the list.
Definition: wvlinklist.cc:24
WvDBusMsg::varray_start
WvDBusMsg & varray_start(WvStringParm element_type)
Start a variant-array.
Definition: wvdbusmsg.cc:614
WvDBusMsg::Iter::open
Iter open() const
Returns a sub-iterator for walking through recursive types, such as arrays, structs,...
Definition: wvdbusmsg.cc:88
WvDBusMsg::struct_start
WvDBusMsg & struct_start(WvStringParm element_type)
Start a struct.
Definition: wvdbusmsg.cc:580
WvDBusMsg::variant_start
WvDBusMsg & variant_start(WvStringParm element_type)
Start a variant.
Definition: wvdbusmsg.cc:553
WvDBusMsg::Iter::get_double
double get_double() const
Get the current element as a double (possible for all integer and floating point types)
Definition: wvdbusmsg.cc:254
WvDBusMsg::Iter::get_str
WvString get_str() const
Get the current element as a string (possible for all types).
Definition: wvdbusmsg.cc:120
WvStringList
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:27
WvDBusMsg::Iter::type
int type() const
Returns the data type of the current element.
Definition: wvdbusmsg.cc:82
WvList
A linked list container class.
Definition: wvlinklist.h:197
strreplace
WvString strreplace(WvStringParm s, WvStringParm a, WvStringParm b)
Replace any instances of "a" with "b" in "s".
Definition: strutils.cc:797
WvFastString::num
int num() const
Return a stdc++ string with the contents of this string.
Definition: wvstring.h:286
WvList::unlink_first
void unlink_first()
Unlinks the first element from the list.
Definition: wvlinklist.h:312
WvList::prepend
void prepend(T *data, bool autofree, const char *id=NULL)
Prepends the element to the beginning of the list.
Definition: wvlinklist.h:293
WvDBusConn
Definition: wvdbusconn.h:65