Tp::ContactPtr ToTpContactPtr(TpContact * tpContact)
{
    if (!tpContact) {
        return Tp::ContactPtr();
    }

    TpConnection * tpConnection = tp_contact_get_connection(tpContact);
    if (!tpConnection) {
        return Tp::ContactPtr();
    }

    const gchar *busName = tp_proxy_get_bus_name(TP_PROXY(tpConnection));
    if (!busName) {
        return Tp::ContactPtr();
    }

    const gchar *objectPath = tp_proxy_get_object_path(TP_PROXY(tpConnection));
    if (!objectPath) {
        return Tp::ContactPtr();
    }

    Tp::ConnectionPtr connection = Tp::Connection::create(busName, objectPath);
    if (connection.isNull()) {
        return Tp::ContactPtr();
    }

    if (connection->contactManager().isNull()) {
        return Tp::ContactPtr();
    }

    TpHandle handle = tp_contact_get_handle(contact);
    // TODO use async version
    return connection->contactManager()->lookupContactByHandle(handle);
}
bool TelepathyAddContactPage::apply(Kopete::Account *account, Kopete::MetaContact *parentMetaContact)
{
    if (!account->isConnected()) {
        KMessageBox::error(this, i18n("You must be connected to add a contact."), i18n("Telepathy plugin"));
        return false;
    }
    TelepathyAccount *tAccount = static_cast<TelepathyAccount*>(account);

    Tp::ConnectionPtr connection = tAccount->account()->connection();

    if (!connection) {
        KMessageBox::error(this, i18n("You must be connected to add a contact."), i18n("Telepathy plugin"));
        kWarning() << "TelepathyAccount->account()->connection() is null.";
        return false;
    }

    if (connection->status() != Tp::ConnectionStatusConnected) {
        KMessageBox::error(this, i18n("You must be connected to add a contact."), i18n("Telepathy plugin"));
        kWarning() << "connection.status() is not Connected.";
        return false;
    }

    // Get new id.
    QString newId = d->mainUi.textUserId->text();

    kDebug() << "Starting to apply adding contact" << newId;

    QObject::connect(connection->contactManager()->contactsForIdentifiers(QStringList() << newId),
            SIGNAL(finished(Tp::PendingOperation*)),
            new TelepathyAddContactAsyncContext(tAccount, parentMetaContact),
            SLOT(normalizedContactFetched(Tp::PendingOperation*)));

    return true;
}
TpContact *ToTpContact(Tp::ContactPtr contact)
{
    if (contact.isNull()) {
        return 0;
    }

    Tp::ReferencedHandles handles = contact->handle();
    if (handles.isEmpty()) {
        return 0;
    }

    GError *error = 0;
    TpDBusDaemon * tpDBusDaemon = tp_dbus_daemon_dup(&error);
    if (error) {
        g_error_free(error);
        return 0;
    }

    if (!tpDBusDaemon) {
        return 0;
    }

    if (!contact->manager()) {
        return 0;
    }

    Tp::ConnectionPtr connection = contact->manager()->connection();
    if (!connection) {
        return 0;
    }

    QString busName = connection->busName();
    QString objectPath = connection->objectPath();
    TpConnection *tpConnection = tp_connection_new(tpDBusDaemon, busName.toLatin1(), objectPath.toLatin1(), &error);
    if (error) {
        return 0;
    }

    if (!tpConnection) {
        return 0;
    }

    Tp::ReferencedHandles::const_iterator it;
    for(it = handles.constBegin(); it != handles.constEnd(); it++) {
        // todo use async version: tp_connection_get_contacts_by_handle
        TpContact *tpContact = tp_connection_dup_contact_if_possible(tpConnection, *it, contact->id().toLatin1());
        if (tpContact) {
            return tpContact;
        }
    }

    return 0;
}
void ContactWrapper::onConnectionChanged(const Tp::ConnectionPtr& newConn)
{
    // connection needs to be valid
    if (newConn) {
        connect(newConn->contactManager().data(), SIGNAL(stateChanged(Tp::ContactListState)), this, SLOT(onContactManagerStateChanged(Tp::ContactListState)));
    }
}
ChatSession::ChatSession(const QString &room_id, Tp::ConnectionPtr tp_connection): state_(STATE_INITIALIZING), self_participant_(NULL)
{
    QVariantMap params;
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType"), QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT));
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"), Tp::HandleTypeRoom);
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetID"), room_id);

    Tp::PendingChannel* pending_channel = tp_connection->ensureChannel(params);
    connect(pending_channel,
            SIGNAL( finished(Tp::PendingOperation*) ),
            SLOT( OnTextChannelCreated(Tp::PendingOperation*) ));
}
ChatSession::ChatSession(Contact& self_contact, Contact& contact, Tp::ConnectionPtr tp_connection) : state_(STATE_INITIALIZING), self_participant_(&self_contact)
{
    ChatSessionParticipant* p = new ChatSessionParticipant(&contact);
    participants_.push_back(p);

    QVariantMap params;
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType"), QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT));
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"), Tp::HandleTypeContact);
    params.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandle"), contact.GetTpContact()->handle().at(0));

    Tp::PendingChannel* pending_channel = tp_connection->ensureChannel(params);
    connect(pending_channel,
            SIGNAL( finished(Tp::PendingOperation*) ),
            SLOT( OnTextChannelCreated(Tp::PendingOperation*) ));
}
TpSessionChannel::TpSessionChannel(Tp::ConnectionPtr conn, const Tp::ContactPtr &contact)
{
    QDEBUG_FUNCTION_BEGIN
    QVariantMap request;
    qDebug() << "TpSessionChannel::TpSessionChannel" << "contact.id() " << contact->id();

    request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType"),
                   TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT);
    request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"),
                   (uint) Tp::HandleTypeContact);
    request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandle"),
                   contact->handle()[0]);

    connect(conn->ensureChannel(request),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onChannelCreated(Tp::PendingOperation*)));

    peerContact = contact;

    QDEBUG_FUNCTION_END
}
ContactInfoDialog::ContactInfoDialog(const Tp::AccountPtr &account, const Tp::ContactPtr &contact, QWidget *parent)
    : QDialog(parent)
    , d(new Private(this))
{
#if 0   // Editing contacts is not yet supported in TpQt
    /* Whether contact is the user himself */
    d->editable = (contact == account->connection()->selfContact());
#endif
    d->editable = false;
    d->account = account;
    d->contact = KTp::ContactPtr::qObjectCast(contact);

    d->buttonBox = new QDialogButtonBox(this);


    if (d->editable) {
        d->buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close);
    } else {
        d->buttonBox->setStandardButtons(QDialogButtonBox::Close);
    }

    connect(d->buttonBox, &QDialogButtonBox::clicked, this, &ContactInfoDialog::slotButtonClicked);

    setMaximumSize(sizeHint());

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setSpacing(30);

    /* Title - presence icon, alias, id */
    KTitleWidget *titleWidget = new KTitleWidget(this);
    KTp::Presence presence(contact->presence());
    titleWidget->setPixmap(presence.icon().pixmap(32, 32), KTitleWidget::ImageLeft);
    titleWidget->setText(contact->alias());
    titleWidget->setComment(contact->id());
    layout->addWidget(titleWidget);

    /* 1st column: avatar; 2nd column: details */
    d->columnsLayout = new QHBoxLayout();
    d->columnsLayout->setSpacing(30);
    layout->addLayout(d->columnsLayout);

    /* Make sure the contact has all neccessary features ready */
    Tp::PendingContacts *op = contact->manager()->upgradeContacts(
            QList<Tp::ContactPtr>() << contact,
            Tp::Features() << Tp::Contact::FeatureAvatarData
                           << Tp::Contact::FeatureInfo);
    connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactUpgraded(Tp::PendingOperation*)));

    /* State Info - there is no point showing this information when it's about ourselves */
    if (!d->editable) {
        d->stateLayout = new QFormLayout();
        d->stateLayout->setSpacing(10);
        layout->addLayout(d->stateLayout);

        // Fetch roster feature, if it is supported, but not loaded
        Tp::ConnectionPtr conn = contact->manager()->connection();
        if(!conn->actualFeatures().contains(Tp::Connection::FeatureRoster) && !conn->missingFeatures().contains(Tp::Connection::FeatureRoster)) {
            Tp::PendingReady *pr = conn->becomeReady(Tp::Features() << Tp::Connection::FeatureRoster);

            connect(pr, SIGNAL(finished(Tp::PendingOperation*)),
                    SLOT(onFeatureRosterReady(Tp::PendingOperation*)));
        } else {
            d->loadStateRows();
        }
    }

    layout->addWidget(d->buttonBox);
}