[vlc-devel] [RFC PATCH 5/8] keystore: add kwallet module

Thomas Guillem thomas at gllm.fr
Wed Dec 30 19:37:02 CET 2015


TODO: see #if 0: QDBusServiceWatcher and openWallet(Asynchronous) are not
working. Indeed, signals are not received even when a QApplication is running
(via the qt interface).
---
 configure.ac                 |  33 +++
 modules/keystore/Makefile.am |  20 ++
 modules/keystore/kwallet.cpp | 566 +++++++++++++++++++++++++++++++++++++++++++
 modules/keystore/kwallet.hpp |  69 ++++++
 4 files changed, 688 insertions(+)
 create mode 100644 modules/keystore/kwallet.cpp
 create mode 100644 modules/keystore/kwallet.hpp

diff --git a/configure.ac b/configure.ac
index 9582139..1443e87 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4075,6 +4075,39 @@ dnl
 PKG_ENABLE_MODULES_VLC([SECRET], [], [libsecret-1], [use libsecret for keystore], [auto])
 
 dnl
+dnl  kwallet
+dnl
+AC_ARG_ENABLE(kwallet,
+  [AS_HELP_STRING([--enable-kwallet],
+    [use KWallet for keystore (default auto)])])
+have_kwallet="no"
+KWALLET_CXXFLAGS=""
+KWALLET_LIBS=""
+AS_IF([test "${enable_qt}" != "no" -a "${KDE4_CONFIG}" != "no" -a "${enable_kwallet}" != "no" ], [
+  VLC_SAVE_FLAGS
+  AC_LANG_PUSH([C++])
+  KWALLET_CXXFLAGS="$QT_CFLAGS $CXXFLAGS_qt4 -I`$KDE4_CONFIG --path include`"
+  CPPFLAGS="$CPPFLAGS $KWALLET_CXXFLAGS"
+  AC_CHECK_HEADER([kwallet.h], [
+    KWALLET_LIBS="$QT_LIBS -L`$KDE4_CONFIG --install lib` -lkdeui"
+    LDFLAGS="$LDFLAGS $KWALLET_LIBS"
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <kwallet.h>], [
+KWallet::Wallet::LocalWallet();
+    ])], [
+      have_kwallet="yes"
+    ])
+  AC_LANG_POP([C++])
+  VLC_RESTORE_FLAGS
+  ])
+#])
+AS_IF([test "$enable_kwallet" = "yes" -a "$have_kwallet" = "no" ], [
+  AC_MSG_ERROR([KWallet headers or so not found])
+])
+AC_SUBST(KWALLET_CXXFLAGS)
+AC_SUBST(KWALLET_LIBS)
+AM_CONDITIONAL([HAVE_KWALLET], [test "${have_kwallet}" = "yes"])
+
+dnl
 dnl  Developers helper modules (should be hidden from configure help)
 dnl
 AC_ARG_ENABLE(devtools, [], [], [enable_devtools="no"])
diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
index dc8c526..64787de 100644
--- a/modules/keystore/Makefile.am
+++ b/modules/keystore/Makefile.am
@@ -8,6 +8,26 @@ libsecret_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(SECRET_CFLAGS)
 libsecret_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(keystoredir)'
 libsecret_plugin_la_LIBADD = $(SECRET_LIBS)
 
+
+# Meta-object compilation
+
+SUFFIXES += .hpp .moc.cpp
+moc_verbose = $(moc_verbose_$(V))
+moc_verbose_ = $(moc_verbose__$(AM_DEFAULT_VERBOSITY))
+moc_verbose_0 = @echo "  MOC   " $@;
+moc_verbose__0 = $(moc_verbose_0)
+
+.hpp.moc.cpp:
+	$(moc_verbose)$(MOC) $(MOC_CPPFLAGS) -o $@ $<
+
+libkwallet_plugin_la_SOURCES = keystore/kwallet.cpp keystore/kwallet.moc.cpp
+libkwallet_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
+libkwallet_plugin_la_CXXFLAGS = $(KWALLET_CXXFLAGS)
+libkwallet_plugin_la_LIBADD = $(KWALLET_LIBS)
+if HAVE_KWALLET
+keystore_LTLIBRARIES += libkwallet_plugin.la
+endif
+
 keystore_LTLIBRARIES += \
 	$(LTLIBsecret)
 
diff --git a/modules/keystore/kwallet.cpp b/modules/keystore/kwallet.cpp
new file mode 100644
index 0000000..caeddb5
--- /dev/null
+++ b/modules/keystore/kwallet.cpp
@@ -0,0 +1,566 @@
+/*****************************************************************************
+ * kwallet.cpp: KWallet keystore module
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "kwallet.hpp"
+
+#include <vlc_plugin.h>
+#include <vlc_interrupt.h>
+#include <vlc_strings.h>
+
+#include <QMap>
+#include <QUrl>
+#include <QApplication>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/qdbusservicewatcher.h>
+
+#define MAP_KEY_SECRET QString("secret")
+
+#define qfu(i) QString::fromUtf8(i)
+#define qtu(i) ((i).toUtf8().constData())
+
+static int Open(vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+    set_shortname(N_("KWallet keystore"))
+    set_description(N_("secrets are stored via KWallet"))
+    set_category(CAT_ADVANCED)
+    set_subcategory(SUBCAT_ADVANCED_MISC)
+    set_capability("keystore", 100)
+    set_callbacks(Open, Close)
+    cannot_unload_broken_library()
+vlc_module_end ()
+
+VLCKWallet::VLCKWallet(vlc_object_t *obj)
+    : mState(STATE_INIT)
+    , mObj(obj)
+    , mWallet(NULL)
+{}
+
+static const char *const ppsz_keys[] = {
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    "realm",
+    "authtype",
+};
+static_assert(sizeof(ppsz_keys)/sizeof(*ppsz_keys) == KEY_MAX, "key mismatch");
+
+static int
+str2key(const char *psz_key)
+{
+    for (unsigned int i = 0; i < KEY_MAX; ++i)
+    {
+        if (ppsz_keys[i] && strcmp(ppsz_keys[i], psz_key) == 0)
+            return i;
+    }
+    return -1;
+}
+
+void
+VLCKWallet::openWallet(bool opened)
+{
+    QMutexLocker locker(&mMutex);
+    mState = opened ? STATE_CONNECTED : STATE_DISCONNECTED;
+    mCond.wakeOne();
+}
+
+void
+VLCKWallet::closeWallet()
+{
+    QMutexLocker locker(&mMutex);
+    mState = STATE_DISCONNECTED;
+    mCond.wakeOne();
+}
+
+void
+VLCKWallet::registerService(const QString &serviceName)
+{
+    printf("VLCKWallet::registerService\n");
+    (void) serviceName;
+    QMutexLocker locker(&mMutex);
+    mState = STATE_SERVICE_ALIVE;
+    mCond.wakeOne();
+}
+
+void
+VLCKWallet::unregisterService(const QString &serviceName)
+{
+    printf("VLCKWallet::unregisterService\n");
+    (void) serviceName;
+    QMutexLocker locker(&mMutex);
+    if (mServiceCount-- == 0)
+    {
+        mState = STATE_DISCONNECTED;
+        mCond.wakeOne();
+    }
+}
+
+void
+VLCKWallet::interrupted(void *data)
+{
+    VLCKWallet *self = (VLCKWallet *) data;
+
+    self->closeWallet();
+}
+
+/**
+ * Connect to KWallet synchronously but it can be interrupted by VLC.
+ */
+bool
+VLCKWallet::connect(bool b_force)
+{
+    /* Asynchronous methods (QDBusServiceWatcher and
+     * KWallet::Wallet::Asynchronous) need a running QCoreApplication or
+     * QApplication. There can be only one and it's currently used by the qt
+     * interface. TODO: Spawn the singleton Qt thread from here or from the qt
+     * interface module */
+    if (QApplication::instance() == NULL)
+        return false;
+
+    QMutexLocker locker(&mMutex);
+
+#if 0
+    if (!b_force)
+    {
+        /* First, check if kwallet service is running using
+         * QDBusServiceWatcher. Indeed, openWallet() will spawn a service if
+         * it's not running, even on non KDE environments */
+        QDBusServiceWatcher watcher(QString::fromLatin1("org.kde.kwalletd5"),
+                                    QDBusConnection::sessionBus());
+        watcher.addWatchedService("org.kde.kwalletd");
+        mServiceCount = 2;
+
+        vlc_interrupt_register(interrupted, this);
+
+        if (!QObject::connect(&watcher, SIGNAL(serviceUnregistered(QString)),
+                              this, SLOT(unregisterService(QString))))
+            return false;
+        if (!QObject::connect(&watcher, SIGNAL(serviceRegistered(QString)),
+                              this, SLOT(registerService(QString))))
+            return false;
+
+        while (mState == STATE_INIT)
+            mCond.wait(&mMutex);
+
+        vlc_interrupt_unregister();
+
+        if (mState != STATE_SERVICE_ALIVE)
+            return false;
+    }
+    else
+        mState = STATE_SERVICE_ALIVE;
+
+    mWallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0,
+                                          KWallet::Wallet::Asynchronous);
+    if (!mWallet)
+    {
+        msg_Err(mObj, "openWallet failed");
+        return false;
+    }
+    mWallet->setParent(this);
+
+    vlc_interrupt_register(interrupted, this);
+
+    /* Connect KWallet signals */
+    if (!QObject::connect(mWallet, SIGNAL(walletOpened(bool)),
+                          this, SLOT(openWallet(bool))))
+    {
+        msg_Err(mObj, "could not connect to walletOpened");
+        return false;
+    }
+    if (!QObject::connect(mWallet, SIGNAL(walletClosed()),
+                          this, SLOT(closeWallet())))
+    {
+        msg_Err(mObj, "could not connect to walletClosed");
+        return false;
+    }
+
+    /* Wait for wallet connection or vlc interrupt */
+    while (mState == STATE_SERVICE_ALIVE)
+        mCond.wait(&mMutex);
+
+    vlc_interrupt_unregister();
+#else
+    mWallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0,
+                                          KWallet::Wallet::Synchronous);
+    if (!mWallet)
+    {
+        msg_Err(mObj, "openWallet failed");
+        return false;
+    }
+    mWallet->setParent(this);
+    mState = STATE_CONNECTED;
+#endif
+
+    if (mState == STATE_CONNECTED)
+    {
+        /* Create VLC folder if it doesn't exist */
+        if (!mWallet->hasFolder(VLC_KEYSTORE_NAME))
+        {
+            if (!mWallet->createFolder(VLC_KEYSTORE_NAME))
+            {
+                msg_Err(mObj, "could not create '%s' folder'", VLC_KEYSTORE_NAME);
+                return false;
+            }
+        }
+        /* set VLC folder */
+        return mWallet->setFolder(VLC_KEYSTORE_NAME);
+    }
+    else
+        return false;
+}
+
+static int
+str2int(const char *psz_port)
+{
+    if (psz_port)
+    {
+        bool ok;
+        int i_port = qfu(psz_port).toInt(&ok);
+        if (!ok)
+            return -1;
+        return i_port;
+    }
+    else
+        return -1;
+}
+
+/**
+ * Create a key and a map from values
+ */
+static QString
+values2Key(const char * const ppsz_values[KEY_MAX])
+{
+    const char *psz_protocol = ppsz_values[KEY_PROTOCOL];
+    const char *psz_user = ppsz_values[KEY_USER];
+    const char *psz_server = ppsz_values[KEY_SERVER];
+    const char *psz_path = ppsz_values[KEY_PATH];
+    const char *psz_port = ppsz_values[KEY_PORT];
+    int i_port = str2int(psz_port);
+
+    if (!psz_protocol || !psz_user || !psz_server || !psz_path)
+        return QString();
+
+    QUrl url;
+    url.setScheme(qfu(psz_protocol));
+    url.setUserName(qfu(psz_user));
+    url.setHost(qfu(psz_server));
+    url.setPath(qfu(psz_path));
+
+    if (i_port != -1)
+        url.setPort(i_port);
+
+    if (!url.isValid())
+        return QString();
+    return url.toString();
+}
+
+static int
+key2Values(const QString &key, const char * ppsz_values[KEY_MAX])
+{
+    QUrl url(key);
+    if (!url.isValid())
+        return VLC_EGENERIC;
+
+    if (url.scheme().isEmpty() || url.userName().isEmpty()
+     || url.host().isEmpty() || url.path().isEmpty())
+        return VLC_EGENERIC;
+
+    ppsz_values[KEY_PROTOCOL] = strdup(qtu(url.scheme()));
+    ppsz_values[KEY_USER] = strdup(qtu(url.userName()));
+    ppsz_values[KEY_SERVER] = strdup(qtu(url.host()));
+    ppsz_values[KEY_PATH] = strdup(qtu(url.path()));
+
+    if (!ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_USER]
+     || !ppsz_values[KEY_SERVER] || !ppsz_values[KEY_PATH])
+        return VLC_EGENERIC;
+
+    int i_port = url.port();
+    if (i_port != -1)
+    {
+        ppsz_values[KEY_PORT] = strdup(qtu(QString("%1").arg(i_port)));
+        if (!ppsz_values[KEY_PORT])
+            return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+static bool
+matchKey(const QString &key, const char * const ppsz_values[KEY_MAX])
+{
+    QUrl url(key);
+    if (!url.isValid())
+        return false;
+
+    if (url.scheme().isEmpty() || url.userName().isEmpty()
+     || url.host().isEmpty() || url.path().isEmpty())
+        return false;
+
+    const char *psz_protocol = ppsz_values[KEY_PROTOCOL];
+    const char *psz_user = ppsz_values[KEY_USER];
+    const char *psz_server = ppsz_values[KEY_SERVER];
+    const char *psz_path = ppsz_values[KEY_PATH];
+    const char *psz_port = ppsz_values[KEY_PORT];
+    int i_port = str2int(psz_port);
+
+    return (!psz_protocol || strcmp(psz_protocol, qtu(url.scheme())) == 0)
+        && (!psz_user || strcmp(psz_user, qtu(url.userName())) == 0)
+        && (!psz_server || strcmp(psz_server, qtu(url.host())) == 0)
+        && (!psz_path || strcmp(psz_path, qtu(url.path())) == 0)
+        && (i_port == -1 || i_port == url.port());
+}
+
+static QMap<QString, QString>
+values2Map(const char * const ppsz_values[KEY_MAX])
+{
+    QMap<QString, QString> map;
+    for (unsigned int i = 0; i < KEY_MAX; ++i)
+    {
+        const char *psz_key = ppsz_keys[i];
+        if (psz_key && ppsz_values[i])
+            map.insert(qfu(psz_key), qfu(ppsz_values[i]));
+    }
+    return map;
+}
+
+/**
+ * Return true if all pairs of matchMap are in map (and not the contrary).
+ */
+static bool
+matchMaps(const QMap<QString, QString> &matchMap,
+          const QMap<QString, QString> &map)
+{
+    if (matchMap.isEmpty())
+        return true;
+
+    QMapIterator<QString, QString> it(matchMap);
+    while (it.hasNext())
+    {
+        it.next();
+        if (map.value(it.key()) != it.value())
+            return false;
+    }
+    return true;
+}
+
+/**
+ * Fill a keystore entry from a map and a key
+ */
+static int
+mapAndKey2Entry(const QMap<QString, QString> &map, const QString &key,
+                vlc_keystore_entry *p_entry)
+{
+    QMapIterator<QString, QString> it(map);
+    while (it.hasNext())
+    {
+        it.next();
+        if (it.key() != MAP_KEY_SECRET)
+        {
+            /* Copy map pair to ppsz_values */
+            const char *psz_key = qtu(it.key());
+            int i_key = str2key(psz_key);
+            if (i_key == -1 || i_key >= KEY_MAX)
+                return VLC_EGENERIC;
+
+            char *psz_value = strdup(qtu(it.value()));
+            if (!psz_value)
+                return VLC_EGENERIC;
+            p_entry->ppsz_values[i_key] = psz_value;
+        }
+        else
+        {
+            /* Copy secret from the map */
+            p_entry->i_secret_len = 
+                vlc_b64_decode_binary(&p_entry->p_secret,
+                                      it.value().toLocal8Bit().constData());
+            if (!p_entry->i_secret_len)
+                return VLC_EGENERIC;
+        }
+    }
+    return key2Values(key, (const char **)p_entry->ppsz_values);
+}
+
+int
+VLCKWallet::store(const char * const ppsz_values[KEY_MAX],
+                   const uint8_t *p_secret, size_t i_secret_len,
+                   const char *psz_label)
+{
+    (void) psz_label;
+    QMutexLocker locker(&mMutex);
+
+    if (mState != STATE_CONNECTED)
+        return VLC_EGENERIC;
+
+    /* Get key and map from values */
+    QString key = values2Key(ppsz_values);
+    if (key.isEmpty())
+        return VLC_EGENERIC;
+    QMap<QString, QString> map = values2Map(ppsz_values);
+
+    /* Encode secret, since KWallet can't store binary */
+    char *psz_b64_secret = vlc_b64_encode_binary(p_secret, i_secret_len);
+    if (!psz_b64_secret)
+        return VLC_EGENERIC;
+    /* Write the secret into the map */
+    map.insert(MAP_KEY_SECRET, QString(psz_b64_secret));
+    free(psz_b64_secret);
+
+    /* Write the map at the specified key */
+    if (mWallet->writeMap(key, map) != 0)
+        return VLC_EGENERIC;
+
+    return VLC_SUCCESS;
+}
+
+unsigned int
+VLCKWallet::find(const char * const ppsz_values[KEY_MAX],
+                  vlc_keystore_entry **pp_entries)
+{
+    QMutexLocker locker(&mMutex);
+
+    if (mState != STATE_CONNECTED)
+        return 0;
+
+    /* Get map from values */
+    QMap<QString, QString> matchMap = values2Map(ppsz_values);
+
+    /* Fetch all maps */
+    QMap<QString, QMap<QString, QString>> mapMap;
+    if (mWallet->readMapList(QString("*"), mapMap) != 0)
+        return 0;
+
+    unsigned int i_entry_count = 0;
+    vlc_keystore_entry *p_entries = (vlc_keystore_entry *)
+        calloc(mapMap.size(), sizeof(vlc_keystore_entry));
+
+    QMapIterator<QString, QMap<QString, QString>> it(mapMap);
+    while (it.hasNext())
+    {
+        it.next();
+
+        if (!matchKey(it.key(), ppsz_values) || !matchMaps(matchMap, it.value()))
+            continue;
+
+        /* Matching key/value */
+        vlc_keystore_entry *p_entry = &p_entries[i_entry_count++];
+
+        /* Fill the entry from the map and the key */
+        if (mapAndKey2Entry(it.value(), it.key(), p_entry))
+        {
+            vlc_keystore_release_entries(p_entries, i_entry_count);
+            return 0;
+        }
+    }
+    *pp_entries = p_entries;
+    return i_entry_count;
+}
+
+unsigned int
+VLCKWallet::remove(const char * const ppsz_values[KEY_MAX])
+{
+    QMutexLocker locker(&mMutex);
+
+    if (mState != STATE_CONNECTED)
+        return 0;
+
+    QMap<QString, QString> matchMap = values2Map(ppsz_values);
+
+    /* Fetch all maps */
+    QMap<QString, QMap<QString, QString>> mapMap;
+    if (mWallet->readMapList("*", mapMap) != 0)
+        return 0;
+
+    unsigned int i_entry_count = 0;
+    QMapIterator<QString, QMap<QString, QString>> it(mapMap);
+    while (it.hasNext())
+    {
+        it.next();
+
+        if (!matchKey(it.key(), ppsz_values) || !matchMaps(matchMap, it.value()))
+            continue;
+
+        /* Matching key/value */
+        if (mWallet->removeEntry(it.key()) == 0)
+            i_entry_count++;
+    }
+    return i_entry_count;
+}
+
+static int
+Store(vlc_keystore *p_keystore, const char * const ppsz_values[KEY_MAX],
+      const uint8_t *p_secret, size_t i_secret_len, const char *psz_label)
+{
+    VLCKWallet *p_wallet = (VLCKWallet *) p_keystore->p_sys;
+
+    return p_wallet->store(ppsz_values, p_secret, i_secret_len, psz_label);
+}
+
+static unsigned int
+Find(vlc_keystore *p_keystore, const char * const ppsz_values[KEY_MAX],
+     vlc_keystore_entry **pp_entries)
+{
+    VLCKWallet *p_wallet = (VLCKWallet *) p_keystore->p_sys;
+
+    return p_wallet->find(ppsz_values, pp_entries);
+}
+
+static unsigned int
+Remove(vlc_keystore *p_keystore, const char * const ppsz_values[KEY_MAX])
+{
+    VLCKWallet *p_wallet = (VLCKWallet *) p_keystore->p_sys;
+
+    return p_wallet->remove(ppsz_values);
+}
+
+static int
+Open(vlc_object_t *p_this)
+{
+    VLCKWallet *p_wallet = new VLCKWallet(p_this);
+
+    if (!p_wallet->connect(p_this->b_force))
+    {
+        delete p_wallet;
+        return VLC_EGENERIC;
+    }
+    vlc_keystore *p_keystore = (vlc_keystore *)p_this;
+    p_keystore->p_sys = (vlc_keystore_sys *) p_wallet;
+    p_keystore->pf_store = Store;
+    p_keystore->pf_find = Find;
+    p_keystore->pf_remove = Remove;
+
+    return VLC_SUCCESS;
+}
+
+static void
+Close(vlc_object_t *p_this)
+{
+    vlc_keystore *p_keystore = (vlc_keystore *)p_this;
+    VLCKWallet *p_wallet = (VLCKWallet *) p_keystore->p_sys;
+
+    delete p_wallet;
+}
diff --git a/modules/keystore/kwallet.hpp b/modules/keystore/kwallet.hpp
new file mode 100644
index 0000000..e03c325
--- /dev/null
+++ b/modules/keystore/kwallet.hpp
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * kwallet.hpp: KWallet keystore module
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_keystore.h>
+
+#include <kwallet.h>
+#include <QObject>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QWaitCondition>
+
+class VLCKWallet : public QObject
+{
+    Q_OBJECT
+
+public:
+    VLCKWallet(vlc_object_t *obj);
+    bool connect(bool b_force);
+    int store(const char * const ppsz_values[KEY_MAX],
+              const uint8_t *p_secret, size_t i_secret_len,
+              const char *psz_label);
+    unsigned int find(const char * const ppsz_values[KEY_MAX],
+                      vlc_keystore_entry **pp_entries);
+    unsigned int remove(const char * const ppsz_values[KEY_MAX]);
+
+private slots:
+    void openWallet(bool opened);
+    void closeWallet();
+    void registerService(const QString &serviceName);
+    void unregisterService(const QString &serviceName);
+
+private:
+    static void interrupted(void *data);
+
+    enum {
+        STATE_INIT,
+        STATE_SERVICE_ALIVE,
+        STATE_CONNECTED,
+        STATE_DISCONNECTED,
+    } mState;
+
+    vlc_object_t *      mObj;
+    KWallet::Wallet *   mWallet;
+    QMutex              mMutex;
+    QWaitCondition      mCond;
+    unsigned int        mServiceCount;
+};
-- 
2.1.4



More information about the vlc-devel mailing list