Commits

portix committed a15ad33

Fixing scan-builld errors; keyring functions

  • Participants
  • Parent commits d00af56

Comments (0)

Files changed (9)

 $(error Cannot find json-c)
 endif
 
+LIBSECRET=libsecret-1
+ifeq ($(shell pkg-config --exists ${LIBSECRET} && echo 1), 1)
+LIBS+=libsecret-1
+USE_LIB_SECRET := 1
+endif
+
 
 # HTML-files
 INFO_FILE=info.html
 M4FLAGS += -DWITH_GTK3=1
 endif
 
+ifeq (${USE_LIB_SECRET}, 1)
+CPPFLAGS+=-DWITH_LIBSECRET
+endif
+
+
 #defines
 CFLAGS += -DINFO_FILE=\"$(INFO_FILE)\"
 CFLAGS += -DSETTINGS_FILE=\"$(SETTINGS_FILE)\"
 set_loader(const char *name, const char *config, int flags) 
 {
     char *script = NULL;
-    char shortcut[64], command[128];
+    char shortcut[64], command[128] = { 0 };
     gboolean load = true;
     gboolean has_cmd;
 
         get_response(command, sizeof(command), "Command for toggling "EXT(%s)"?", name);
         load = yes_no(1, "Load "EXT(%s)" on startup", name);
     }
-    has_cmd = command != NULL && *command != '\0';
+    has_cmd = (command != NULL) && (*command != '\0');
 
     if (config == NULL || flags & F_NO_CONFIG) 
     {
     LOG(3, "Closing %s\n", archive);
 
     fclose(s_out);
+    s_out_path = NULL;
+
     return ret;
 }
 

scripts/lib/enums.js.in

 };
 Object.freeze(LoadStatus);
 /**
+ * Results of keyring actions
+ * @constant
+ * @name KeyringResult
+ * @memberOf Enums and Flags
+ * @type Object
+ * @property {Enum}  ok             Function call was successfull
+ * @property {Enum}  keyringExists  A keyring with that name already exists
+ * @property {Enum}  noSuchKeyring  A keyring with the provided name wasn't found
+ * @property {Enum}  serviceError   Couldn't get a keyring service
+ * @property {Enum}  error          General error
+ * */
+const KeyringResult = { 
+    ok : 0, 
+    keyringExists : 1,
+    noSuchKeyring : 2,
+    serviceError : 3,
+    error : 4
+};
+Object.freeze(KeyringResult);
+/**
  * Gdk modifier flag
  * @constant
  * @name Modifier 
 #include "dom.h"
 #include "ipc.h"
 #include "plugindb.h"
+#include "secret.h"
 
 #ifndef DISABLE_HSTS
 #include "hsts.h"
 dwb_set_setting(const char *key, char *value, int scope) 
 {
     WebSettings *s;
-    Arg *a = NULL, oldarg = { .p = NULL };
+    Arg *a = NULL, oldarg;
 
     DwbStatus ret = STATUS_ERROR;
 
 #endif
     fprintf(stdout, "      cairo : %d.%d.%d\n",  CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR, CAIRO_VERSION_MICRO);
 }
+void 
+got_collections(int state, GList *l, gpointer *data) {
+    /*for (GList *g = l; g; g=g->next) {*/
+        /*puts(g->data);*/
+    /*}*/
+    /*g_list_free_full(l, g_free);*/
+    gtk_main_quit();
+}
 /* MAIN {{{*/
 int 
 main(int argc, char *argv[]) 
 {
+//    gtk_init(NULL, NULL);
+//
+//    /*dwb_secret_get_collections((dwb_secret_cb)got_collections, NULL);*/
+//    dwb_secret_create_collection((dwb_secret_cb)got_collections, "foo", NULL);
+//
+//    ///*dwb_secret_create_collection();*/
+//    //dwb_secret_store_password("mytest-password", "blubblub", "xxy");
+//    ///*const char *pwd = dwb_secret_get_password("xxy");*/
+//    ///*if (pwd) {*/
+//    //    /*puts(pwd);*/
+//    ///*}*/
+//    gtk_main();
+//    return 0;
+
     dwb.misc.name = REAL_NAME;
     dwb.misc.profile = "default";
     dwb.misc.prog_path = argv[0];
 #include "application.h" 
 #include "completion.h" 
 #include "entry.h" 
+#include "secret.h" 
 
 #define API_VERSION 1.10
 
     NAMESPACE_TABS, 
     NAMESPACE_TIMER, 
     NAMESPACE_UTIL, 
+#ifdef WITH_LIBSECRET
+    NAMESPACE_KEYRING, 
+#endif
     NAMESPACE_LAST,
 };
 enum {
 static GList *
 find_webview(JSObjectRef o) 
 {
+    g_return_val_if_fail(dwb.state.fview != NULL, NULL);
+
     for (GList *r = dwb.state.fview; r; r=r->next)
         if (VIEW(r)->script_wv == o)
             return r;
 static JSValueRef 
 wv_get_all_frames(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) 
 {
+    JSValueRef ret = NIL;
     int argc = 0, n = 0;
     GSList *frames = NULL;
     GList *gl = find_webview(object);
         }
     }
 
-    JSValueRef argv[argc];
+    if (argc > 0) {
+        JSValueRef argv[argc];
 
-    for (GSList *sl = frames; sl; sl=sl->next) {
-        WebKitWebFrame *frame = sl->data;
-        if (frame != NULL) {
-            argv[n++] = make_object(ctx, G_OBJECT(sl->data));
+        for (GSList *sl = frames; sl; sl=sl->next) {
+            WebKitWebFrame *frame = sl->data;
+            if (frame != NULL) {
+                argv[n++] = make_object(ctx, G_OBJECT(sl->data));
+            }
         }
+        ret = JSObjectMakeArray(ctx, argc, argv, exception);
     }
     g_slist_free_full(frames, (GDestroyNotify)g_object_unref);
 
-    return JSObjectMakeArray(ctx, argc, argv, exception);
+    return ret;
 }/*}}}*/
 
 /** 
         [NAMESPACE_TABS]        = "tabs",
         [NAMESPACE_TIMER]       = "timer",
         [NAMESPACE_UTIL]        = "util",
+#ifdef WITH_LIBSECRET
+        [NAMESPACE_KEYRING]     = "keyring"
+#endif
     };
     JSValueRef ret = NULL;
     if (argc > 0) {
     guchar *data;
     gushort *js_data;
     JSStringRef string;
-    JSValueRef ret = NIL;
+    JSValueRef ret;
+
     if (argc == 0)
         return NIL;
     base64 = js_value_to_char(ctx, argv[0], -1, exc);
     else
         return NULL;
 }
+
+#ifdef WITH_LIBSECRET
+void
+on_keyring_no_val(int status, void *unused, JSObjectRef d) {
+    (void) unused;
+    EXEC_LOCK;
+    JSValueRef args[] = { JSValueMakeNumber(s_ctx->global_context, status) };
+    if (status == DWB_SECRET_OK) {
+        deferred_resolve(s_ctx->global_context, d, d, 1, args, NULL);
+    }
+    else {
+        deferred_reject(s_ctx->global_context, d, d, 1, args, NULL);
+    }
+    EXEC_UNLOCK;
+}
+void 
+on_keyring_string(int status, const char *value, JSObjectRef dfd) {
+    EXEC_LOCK;
+    if (status == DWB_SECRET_OK) {
+        JSValueRef args[] = { value == NULL ? NIL : js_char_to_value(s_ctx->global_context, value) };
+        deferred_resolve(s_ctx->global_context, dfd, dfd, 1, args, NULL);
+    }
+    else {
+        JSValueRef args[] = { JSValueMakeNumber(s_ctx->global_context, status) };
+        deferred_reject(s_ctx->global_context, dfd, dfd, 1, args, NULL);
+    }
+    EXEC_UNLOCK;
+}
+
+static JSValueRef
+keyring_call_str(JSContextRef ctx, void (*secret_func)(dwb_secret_cb, const char *, void *), size_t argc, const JSValueRef argv[], JSValueRef *exc) {
+    if (argc > 0) {
+        char *name = js_value_to_char(ctx, argv[0], -1, exc);
+        if (name != NULL) {
+            JSObjectRef d = deferred_new(ctx);
+            secret_func((dwb_secret_cb)on_keyring_no_val, name, d);
+            g_free(name);
+            return d;
+        }
+    }
+    return NIL;
+}
+
+/**
+ * Checks if a service can be retrieved, i.e. gnome-keyring-daemon is installed and
+ * running or could be started 
+ *
+ * @name checkService
+ * @memberOf keyring
+ * @function
+ * @example 
+ * keyring.checkService().then(
+ *      function() {
+ *          io.print("Everything's fine");
+ *      }, 
+ *      function() 
+ *          io.print("No service");
+ *      }
+ * );
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if a service can be retrieved and
+ *      rejected if an error occured.
+ */
+static JSValueRef 
+keyring_check_service(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    JSObjectRef d = deferred_new(ctx);
+    dwb_secret_check_service((dwb_secret_cb)on_keyring_no_val, d);
+    return d;
+}
+/**
+ * Creates a new keyring, if a keyring with the same name already exists no new keyring is created
+ *
+ * @name create
+ * @memberOf keyring
+ * @function
+ * @example 
+ * keyring.create("foo").then(function() {
+ *     io.print("keyring created");
+ * });
+ *
+ * @param {String} keyring The name of the keyring
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if the keyring was created or rejected
+ *      if a keyring with the same name already exists or an error occured
+ *
+ */
+static JSValueRef 
+keyring_create(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    return keyring_call_str(ctx, dwb_secret_create_collection, argc, argv, exc);
+}
+/**
+ * Unlocks a keyring
+ *
+ * @name unlock
+ * @memberOf keyring
+ * @function
+ * @example 
+ * keyring.unlock("foo").then(function() {
+ *     io.print("keyring unlocked");
+ * });
+ *
+ * @param {String} keyring The name of the keyring
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if the keyring was unlocked or rejected
+ *      if no such keyring exists or an error occured
+ *
+ */
+static JSValueRef 
+keyring_unlock(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    return keyring_call_str(ctx, dwb_secret_unlock_collection, argc, argv, exc);
+}
+/**
+ * Locks a keyring
+ *
+ * @name lock
+ * @memberOf keyring
+ * @function
+ * @example 
+ * keyring.lock("foo").then(function() {
+ *     io.print("keyring locked");
+ * });
+ *
+ * @param {String} keyring The name of the keyring
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if the keyring was locked or rejected
+ *      if no such keyring exists or an error occured
+ *
+ */
+static JSValueRef 
+keyring_lock(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    return keyring_call_str(ctx, dwb_secret_lock_collection, argc, argv, exc);
+}
+
+/**
+ * Stores a password in a keyring
+ *
+ * @name store
+ * @memberOf keyring
+ * @function
+ * @example 
+ * var id = script.generateId();
+ * keyring.store("foo", "mypassword", id, "secretpassword").then(function() {
+ *     io.print("keyring locked");
+ * });
+ *
+ * @param {String} keyring  The name of the keyring
+ * @param {String} label    Label for the password
+ * @param {String} id       Identifier for the password
+ * @param {String} password The password
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if the password was save or rejected
+ *      if no such keyring exists or an error occured
+ *
+ */
+static JSValueRef 
+keyring_store(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    JSValueRef ret = NIL;
+    JSObjectRef dfd;
+    char *collection = NULL, *label = NULL, *id = NULL, *pwd = NULL;
+
+    if (argc < 4) 
+        return NIL;
+
+    collection = js_value_to_char(ctx, argv[0], -1, exc);
+    if (collection == NULL) 
+        goto error_out;
+    label = js_value_to_char(ctx, argv[1], -1, exc);
+    if (label == NULL) 
+        goto error_out;
+    id = js_value_to_char(ctx, argv[2], -1, exc);
+    if (id == NULL) 
+        goto error_out;
+    pwd = js_value_to_char(ctx, argv[3], -1, exc);
+    if (pwd == NULL) 
+        goto error_out;
+
+    dfd = deferred_new(ctx);
+    dwb_secret_store_pwd((dwb_secret_cb)on_keyring_no_val, collection, label, id, pwd, dfd);
+
+    sec_memset(pwd, 0, strlen(pwd));
+
+    ret = dfd;
+error_out: 
+    g_free(collection);
+    g_free(label);
+    g_free(id);
+    g_free(pwd);
+    return ret;
+}
+
+/**
+ * Get a password from a keyring
+ *
+ * @name lookup
+ * @memberOf keyring
+ * @function
+ * @example 
+ * keyring.lookup("foo", "myid").then(function(password) {
+ *     io.print("password: " + password);
+ * });
+ *
+ * @param {String} keyring  The name of the keyring
+ * @param {String} id       Identifier of the password
+ *
+ * @returns {Deferred} 
+ *      A deferred that will be resolved if the password was found or rejected
+ *      if no such keyring exists, the password wasn't found or an error occured
+ *
+ */
+static JSValueRef 
+keyring_lookup(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
+    JSValueRef ret = NIL;
+    JSObjectRef dfd;
+    char *collection = NULL, *id = NULL;
+
+    if (argc < 2) 
+        return NIL;
+
+    collection = js_value_to_char(ctx, argv[0], -1, exc);
+    if (collection == NULL) 
+        goto error_out;
+    id = js_value_to_char(ctx, argv[1], -1, exc);
+    if (id == NULL) 
+        goto error_out;
+
+    dfd = deferred_new(ctx);
+    dwb_secret_lookup_pwd((dwb_secret_cb)on_keyring_string, collection, id, dfd);
+    ret = dfd;
+error_out: 
+    g_free(collection);
+    g_free(id);
+    return ret;
+}
+#endif // WITH_LIBSECRET
+
 /**
  * Sets content of the system clipboard
  * @name set
 static JSValueRef 
 widget_get_children(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc)  {
     GtkWidget *widget = JSObjectGetPrivate(this);
+
     g_return_val_if_fail(widget != NULL, UNDEFINED);
-    JSValueRef result = NIL;
+
+    JSValueRef result;
     GList *children = NULL;
+
     int i=0;
 
     if (! GTK_IS_CONTAINER(widget))
     JSClassRelease(class);
 
     /**
+     * Namespace for managing passwords, needs gnome-keyring
+     * @namespace 
+     *      Access to gnome-keyring
+     * @name keyring 
+     * @static 
+     * @example
+     *
+     * //!javascript
+     * 
+     * var keyring = namespace("keyring");
+     * 
+     * var collection = "foo";
+     * var id = script.generateId();
+     * 
+     * keyring.create(collection).always(function(status) {
+     *     if (status == KeyringResult.ok || KeyringResult.keyringExists) {
+     *         keyring.store(collection, "foobar", id, "secret").then(function() {
+     *             io.print("password saved");
+     *         });;
+     *     }
+     * });
+     *
+     * */
+#ifdef WITH_LIBSECRET
+    JSStaticFunction keyring_functions[] = { 
+        { "checkService",            keyring_check_service,       kJSDefaultAttributes },
+        { "create",                  keyring_create,       kJSDefaultAttributes },
+        { "lock",                    keyring_lock,       kJSDefaultAttributes },
+        { "unlock",                  keyring_unlock,       kJSDefaultAttributes },
+        { "store",                   keyring_store,       kJSDefaultAttributes },
+        { "lookup",                  keyring_lookup,      kJSDefaultAttributes },
+        { 0, 0, 0 }, 
+    };
+    class = create_class("keyring", keyring_functions, NULL, NULL);
+    s_ctx->namespaces[NAMESPACE_KEYRING] = JSObjectMake(ctx, class, NULL);
+    JSClassRelease(class);
+#endif
+
+    /**
      * Access to the system clipboard
      * @namespace 
      *      Accessing the system clipboard
+/*
+ * Copyright (c) 2014 Stefan Bolte <portix@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 WITH_LIBSECRET
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include "secret.h"
+
+static const SecretSchema s_schema = {
+    "org.bitbucket.dwb.secrets", SECRET_SCHEMA_NONE, {
+        { "id", SECRET_SCHEMA_ATTRIBUTE_STRING }, 
+        { NULL, 0 },
+    }
+};
+
+enum {
+    DWB_SECRET_ACTION_NONE, 
+    DWB_SECRET_ACTION_STORE, 
+    DWB_SECRET_ACTION_LOOKUP, 
+    DWB_SECRET_ACTION_LOCK, 
+    DWB_SECRET_ACTION_UNLOCK, 
+};
+
+typedef struct dwb_secret_s dwb_secret_t;
+typedef struct dwb_pwd_s dwb_pwd_t;
+
+struct dwb_secret_s {
+    void *data;
+    void *user_data;
+    void (*free_func)(void*);
+    dwb_secret_cb cb;
+    int action;
+};
+
+struct dwb_pwd_s {
+    char *collection;
+    char *label;
+    char *id;
+    char *pwd; 
+};
+#define get_service_init(cb, s) secret_service_get(SECRET_SERVICE_LOAD_COLLECTIONS | SECRET_SERVICE_OPEN_SESSION, \
+        NULL, (GAsyncReadyCallback)cb, s)
+
+
+static dwb_pwd_t * 
+dwb_pwd_new(const char *collection, const char *label, const char *id, const char *password) {
+    dwb_pwd_t *pwd = g_malloc0(sizeof(dwb_pwd_t));
+    if (collection != NULL) 
+        pwd->collection = g_strdup(collection);
+    if (label != NULL) 
+        pwd->label = g_strdup(label);
+    if (id != NULL) 
+        pwd->id = g_strdup(id);
+    if (pwd != NULL) 
+        pwd->pwd = g_strdup(password);
+    return pwd;
+}
+
+static void
+dwb_pwd_free(dwb_pwd_t *pwd) {
+    g_return_if_fail(pwd != NULL);
+    g_free(pwd->collection);
+    g_free(pwd->label);
+    g_free(pwd->id);
+    if (pwd->pwd != NULL) {
+        secret_password_free(pwd->pwd);
+    }
+    g_free(pwd);
+}
+
+static dwb_secret_t *
+dwb_secret_new(dwb_secret_cb cb, void *data, void *user_data, void (*free_func)(void *), int action) {
+
+    dwb_secret_t *secret = g_malloc0(sizeof(dwb_secret_t));
+
+    secret->data = data;
+    secret->user_data = user_data;
+    secret->free_func = free_func;
+    secret->cb = cb;
+    secret->action = action;
+    return secret;
+}
+
+static void 
+dwb_secret_free(dwb_secret_t *s) {
+    g_return_if_fail(s != NULL);
+    if (s->data != NULL && s->free_func != NULL) {
+        s->free_func(s->data);
+    }
+    g_free(s);
+
+}
+
+static void
+invoke(dwb_secret_t *s, int state, const void *data) {
+    g_return_if_fail(s != NULL);
+    if (s->cb != NULL) {
+        s->cb(state, data, s->user_data);
+    }
+    dwb_secret_free(s);
+}
+
+static SecretService *
+get_service(dwb_secret_t *secret, GAsyncResult *result)  {
+    GError *e = NULL;
+    SecretService *service = secret_service_get_finish(result, &e);
+    if (e != NULL) {
+        invoke(secret, DWB_SECRET_SERVICE_ERROR, NULL);
+        g_error_free(e);
+    }
+    return service;
+}
+
+static SecretCollection *
+collection_first_matching(SecretService *service, const char *name) {
+    SecretCollection *ret = NULL;
+    GList *collections = secret_service_get_collections(service);
+    for (GList *l = collections; l != NULL && ret == NULL; l=l->next) {
+        SecretCollection *collection = l->data;
+        char *label = secret_collection_get_label(collection);
+        if (!g_strcmp0(name, label)) {
+            ret = g_object_ref(collection);
+        }
+    }
+    g_list_free_full(collections, g_object_unref);
+    return ret;
+}
+
+static const char *
+collection_lookup_path(SecretService *service, const char *name) {
+    const char *ret = NULL;
+    SecretCollection *collection = collection_first_matching(service, name);
+    if (collection != NULL) {
+        ret = g_dbus_proxy_get_object_path((GDBusProxy *) collection);
+        g_object_unref(collection);
+    }
+    return ret;
+}
+
+/*
+ * create collection
+ * */
+static void 
+on_created_collection(GObject *o, GAsyncResult *result, dwb_secret_t *secret) {
+    GError *e = NULL;
+    SecretCollection *collection = secret_collection_create_finish(result, &e);
+    if (e == NULL) {
+        invoke(secret, DWB_SECRET_OK, NULL);
+        g_object_unref(collection);
+    }
+    else {
+        invoke(secret, DWB_SECRET_ERROR, NULL);
+        g_clear_error(&e);
+    }
+}
+static void 
+on_service_create_collection(GObject *source, GAsyncResult *result, dwb_secret_t *secret) {
+    SecretService *service = get_service(secret, result);
+    if (service != NULL) {
+        SecretCollection *collection = collection_first_matching(service, secret->data);
+        if (collection == NULL) {
+            secret_collection_create(service, secret->data, NULL, SECRET_COLLECTION_CREATE_NONE, NULL, 
+                    (GAsyncReadyCallback)on_created_collection, secret);
+        }
+        else {
+            invoke(secret, DWB_SECRET_COLLECTION_EXISTS, NULL);
+            g_object_unref(collection);
+        }
+        g_object_unref(service);
+    }
+}
+void 
+dwb_secret_create_collection(dwb_secret_cb cb, const char *name, void *user_data) {
+    dwb_secret_t *s = dwb_secret_new(cb, g_strdup(name), user_data, g_free, DWB_SECRET_ACTION_NONE);
+    get_service_init(on_service_create_collection, s);
+}
+/*
+ * lock
+ */
+
+static void 
+on_lock_unlock_collection(SecretService *service, GAsyncResult *result, dwb_secret_t *secret) {
+    GError *e = NULL;
+    int status = DWB_SECRET_OK;
+
+    if (secret->action == DWB_SECRET_ACTION_LOCK) {
+        secret_service_lock_finish(service, result, NULL, &e);
+    }
+    else {
+        secret_service_unlock_finish(service, result, NULL, &e);
+    }
+    if (e != NULL) {
+        status = DWB_SECRET_ERROR;
+        g_error_free(e);
+    }
+
+    invoke(secret, status, NULL);
+}
+
+static void 
+on_service_lock_unlock_collection(GObject *source, GAsyncResult *result, dwb_secret_t *secret) {
+    SecretService *service = get_service(secret, result);
+    if (service == NULL) 
+        return;
+
+    GList *cols = NULL;
+    GList *collections = secret_service_get_collections(service);
+    gboolean lock = secret->action == DWB_SECRET_ACTION_LOCK;
+
+    for (GList *l = collections; l != NULL; l=l->next) {
+        SecretCollection *collection = l->data;
+        gboolean locked = secret_collection_get_locked(collection);
+        if ((lock && !locked) || (!lock && locked)) {
+            char *label = secret_collection_get_label(collection);
+            if (!g_strcmp0(secret->data, label)) {
+                cols = g_list_append(cols, collection);
+            }
+            g_free(label);
+        }
+    }
+    if (cols != NULL) {
+        if (!lock) 
+            secret_service_unlock(service, cols, NULL, (GAsyncReadyCallback)on_lock_unlock_collection, secret);
+        else 
+            secret_service_lock(service, cols, NULL, (GAsyncReadyCallback)on_lock_unlock_collection, secret);
+    }
+    else {
+        invoke(secret, DWB_SECRET_NO_SUCH_COLLECTION, NULL);
+    }
+    if (collections != NULL) {
+        g_list_free_full(collections, g_object_unref);
+    }
+    g_object_unref(service);
+}
+
+void 
+dwb_secret_lock_collection(dwb_secret_cb cb, const char *name, void *user_data) {
+    dwb_secret_t *s = dwb_secret_new(cb, g_strdup(name), user_data, g_free, DWB_SECRET_ACTION_LOCK);
+    get_service_init(on_service_lock_unlock_collection, s);
+}
+void 
+dwb_secret_unlock_collection(dwb_secret_cb cb, const char *name, void *user_data) {
+    dwb_secret_t *s = dwb_secret_new(cb, g_strdup(name), user_data, g_free, DWB_SECRET_ACTION_UNLOCK);
+    get_service_init(on_service_lock_unlock_collection, s);
+}
+
+/*  
+ *  store
+ * */
+
+static void 
+on_store_pwd(GObject *o, GAsyncResult *result, dwb_secret_t *secret) {
+    gboolean success = secret_password_store_finish(result, NULL);
+    invoke(secret, success ? DWB_SECRET_OK : DWB_SECRET_ERROR, NULL);
+}
+static void 
+on_lookup_pwd(GObject *o, GAsyncResult *result, dwb_secret_t *secret) {
+    GError *e = NULL;
+    char *pwd = secret_password_lookup_finish(result, &e);
+    if (e == NULL) {
+        invoke(secret, DWB_SECRET_OK, pwd);
+        secret_password_free(pwd);
+    }
+    else {
+        invoke(secret, DWB_SECRET_ERROR, NULL);
+        g_error_free(e);
+    }
+}
+
+static void 
+on_service_pwd(GObject *source, GAsyncResult *result, dwb_secret_t *secret) {
+    SecretService *service = get_service(secret, result);
+    if (service != NULL) {
+        dwb_pwd_t *pwd = secret->data;
+        const char *path = collection_lookup_path(service, pwd->collection);
+        if (path != NULL) {
+            if (secret->action == DWB_SECRET_ACTION_STORE) {
+                secret_password_store(&s_schema, path, pwd->label, pwd->pwd, NULL,
+                        (GAsyncReadyCallback)on_store_pwd, secret, "id", pwd->id, NULL);
+            }
+            else {
+                secret_password_lookup(&s_schema, NULL, (GAsyncReadyCallback)on_lookup_pwd, secret, "id", pwd->id, NULL);
+            }
+        }
+        else {
+            invoke(secret, DWB_SECRET_NO_SUCH_COLLECTION, NULL);
+        }
+        g_object_unref(service);
+    }
+}
+
+void 
+dwb_secret_store_pwd(dwb_secret_cb cb, const char *collection, 
+        const char *label, const char *id, const char *password, void *user_data) {
+    dwb_pwd_t *pwd = dwb_pwd_new(collection, label, id, password);
+    dwb_secret_t *s = dwb_secret_new(cb, pwd, user_data, (void (*)(void *))dwb_pwd_free, DWB_SECRET_ACTION_STORE);
+    get_service_init(on_service_pwd, s);
+}
+
+void 
+dwb_secret_lookup_pwd(dwb_secret_cb cb, const char *collection, const char *id, void *user_data) {
+    dwb_pwd_t *pwd = dwb_pwd_new(collection, NULL, id, NULL);
+    dwb_secret_t *s = dwb_secret_new(cb, pwd, user_data, (void (*)(void *))dwb_pwd_free, DWB_SECRET_ACTION_LOOKUP);
+    get_service_init(on_service_pwd, s);
+}
+
+void 
+on_service_check_service(GObject *o, GAsyncResult *result, dwb_secret_t *secret) {
+    SecretService *service = get_service(secret, result);
+    if (service != NULL) {
+        invoke(secret, DWB_SECRET_OK, NULL);
+        g_object_unref(service);
+    }
+}
+void 
+dwb_secret_check_service(dwb_secret_cb cb, void *user_data) {
+    dwb_secret_t *s = dwb_secret_new(cb, NULL, user_data, NULL, DWB_SECRET_ACTION_NONE);
+    get_service_init(on_service_check_service, s);
+}
+#endif
+/*
+ * Copyright (c) 2014 Stefan Bolte <portix@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 WITH_LIBSECRET
+
+#ifndef __DWB_SECRET_H__
+#define __DWB_SECRET_H__
+
+#include <libsecret/secret.h>
+#include <glib-2.0/glib.h>
+
+
+typedef void (* dwb_secret_cb)(int, const void *, void *);
+
+enum {
+    DWB_SECRET_OK,
+    DWB_SECRET_COLLECTION_EXISTS,
+    DWB_SECRET_NO_SUCH_COLLECTION,
+    DWB_SECRET_SERVICE_ERROR,
+    DWB_SECRET_ERROR,
+};
+
+void 
+dwb_secret_create_collection(dwb_secret_cb cb, const char *name, void *user_data);
+
+void 
+dwb_secret_lock_collection(dwb_secret_cb cb, const char *name, void *user_data);
+
+void 
+dwb_secret_unlock_collection(dwb_secret_cb cb, const char *name, void *user_data);
+
+void 
+dwb_secret_store_pwd(dwb_secret_cb cb, const char *collection, const char *label, 
+        const char *id, const char *password, void *user_data);
+
+void 
+dwb_secret_lookup_pwd(dwb_secret_cb cb, const char *collection, const char *id, void *user_data);
+
+void 
+dwb_secret_check_service(dwb_secret_cb cb, void *user_data);
+
+#endif
+
+#endif
 void 
 session_set_name(const char *name)
 {
-    g_return_if_fail(name != NULL || !(*name));
+    g_return_if_fail(name != NULL && *name);
 
     if (s_session_name)
         g_free(s_session_name);