Active Topics

 


Reply
Thread Tools
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#1
Hi!

I'm working on OTR integration for Harmattans conversations UI.
It should be fine by using D-Bus but I have a problem with D-Bus objects converting to Qt-Classes.

But let me explain.

I would like to connect to the interface "org.freedesktop.Telepathy.Channel.Interface.Messa ges" and method "MessageReceived".

dbus-monitor shows this structure:

Code:
signal sender=:1.606 -> dest=(null destination) serial=333 path=/org/freedesktop/Telepathy/Connection/gabble/jabber/XXX_2fnokiaN9/ImChannel33; interface=org.freedesktop.Telepathy.Channel.Interface.Messages; member=MessageReceived
   array [
      array [
         dict entry(            string "pending-message-id"
            variant                uint32 0
         )
         dict entry(
            string "message-sender-id"            
            variant                string "XXX@jabberes.org"
         )
         dict entry(
            string "message-received"
            variant                int64 1440523701    
         )
         dict entry(
            string "message-sender"
            variant                uint32 33
         )      ]
      array [
         dict entry(
            string "content"
            variant                string "Message content" 
          )
         dict entry(
            string "content-type"
            variant                string "text/plain"
         )      ]
   ]
So I wrote the following Qt-Code to connect to this event:

Code:
QDBusConnection::sessionBus().connect(QString(), 
    QString(),
     "org.freedesktop.Telepathy.Channel.Interface.Messages",
     "MessageReceived", this, 
     SLOT(telepathyMessageReceived(QList<QVariant>)));
It works fine and my SLOT will be called on incoming messages:

Code:
void ImControlThread::telepathyMessageReceived(QList<QVariant> _content)
{
    qDebug() << "ImControlThread::telepathyMessageReceived(): size=" << _content.size() << ". Variant=" << _content.at(0).typeName();
}
I have there a QList<QVariant>. The QVariant-Objects must be a QList again with some QVariantMap entries.
But now, I'm out of idea. I'm just not able to parse the D-Bus structure from QList<QVariant>.
The debug output in my SLOT shows for _content.size() == 2. But for _content.at(0).typeName() == "void*".

No chance to cast it in something I can extract the data from.

Do you have an idea? Thank you very much for any hint!

Last edited by chrm; 2015-09-05 at 19:15.
 

The Following User Says Thank You to chrm For This Useful Post:
marxian's Avatar
Posts: 2,448 | Thanked: 9,523 times | Joined on Aug 2010 @ Wigan, UK
#2
I think you will need to use QDBusMessage and QDBusArgument in order to convert the reply arguments:

Code:
void ImControlThread::telepathyMessageReceived(const QDBusMessage &reply) {
    foreach (QVariant arg, reply.arguments()) {
        if (arg.canConvert<QDBusArgument>()) {
            qDebug() << dbusArgumentToVariant(arg.value<QDBusArgument>());
        }
        else {
            qDebug() << arg;
        }
    }
}

QVariant dbusArgumentToVariant(const QDBusArgument &arg) {
    switch (arg.currentType()) {
    case QDBusArgument::BasicType:
    case QDBusArgument::VariantType:
        return basicTypeToVariant(arg);
    case QDBusArgument::ArrayType:
        return arrayTypeToVariant(arg);
    case QDBusArgument::MapType:
        return mapTypeToVariant(arg);
    default:
        return QVariant();
    }
}

QVariant basicTypeToVariant(const QDBusArgument &arg) {
    return arg.asVariant();
}

QVariant arrayTypeToVariant(const QDBusArgument &arg) {
    QVariantList list;
    arg.beginArray();

    while (!arg.atEnd()) {
        list << dbusArgumentToVariant(arg);
    }

    arg.endArray();
    return list;
}

QVariant mapTypeToVariant(const QDBusArgument &arg) {
    QVariantMap map;
    arg.beginMap();

    while (!arg.atEnd()) {
        arg.beginMapEntry();
        map[basicTypeToVariant(arg).toString()] = dbusArgumentToVariant(arg);
        arg.endMapEntry();
    }

    arg.endMap();
    return map;
}
__________________
'Men of high position are allowed, by a special act of grace, to accomodate their reasoning to the answer they need. Logic is only required in those of lesser rank.' - J K Galbraith

My website

GitHub
 

The Following 3 Users Say Thank You to marxian For This Useful Post:
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#3
Perfect! Thank you very much!
 
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#4
Dear marxian,

it works well expect for mapTypeToVariant().
Im able to extract the key name, but value is always empty.
QDBusMessage &reply includes all the data (qDebug() shows everything), but

Code:
map[basicTypeToVariant(arg).toString()] = busArgumentToVariant(arg);
gives a valid map with keys but empty values.

Any idea?
 
marxian's Avatar
Posts: 2,448 | Thanked: 9,523 times | Joined on Aug 2010 @ Wigan, UK
#5
It could be that the QDBusArgument::currentType() of the map values is not handled in dbusArgumentToVariant(), therfore an null QVariant is returned. Try adding a qDebug() statement in that function to check the reported type:

Code:
QVariant dbusArgumentToVariant(const QDBusArgument &arg) {
    qDebug() << "dbusArgumentToVariant. Current type is" << arg.currentType();
    switch (arg.currentType()) {
    case QDBusArgument::BasicType:
    case QDBusArgument::VariantType:
        return basicTypeToVariant(arg);
    case QDBusArgument::ArrayType:
        return arrayTypeToVariant(arg);
    case QDBusArgument::MapType:
        return mapTypeToVariant(arg);
    default:
        qDebug() << "dbusArgumentToVariant. Type not handled.";
        return QVariant();
    }
}
I would expect the map values to be basic/variant type, so perhaps QDBusArgument::asVariant() is returning a null QVariant.
__________________
'Men of high position are allowed, by a special act of grace, to accomodate their reasoning to the answer they need. Logic is only required in those of lesser rank.' - J K Galbraith

My website

GitHub
 

The Following User Says Thank You to marxian For This Useful Post:
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#6
Hi!

Thank you a lot!
Handling for QDBusArgument::MapEntryType is needed. But now it works fine.

The next step is to insert the decrypted message back in tracker so it appears in the conversations UI.

Do you have any experience with the Tracker on N9? I thing, using tracker-sparql to modify the message is the right way.

Thank you for any hint.
 
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#7
Ok, got it. I'm able to remove messages from tracker.

The next step is to insert a new message, the decrypted one.
 
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#8
Dear Marxian,

Reading received messages and changing them in tracker works fine. But I spent the last week trying to send a DBus message to Telepathy - without success

I have to implement this method:
http://telepathy.freedesktop.org/spe...Messages1.html

So this is my code:

Code:
    QList<QVariant> args;

    QDBusObjectPath path("/org/freedesktop/Telepathy/Connection/gabble/jabber/XXX");
    QString targetID = "XXX@jabberes.org";
    args << qVariantFromValue(path);
    args << targetID;

    QMap<QString, QVariant> message;

    message["content"] = QVariant(qVariantFromValue("Message Content"));
    message["content-type"] = QVariant(qVariantFromValue(QString("text/plain")));

    QList<QVariant> msgList;
    msgList << qVariantFromValue(message);

    args << msgList;

    uint flags = 0;
    args << flags;

    m.setArguments(args);
   QDBusMessage retVal = QDBusConnection::sessionBus().call(m);
The retVal error code is:
Code:
QDBusMessage(type=Error, service="", error name="org.freedesktop.DBus.Error.UnknownMethod", error message="Method "SendMessage" with signature "osa{sv}u" on interface "org.freedesktop.Telepathy.ChannelDispatcher.Interface.Messages1" doesn't exist"
So my question is, how to create a message with this signature: "osaa{sv}u", especially this aa{sv}?

I know, there are heavy libs like TelepathyQt, but i want just to send only one message and hope, this could be done with a simple code...

Thank you for any hint.

Last edited by chrm; 2015-09-05 at 19:13. Reason: topic extension for "send"
 

The Following User Says Thank You to chrm For This Useful Post:
Posts: 133 | Thanked: 405 times | Joined on Mar 2012 @ Europe
#9
Finally, it works!

If someone wants to know, how to send an XMMP-Message using Qt and DBus on Harmattan, here it is:

First declare needed typedefs

Code:
typedef QMap<QString, QVariant> KeyVarPair;
typedef QList<KeyVarPair> KeyVarPairList;
Q_DECLARE_METATYPE(KeyVarPair)
Q_DECLARE_METATYPE(KeyVarPairList)
And register them as DBus types:

Code:
qDBusRegisterMetaType<KeyVarPair>();
qDBusRegisterMetaType<KeyVarPairList>();
Now create a sendMessage function:

Code:
bool MyClass::telepathySendDBusMessage(QString _receiver, QString _account, QString _content)
{
    QString dbus_service = "org.freedesktop.Telepathy.ChannelDispatcher";
    QString dbus_path = "/org/freedesktop/Telepathy/ChannelDispatcher";
    QString dbus_interface = "org.freedesktop.Telepathy.ChannelDispatcher.Interface.Messages.DRAFT";
  
    QDBusMessage m = QDBusMessage::createMethodCall(
                                       dbus_service,
                                       dbus_path, 
                                       dbus_interface, 
                                       "SendMessage");
    

    QList<QVariant> args;

    // Path and targetID
    QDBusObjectPath path(_account);
    QString targetID = _receiver;
    args << qVariantFromValue(path);
    args << targetID;

    // Message Parts
    KeyVarPair message1;

    int type = 0;
    message1["message-type"] = qVariantFromValue(type);

    KeyVarPair message2;

    message2["content"] = qVariantFromValue(_content);
    message2["content-type"] = qVariantFromValue(QString("text/plain"));

    KeyVarPairList messageData;
    messageData << message1;
    messageData << message2;

    args << qVariantFromValue(messageData);

    // Flags
    uint flags = 0;
    args << flags;

    m.setArguments(args);
   
    QDBusMessage retVal = QDBusConnection::sessionBus().call(m);

    return true;
}
Call the message:

Code:
myClassObj->telepathySendDBusMessage(
  "to.jabber.account@jabber.server.tld",
  "/org/freedesktop/Telepathy/Account/gabble/jabber/ACCOUNT_NAME",
  "It works!");
Finally I have everything to start with the OTR implementation!
 

The Following 4 Users Say Thank You to chrm For This Useful Post:
Halftux's Avatar
Posts: 862 | Thanked: 2,511 times | Joined on Feb 2012 @ Germany
#10
Originally Posted by chrm View Post
Finally I have everything to start with the OTR implementation!
Wow that is amazing thanks to you and marxian I learned a lot in this thread.

Will be your final project opensource? Wish you success!
 
Reply


 
Forum Jump


All times are GMT. The time now is 13:01.