WvStreams
wvdbusmsg.cc
00001 /* -*- Mode: C++ -*-
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2004-2006 Net Integration Technologies, Inc.
00004  * 
00005  * Pathfinder Software:
00006  *   Copyright (C) 2007, Carillon Information Security Inc.
00007  *
00008  * This library is licensed under the LGPL, please read LICENSE for details.
00009  *
00010  */ 
00011 #include "wvdbusmsg.h"
00012 #include "wvdbusconn.h"
00013 #include "wvstrutils.h"
00014 #undef interface // windows
00015 #include <dbus/dbus.h>
00016 
00017 
00018 class WvDBusReplyMsg : public WvDBusMsg
00019 {
00020 public:
00027     WvDBusReplyMsg(DBusMessage *_msg);
00028 
00029     virtual ~WvDBusReplyMsg() {}
00030 };
00031 
00032 
00033 
00034 WvDBusMsg::Iter::Iter(const WvDBusMsg &_msg)
00035     : first(new DBusMessageIter), it(new DBusMessageIter)
00036 {
00037     dbus_message_iter_init(_msg, first);
00038     rewind();
00039 }
00040 
00041 
00042 WvDBusMsg::Iter::Iter(const WvDBusMsg::Iter &_it)
00043     : first(new DBusMessageIter), it(new DBusMessageIter)
00044 {
00045     *first = *_it.first;
00046     rewind();
00047 }
00048 
00049 
00050 WvDBusMsg::Iter::Iter(const DBusMessageIter &_first)
00051     : first(new DBusMessageIter), it(new DBusMessageIter)
00052 {
00053     *first = _first;
00054     rewind();
00055 }
00056 
00057 
00058 WvDBusMsg::Iter::~Iter()
00059 {
00060     delete first;
00061     delete it;
00062 }
00063 
00064 
00065 void WvDBusMsg::Iter::rewind()
00066 {
00067     rewound = true;
00068 }
00069 
00070 
00071 bool WvDBusMsg::Iter::next()
00072 {
00073     if (rewound)
00074         *it = *first;
00075     else if (type() != DBUS_TYPE_INVALID)
00076         dbus_message_iter_next(it);
00077     rewound = false;
00078     return type() != DBUS_TYPE_INVALID;
00079 }
00080 
00081 
00082 int WvDBusMsg::Iter::type() const
00083 {
00084     return dbus_message_iter_get_arg_type(it);
00085 }
00086 
00087 
00088 WvDBusMsg::Iter WvDBusMsg::Iter::open() const
00089 {
00090     DBusMessageIter sub;
00091     dbus_message_iter_recurse(it, &sub);
00092     return Iter(sub); 
00093 }
00094 
00095 
00096 bool WvDBusMsg::Iter::cur() const
00097 {
00098     return !rewound && type() != DBUS_TYPE_INVALID;
00099 }
00100 
00101 
00102 void WvDBusMsg::Iter::get_all(WvStringList &list)
00103 {
00104     int items = 0;
00105     for (rewind(); next() && items < 20; items++)
00106         list.append(get_str());
00107     if (items == 20)
00108         list.append("...");
00109 }
00110 
00111 
00112 WvString WvDBusMsg::Iter::get_all()
00113 {
00114     WvStringList list;
00115     get_all(list);
00116     return list.join(",");
00117 }
00118 
00119 
00120 WvString WvDBusMsg::Iter::get_str() const
00121 {
00122     char *s;
00123     double d;
00124     
00125     switch (type())
00126     {
00127     case DBUS_TYPE_BYTE:
00128         // Don't do this: things like vxodbc expect to be able to atoi()
00129         // the resulting string!
00130         //return WvString("y%s", get_int());
00131     case DBUS_TYPE_BOOLEAN: 
00132         //return WvString("b%s", get_int());
00133     case DBUS_TYPE_INT16: 
00134     case DBUS_TYPE_INT32: 
00135     case DBUS_TYPE_INT64: 
00136         return get_int();
00137     case DBUS_TYPE_UINT16: 
00138     case DBUS_TYPE_UINT32: 
00139     case DBUS_TYPE_UINT64: 
00140         return get_uint();
00141     case DBUS_TYPE_DOUBLE: 
00142         dbus_message_iter_get_basic(it, &d);
00143         return d;
00144     case DBUS_TYPE_STRING: 
00145         dbus_message_iter_get_basic(it, &s);
00146         return s;
00147     case DBUS_TYPE_VARIANT:
00148         return WvString("{%s}", open().getnext().get_str());
00149     case DBUS_TYPE_STRUCT:
00150     case DBUS_TYPE_ARRAY:
00151         return WvString("[%s]", open().get_all());
00152     case DBUS_TYPE_INVALID:
00153         return WvString();
00154     default:
00155         return WvString("UNKNOWN_TYPE(%c)", type());
00156     }
00157 }
00158 
00159 
00160 int64_t WvDBusMsg::Iter::get_int() const
00161 {
00162     dbus_bool_t b;
00163     unsigned char c;
00164     dbus_int16_t s;
00165     dbus_int32_t i;
00166     dbus_int64_t l;
00167     char *str;
00168     
00169     switch (type())
00170     {
00171     case DBUS_TYPE_BYTE: 
00172         dbus_message_iter_get_basic(it, &c);
00173         return c;
00174         
00175     case DBUS_TYPE_BOOLEAN: 
00176         dbus_message_iter_get_basic(it, &b);
00177         return b;
00178         
00179     case DBUS_TYPE_INT16: 
00180     case DBUS_TYPE_UINT16: 
00181         dbus_message_iter_get_basic(it, &s);
00182         return s;
00183         
00184     case DBUS_TYPE_INT32: 
00185     case DBUS_TYPE_UINT32:
00186         dbus_message_iter_get_basic(it, &i);
00187         return i;
00188         
00189     case DBUS_TYPE_INT64: 
00190     case DBUS_TYPE_UINT64: 
00191         dbus_message_iter_get_basic(it, &l);
00192         return l;
00193         
00194     case DBUS_TYPE_STRING: 
00195         dbus_message_iter_get_basic(it, &str);
00196         return WvString(str).num();
00197         
00198     case DBUS_TYPE_VARIANT:
00199         return open().getnext().get_int();
00200         
00201     default:
00202         return 0;
00203     }
00204 }
00205 
00206 
00207 uint64_t WvDBusMsg::Iter::get_uint() const
00208 {
00209     dbus_bool_t b;
00210     unsigned char c;
00211     dbus_uint16_t s;
00212     dbus_uint32_t i;
00213     dbus_uint64_t l;
00214     char *str;
00215     
00216     switch (type())
00217     {
00218     case DBUS_TYPE_BYTE: 
00219         dbus_message_iter_get_basic(it, &c);
00220         return c;
00221         
00222     case DBUS_TYPE_BOOLEAN: 
00223         dbus_message_iter_get_basic(it, &b);
00224         return b;
00225         
00226     case DBUS_TYPE_INT16: 
00227     case DBUS_TYPE_UINT16: 
00228         dbus_message_iter_get_basic(it, &s);
00229         return s;
00230         
00231     case DBUS_TYPE_INT32: 
00232     case DBUS_TYPE_UINT32:
00233         dbus_message_iter_get_basic(it, &i);
00234         return i;
00235         
00236     case DBUS_TYPE_INT64: 
00237     case DBUS_TYPE_UINT64: 
00238         dbus_message_iter_get_basic(it, &l);
00239         return l;
00240         
00241     case DBUS_TYPE_STRING: 
00242         dbus_message_iter_get_basic(it, &str);
00243         return WvString(str).num();
00244         
00245     case DBUS_TYPE_VARIANT:
00246         return open().getnext().get_uint();
00247         
00248     default:
00249         return 0;
00250     }
00251 }
00252 
00253 
00254 double WvDBusMsg::Iter::get_double() const
00255 {
00256     dbus_bool_t b;
00257     unsigned char c;
00258     dbus_uint16_t s;
00259     dbus_uint32_t i;
00260     dbus_uint64_t l;
00261     char *str;
00262     double d;
00263     
00264     switch (type())
00265     {
00266     case DBUS_TYPE_DOUBLE:
00267         dbus_message_iter_get_basic(it, &d);
00268         return d;
00269 
00270     case DBUS_TYPE_BYTE: 
00271         dbus_message_iter_get_basic(it, &c);
00272         return c;
00273         
00274     case DBUS_TYPE_BOOLEAN: 
00275         dbus_message_iter_get_basic(it, &b);
00276         return b;
00277         
00278     case DBUS_TYPE_INT16: 
00279     case DBUS_TYPE_UINT16: 
00280         dbus_message_iter_get_basic(it, &s);
00281         return s;
00282         
00283     case DBUS_TYPE_INT32: 
00284     case DBUS_TYPE_UINT32:
00285         dbus_message_iter_get_basic(it, &i);
00286         return i;
00287         
00288     case DBUS_TYPE_INT64: 
00289     case DBUS_TYPE_UINT64: 
00290         dbus_message_iter_get_basic(it, &l);
00291         return l;
00292         
00293     case DBUS_TYPE_STRING: 
00294         dbus_message_iter_get_basic(it, &str);
00295         return atof(str);
00296         
00297     case DBUS_TYPE_VARIANT:
00298         return open().getnext().get_double();
00299         
00300     default:
00301         return 0;
00302     }
00303 }
00304 
00305 
00306 WvString *WvDBusMsg::Iter::ptr() const
00307 {
00308     s = get_str();
00309     return &s;
00310 }
00311 
00312 
00313 
00314 
00315 static DBusMessageIter *new_append_iter(WvDBusMsg &msg)
00316 {
00317     DBusMessageIter *it = new DBusMessageIter;
00318     dbus_message_iter_init_append(msg, it);
00319     return it;
00320 }
00321 
00322 
00323 WvDBusMsg::WvDBusMsg(WvStringParm busname, WvStringParm objectname, 
00324                      WvStringParm interface, WvStringParm method)
00325 {
00326     msg = dbus_message_new_method_call(busname, objectname, interface, method);
00327     itlist.prepend(new_append_iter(*this), true);
00328 }
00329 
00330 
00331 WvDBusMsg::WvDBusMsg(WvDBusMsg &_msg)
00332 {
00333     msg = _msg.msg;
00334     dbus_message_ref(msg);
00335     itlist.prepend(new_append_iter(*this), true);
00336 }
00337 
00338 
00339 WvDBusMsg::WvDBusMsg(DBusMessage *_msg)
00340 {
00341     msg = _msg;
00342     dbus_message_ref(msg);
00343     itlist.prepend(new_append_iter(*this), true);
00344 }
00345 
00346 
00347 WvDBusMsg::~WvDBusMsg()
00348 {
00349     dbus_message_unref(msg);
00350 }
00351 
00352 
00353 WvDBusMsg::operator DBusMessage* () const
00354 {
00355     return msg;
00356 }
00357 
00358 
00359 WvString WvDBusMsg::get_sender() const
00360 {
00361     return dbus_message_get_sender(msg);
00362 }
00363 
00364 
00365 WvString WvDBusMsg::get_dest() const
00366 {
00367     return dbus_message_get_destination(msg);
00368 }
00369 
00370 
00371 WvString WvDBusMsg::get_path() const
00372 {
00373     return dbus_message_get_path(msg);
00374 }
00375 
00376 
00377 WvString WvDBusMsg::get_interface() const
00378 {
00379     return dbus_message_get_interface(msg);
00380 }
00381 
00382 
00383 WvString WvDBusMsg::get_member() const
00384 {
00385     return dbus_message_get_member(msg);
00386 }
00387 
00388 
00389 WvString WvDBusMsg::get_error() const
00390 {
00391     if (iserror())
00392         return dbus_message_get_error_name(msg);
00393 
00394     return WvString::null;
00395 }
00396 
00397 bool WvDBusMsg::is_reply() const
00398 {
00399     // This used to have a hack to deal with replies to message #0.
00400     // But it turns out the first message is #1, so that's not an actual
00401     // problem.
00402     return get_replyserial() != 0;
00403 }
00404 
00405 
00406 uint32_t WvDBusMsg::get_serial() const
00407 {
00408     return dbus_message_get_serial(msg);
00409 }
00410 
00411 
00412 uint32_t WvDBusMsg::get_replyserial() const
00413 {
00414     return dbus_message_get_reply_serial(msg);
00415 }
00416 
00417 
00418 void WvDBusMsg::get_arglist(WvStringList &list) const
00419 {
00420     Iter(*this).get_all(list);
00421 }
00422 
00423 
00424 WvString WvDBusMsg::get_argstr() const
00425 {
00426     return Iter(*this).get_all();
00427 }
00428 
00429 
00430 WvDBusMsg::operator WvString() const
00431 {
00432     WvString dest(get_dest());
00433     if (!dest)
00434         dest = "";
00435     else
00436         dest = WvString("%s:", dest);
00437     if (is_reply())
00438     {
00439         if (iserror())
00440             return WvString("ERR#%s->%s#%s(%s)",
00441                             get_serial(), dest, get_replyserial(),
00442                             get_argstr());
00443         else
00444             return WvString("REPLY#%s->%s#%s(%s)",
00445                             get_serial(), dest, get_replyserial(),
00446                             get_argstr());
00447     }
00448     else
00449     {
00450         WvString s("%s%s/%s.%s(%s)#%s",
00451                    dest,
00452                    get_path(), get_interface(), get_member(),
00453                    get_argstr(), get_serial());
00454         s = strreplace(s, "org.freedesktop.DBus", "o.f.D");
00455         s = strreplace(s, "org/freedesktop/DBus", "o/f/D");
00456         return s;
00457     }
00458 }
00459 
00460 
00461 WvDBusMsg &WvDBusMsg::append(const char *s)
00462 {
00463     assert(msg);
00464     assert(s);
00465     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_STRING, &s);
00466     return *this;
00467 }
00468 
00469 
00470 WvDBusMsg &WvDBusMsg::append(bool b)
00471 {
00472     assert(msg);
00473     dbus_bool_t bb = b;
00474     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BOOLEAN, &bb);
00475     return *this;
00476 }
00477 
00478 
00479 WvDBusMsg &WvDBusMsg::append(signed char c)
00480 {
00481     assert(msg);
00482     dbus_unichar_t cc = c;
00483     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BYTE, &cc);
00484     return *this;
00485 }
00486 
00487 
00488 WvDBusMsg &WvDBusMsg::append(unsigned char c)
00489 {
00490     assert(msg);
00491     dbus_unichar_t cc = c;
00492     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_BYTE, &cc);
00493     return *this;
00494 }
00495 
00496 
00497 WvDBusMsg &WvDBusMsg::append(int16_t i)
00498 {
00499     assert(msg);
00500     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT16, &i);
00501     return *this;
00502 }
00503 
00504 
00505 WvDBusMsg &WvDBusMsg::append(uint16_t i)
00506 {
00507     assert(msg);
00508     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT16, &i);
00509     return *this;
00510 }
00511 
00512 
00513 WvDBusMsg &WvDBusMsg::append(int32_t i)
00514 {
00515     assert(msg);
00516     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT32, &i);
00517     return *this;
00518 }
00519 
00520 
00521 WvDBusMsg &WvDBusMsg::append(uint32_t i)
00522 {
00523     assert(msg);
00524     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT32, &i);
00525     return *this;
00526 }
00527 
00528 
00529 WvDBusMsg &WvDBusMsg::append(int64_t i)
00530 {
00531     assert(msg);
00532     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_INT64, &i);
00533     return *this;
00534 }
00535 
00536 
00537 WvDBusMsg &WvDBusMsg::append(uint64_t i)
00538 {
00539     assert(msg);
00540     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_UINT64, &i);
00541     return *this;
00542 }
00543 
00544 
00545 WvDBusMsg &WvDBusMsg::append(double d)
00546 {
00547     assert(msg);
00548     dbus_message_iter_append_basic(itlist.first(), DBUS_TYPE_DOUBLE, &d);
00549     return *this;
00550 }
00551 
00552 
00553 WvDBusMsg &WvDBusMsg::variant_start(WvStringParm element_type)
00554 {
00555     DBusMessageIter *parent = itlist.first();
00556     DBusMessageIter *sub = new DBusMessageIter;
00557     dbus_message_iter_open_container(parent,
00558                                      DBUS_TYPE_VARIANT, element_type, sub);
00559     itlist.prepend(sub, true);
00560     return *this;
00561 }
00562 
00563 
00564 WvDBusMsg &WvDBusMsg::variant_end()
00565 {
00566     assert(itlist.count() >= 2);
00567     
00568     WvList<DBusMessageIter>::Iter i(itlist);
00569     i.rewind(); i.next();
00570     DBusMessageIter *sub = i.ptr();
00571     i.next();
00572     DBusMessageIter *parent = i.ptr();
00573     
00574     dbus_message_iter_close_container(parent, sub);
00575     itlist.unlink_first();
00576     return *this;
00577 }
00578 
00579 
00580 WvDBusMsg &WvDBusMsg::struct_start(WvStringParm element_type)
00581 {
00582     DBusMessageIter *parent = itlist.first();
00583     DBusMessageIter *sub = new DBusMessageIter;
00584     dbus_message_iter_open_container(parent,
00585                                      DBUS_TYPE_STRUCT, 0, sub);
00586     itlist.prepend(sub, true);
00587     return *this;
00588 }
00589 
00590 
00591 WvDBusMsg &WvDBusMsg::struct_end()
00592 {
00593     return array_end(); // same thing
00594 }
00595 
00596 
00597 WvDBusMsg &WvDBusMsg::array_start(WvStringParm element_type)
00598 {
00599     DBusMessageIter *parent = itlist.first();
00600     DBusMessageIter *sub = new DBusMessageIter;
00601     dbus_message_iter_open_container(parent,
00602                                      DBUS_TYPE_ARRAY, element_type, sub);
00603     itlist.prepend(sub, true);
00604     return *this;
00605 }
00606 
00607 
00608 WvDBusMsg &WvDBusMsg::array_end()
00609 {
00610     return variant_end(); // same thing
00611 }
00612 
00613 
00614 WvDBusMsg &WvDBusMsg::varray_start(WvStringParm element_type)
00615 {
00616     variant_start(WvString("a%s", element_type));
00617     return array_start(element_type);
00618 }
00619 
00620 
00621 WvDBusMsg &WvDBusMsg::varray_end()
00622 {
00623     assert(itlist.count() >= 3);
00624     array_end();
00625     return variant_end();
00626 }
00627 
00628 
00629 WvDBusMsg WvDBusMsg::reply()
00630 {
00631     return WvDBusReplyMsg(*this);
00632 }
00633 
00634 
00635 bool WvDBusMsg::iserror() const
00636 {
00637     return dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR;
00638 }
00639 
00640 
00641 void WvDBusMsg::send(WvDBusConn &conn)
00642 {
00643     conn.send(*this);
00644 }
00645 
00646 
00647 WvDBusReplyMsg::WvDBusReplyMsg(DBusMessage *_msg) 
00648     : WvDBusMsg(dbus_message_new_method_return(_msg))
00649 {
00650     dbus_message_unref(msg);
00651 }
00652 
00653 
00654 WvDBusSignal::WvDBusSignal(WvStringParm objectname, WvStringParm interface,
00655                            WvStringParm name)
00656     : WvDBusMsg(dbus_message_new_signal(objectname, interface, name))
00657 {
00658     dbus_message_unref(msg);
00659 }
00660 
00661 
00662 DBusMessage *WvDBusError::setup1(WvDBusMsg &in_reply_to,
00663                          WvStringParm errname, WvStringParm message)
00664 {
00665     return dbus_message_new_error(in_reply_to, errname, message);
00666 }
00667 
00668 void WvDBusError::setup2()
00669 {
00670     dbus_message_unref(msg);
00671 }