/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include <pygobject.h>
#include <gnome-keyring.h>
#include "config.h"

gboolean  pygnomekeyring_result_check        (GnomeKeyringResult result);
PyObject* pygnomekeyring_result_to_exception (GnomeKeyringResult result);

typedef struct {
    PyObject *func, *data;
} PyGtkCustomNotify;

static void
pygtk_custom_destroy_notify(gpointer user_data)
{
    PyGtkCustomNotify *cunote = user_data;
    PyGILState_STATE state;

    g_return_if_fail(user_data);
    state = pyg_gil_state_ensure();
    Py_XDECREF(cunote->func);
    Py_XDECREF(cunote->data);
    pyg_gil_state_release(state);
    
    g_free(cunote);
}


#ifndef GNOME_KEYRING_TYPE_INFO
# define GNOME_KEYRING_TYPE_INFO pygnome_keyring_info_get_type()

static GType
pygnome_keyring_info_get_type(void)
{
    static GType our_type = 0;
  
    if (our_type == 0)
        our_type = g_boxed_type_register_static("PyGnomeKeyringInfo",
                                                (GBoxedCopyFunc)gnome_keyring_info_copy,
                                                (GBoxedFreeFunc)gnome_keyring_info_free);
    return our_type;
}

#endif /* #ifndef GNOME_KEYRING_TYPE_INFO */

#ifndef GNOME_KEYRING_TYPE_ITEM_INFO
# define GNOME_KEYRING_TYPE_ITEM_INFO pygnome_keyring_item_info_get_type()

static GType
pygnome_keyring_item_info_get_type(void)
{
    static GType our_type = 0;
  
    if (our_type == 0)
        our_type = g_boxed_type_register_static("PyGnomeKeyringItemInfo",
                                                (GBoxedCopyFunc)gnome_keyring_item_info_copy,
                                                (GBoxedFreeFunc)gnome_keyring_item_info_free);
    return our_type;
}

#endif /* #ifndef GNOME_KEYRING_TYPE_ITEM_INFO */

#ifndef GNOME_KEYRING_TYPE_APPLICATION_REF
# define GNOME_KEYRING_TYPE_APPLICATION_REF pygnome_keyring_application_ref_get_type()
static GType
pygnome_keyring_application_ref_get_type(void)
{
    static GType our_type = 0;
  
    if (our_type == 0)
        our_type = g_boxed_type_register_static("PyGnomeKeyringApplicationRef",
                                                (GBoxedCopyFunc)gnome_keyring_application_ref_copy,
                                                (GBoxedFreeFunc)gnome_keyring_application_ref_free);
    return our_type;
}
#endif /* #ifndef GNOME_KEYRING_APPLICATION_REF_TYPE */

#ifndef GNOME_KEYRING_TYPE_ACCESS_CONTROL
# define GNOME_KEYRING_TYPE_ACCESS_CONTROL pygnome_keyring_access_control_get_type()
static GType
pygnome_keyring_access_control_get_type(void)
{
    static GType our_type = 0;
  
    if (our_type == 0)
        our_type = g_boxed_type_register_static("PyGnomeKeyringAccessControl",
                                                (GBoxedCopyFunc)gnome_keyring_access_control_copy,
                                                (GBoxedFreeFunc)gnome_keyring_access_control_free);
    return our_type;
}
#endif /* #ifndef GNOME_KEYRING_ACCESS_CONTROL_TYPE */

#ifndef GNOME_KEYRING_TYPE_FOUND
# define GNOME_KEYRING_TYPE_FOUND pygnome_keyring_found_get_type()
GnomeKeyringFound *
pygnome_keyring_found_copy (GnomeKeyringFound *found)
{
    GnomeKeyringFound *copy;

    copy = g_new (GnomeKeyringFound, 1);
    memcpy (copy, found, sizeof (GnomeKeyringFound));

    copy->keyring = g_strdup (copy->keyring);
    copy->attributes = gnome_keyring_attribute_list_copy (copy->attributes);
    copy->secret = g_strdup (copy->secret);

    return copy;
}

static GType
pygnome_keyring_found_get_type(void)
{
    static GType our_type = 0;
  
    if (our_type == 0)
        our_type = g_boxed_type_register_static("PyGnomeKeyringFound",
                                                (GBoxedCopyFunc)pygnome_keyring_found_copy,
                                                (GBoxedFreeFunc)gnome_keyring_found_free);
    return our_type;
}
#endif /* #ifndef GNOME_KEYRING_ACCESS_CONTROL_TYPE */

static GnomeKeyringAttributeList *
pygnome_keyring_attribute_list_from_pyobject(PyObject *py_attrlist)
{
    GnomeKeyringAttributeList *attrlist;
    Py_ssize_t iter = 0;
    PyObject *key, *value;
    
    if (!PyDict_Check(py_attrlist)) {
        PyErr_SetString(PyExc_TypeError, "dict expected for attribute list parameter");
        return NULL;
    }

    attrlist = gnome_keyring_attribute_list_new();
    while (PyDict_Next(py_attrlist, &iter, &key, &value)) {
        char *name;
        if (!PyString_Check(key)) {
            PyErr_SetString(PyExc_TypeError, "dict keys must be strings, when converting attribute list parameter");
            gnome_keyring_attribute_list_free(attrlist);
            return NULL;
        }
        name = PyString_AsString(key);
        if (PyInt_Check(value))
            gnome_keyring_attribute_list_append_uint32(attrlist, name,
                                                       PyInt_AsLong(value));
        else if (PyLong_Check(value)) {
            gnome_keyring_attribute_list_append_uint32(attrlist, name,
                                                       PyLong_AsUnsignedLong(value));
            if (PyErr_Occurred()) {
                gnome_keyring_attribute_list_free(attrlist);
                return NULL;
            }
        }
        else if (PyString_Check(value))
            gnome_keyring_attribute_list_append_string(attrlist, name,
                                                       PyString_AsString(value));
        else {
            PyErr_SetString(PyExc_TypeError, "dict values must be strings, ints or longs,"
                            " when converting attribute list parameter");
            gnome_keyring_attribute_list_free(attrlist);
            return NULL;
        }
    }
    return attrlist;
}

static PyObject *
pygnome_keyring_attribute_list_as_pyobject(GnomeKeyringAttributeList *attrlist)
{
    PyObject *py_attrlist;
    int i, len = ((GArray *) attrlist)->len;

    py_attrlist = PyDict_New();
    for (i = 0; i < len; ++i) {
        GnomeKeyringAttribute *attr;
        PyObject *val = NULL;

        attr = &gnome_keyring_attribute_list_index(attrlist, i);

        switch (attr->type)
        {
        case GNOME_KEYRING_ATTRIBUTE_TYPE_STRING:
            val = PyString_FromString(attr->value.string);
            break;
	case GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32:
            val = PyLong_FromUnsignedLong(attr->value.integer);
            break;
        default:
            Py_DECREF(py_attrlist);
            PyErr_SetString(PyExc_AssertionError, "invalided GnomeKeyringAttributeType"
                            " (congratulations, you found bug in bindings or C library)");
            return NULL;
        }

        if (PyDict_SetItemString(py_attrlist, attr->name, val)) {
            Py_DECREF(py_attrlist);
            return NULL;
        }
    }

    return py_attrlist;
}


%%
ignore-glob
 *_get_type
%%
ignore
 gnome_keyring_attribute_list_free
 gnome_keyring_attribute_list_copy
 gnome_keyring_free_password
 gnome_keyring_found_free
 gnome_keyring_found_list_free
 gnome_keyring_info_free
 gnome_keyring_info_copy
 gnome_keyring_item_info_free
 gnome_keyring_item_info_copy
 gnome_keyring_application_ref_copy
 gnome_keyring_application_ref_free
 gnome_keyring_access_control_copy
 gnome_keyring_access_control_free
 gnome_keyring_acl_free
 gnome_keyring_network_password_free
 gnome_keyring_network_password_list_free
 gnome_keyring_find_itemsv
 gnome_keyring_find_itemsv_sync

%%
override gnome_keyring_get_default_keyring_sync noargs
static PyObject *
_wrap_gnome_keyring_get_default_keyring_sync(PyObject *self)
{
    gint ret;
    char *keyring;
    
    pyg_begin_allow_threads;
    ret = gnome_keyring_get_default_keyring_sync(&keyring);
    pyg_end_allow_threads;
    if (pygnomekeyring_result_check(ret))
        return NULL;
    if (keyring)
        return PyString_FromString(keyring);
    else {
        Py_INCREF(Py_None);
        return Py_None;
    }
}

%%
override gnome_keyring_list_keyring_names_sync noargs
static PyObject *
_wrap_gnome_keyring_list_keyring_names_sync(PyObject *self)
{
    gint ret;
    GList *keyrings, *l;
    PyObject *py_keyrings = NULL;

    pyg_begin_allow_threads;
    ret = gnome_keyring_list_keyring_names_sync(&keyrings);
    pyg_end_allow_threads;

    py_keyrings = PyList_New(0);
    for (l = keyrings; l; l = l->next) {
        PyObject *item = PyString_FromString((char *) l->data);
        PyList_Append(py_keyrings, item);
        Py_DECREF(item);
        g_free(l->data);
    }
    g_list_free(keyrings);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return py_keyrings;
}
%%
override gnome_keyring_item_get_attributes_sync kwargs
static PyObject *
_wrap_gnome_keyring_item_get_attributes_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "id", NULL };
    char *keyring;
    unsigned long id;
    gint ret;
    GnomeKeyringAttributeList *attrlist = NULL;
    PyObject *py_attrlist;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zk:item_get_attributes_sync", kwlist, &keyring, &id))
        return NULL;

    pyg_begin_allow_threads;
    ret = gnome_keyring_item_get_attributes_sync(keyring, id, &attrlist);
    pyg_end_allow_threads;

    if (pygnomekeyring_result_check(ret))
        return NULL;

    py_attrlist = pygnome_keyring_attribute_list_as_pyobject(attrlist);
    if (!py_attrlist)
        return NULL;
    return py_attrlist;
}

%%
override gnome_keyring_set_network_password_sync kwargs
static PyObject *
_wrap_gnome_keyring_set_network_password_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "user", "domain", "server", "object",
                              "protocol", "authtype", "port", "password", NULL };
    char *keyring = NULL;
    char *user = NULL;
    char *domain = NULL;
    char *server = NULL;
    char *object = NULL;
    char *protocol = NULL;
    char *authtype = NULL;
    char *password = NULL;
    unsigned long port = 0;
    gint ret;
    guint32 item_id;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"|zzzzzzzks:set_network_password_sync", kwlist,
                                     &keyring, &user, &domain, &server, &object, &protocol,
                                     &authtype, &port, &password))
        return NULL;

    if (!password) {
        PyErr_SetString(PyExc_TypeError, "set_network_password_sync() argument 'password' must be supplied");
        return NULL;
    }

    pyg_begin_allow_threads;
    ret = gnome_keyring_set_network_password_sync(keyring, user, domain, server, object,
                                                  protocol, authtype, port, password, &item_id);
    pyg_end_allow_threads;

    if (pygnomekeyring_result_check(ret))
        return NULL;
    return PyLong_FromUnsignedLong(item_id);
}

%%
override gnome_keyring_find_network_password_sync kwargs
static PyObject *
_wrap_gnome_keyring_find_network_password_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "user", "domain", "server", "object", "protocol", "authtype", "port", NULL };
    char *user = NULL;
    char *domain = NULL;
    char *server = NULL;
    char *object = NULL;
    char *protocol = NULL;
    char *authtype = NULL;
    unsigned long port = 0l;
    gint ret;
    GList *result = NULL, *l;
    PyObject *py_result;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"|zzzzzzk:find_network_password_sync", kwlist,
                                     &user, &domain, &server, &object, &protocol, &authtype, &port))
        return NULL;

    pyg_begin_allow_threads;
    ret = gnome_keyring_find_network_password_sync(user, domain, server, object,
                                                   protocol, authtype, port, &result);
    pyg_end_allow_threads;

    py_result = PyList_New(0);
    for (l = result; l; l = l->next) {
        GnomeKeyringNetworkPasswordData *data = l->data;
        PyObject *dict = PyDict_New();

        PyList_Append(py_result, dict);
        Py_DECREF(dict);

#define copy_string_attr(name)                                  \
        if (data->name) {                                       \
            PyObject *item = PyString_FromString(data->name);   \
            PyDict_SetItemString(dict, #name, item);            \
            Py_DECREF(item);                                    \
        }
#define copy_guint32_attr(name)                                         \
        if (data->name) {                                               \
            PyObject *item = PyLong_FromUnsignedLong(data->name);       \
            PyDict_SetItemString(dict, #name, item);                    \
            Py_DECREF(item);                                            \
        }
        
        copy_string_attr(keyring);
        copy_guint32_attr(item_id);
        copy_string_attr(protocol);
        copy_string_attr(server);
        copy_string_attr(object);
        copy_string_attr(authtype);
        copy_guint32_attr(port);
        copy_string_attr(user);
        copy_string_attr(domain);
        copy_string_attr(password);

#undef copy_guint32_attr
#undef copy_string_attr

    }
    gnome_keyring_network_password_list_free(result);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return py_result;
}

%%
override gnome_keyring_get_info_sync kwargs
static PyObject *
_wrap_gnome_keyring_get_info_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", NULL };
    char *keyring;
    gint ret;
    GnomeKeyringInfo *info = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z:get_info_sync", kwlist, &keyring))
        return NULL;

    pyg_begin_allow_threads;
    ret = gnome_keyring_get_info_sync(keyring, &info);
    pyg_end_allow_threads;

    /* pyg_boxed_new handles NULL checking */
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return pyg_boxed_new(GNOME_KEYRING_TYPE_INFO, info, FALSE, TRUE);
}
%%
override gnome_keyring_item_create_sync kwargs
static PyObject *
_wrap_gnome_keyring_item_create_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "type", "display_name", "attributes", "secret", "update_if_exists", NULL };
    PyObject * py_attributes;
    PyObject *py_type = NULL;
    char *keyring, *display_name, *secret;
    int update_if_exists;
    GnomeKeyringAttributeList * attributes;
    GnomeKeyringItemType type;
    gint ret;
    guint32 item_id = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zOsOsi:item_create_sync", kwlist, &keyring, &py_type, &display_name, &py_attributes, &secret, &update_if_exists))
        return NULL;
    if (pyg_enum_get_value(G_TYPE_NONE, py_type, (gint *)&type))
        return NULL;
    attributes = pygnome_keyring_attribute_list_from_pyobject(py_attributes);
    if (!attributes)
        return NULL;
    pyg_begin_allow_threads;
    ret = gnome_keyring_item_create_sync(keyring, type, display_name, attributes, secret, update_if_exists, &item_id);
    pyg_end_allow_threads;
    gnome_keyring_attribute_list_free(attributes);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return PyLong_FromUnsignedLong(item_id);
}

%%
override gnome_keyring_item_get_info_sync kwargs
static PyObject *
_wrap_gnome_keyring_item_get_info_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "id", NULL };
    char *keyring;
    unsigned long id;
    gint ret;
    GnomeKeyringItemInfo *info = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zk:item_get_info_sync", kwlist, &keyring, &id))
        return NULL;
    pyg_begin_allow_threads;
    ret = gnome_keyring_item_get_info_sync(keyring, id, &info);
    pyg_end_allow_threads;
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return pyg_boxed_new(GNOME_KEYRING_TYPE_ITEM_INFO, info, FALSE, TRUE);
}

%%
override gnome_keyring_item_set_acl_sync kwargs

static PyObject *
_wrap_gnome_keyring_item_set_acl_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "id", "acl", NULL };
    char *keyring;
    unsigned long id;
    gint ret, i, len;
    PyObject *pyacl;
    GList *acl = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zkO!:item_set_acl_sync", kwlist, &keyring, &id,
                                     &PyList_Type, &pyacl))
        return NULL;

    len = PyList_Size(pyacl);
    for (i = 0; i < len; ++i) {
        PyObject *item = PyList_GET_ITEM(pyacl, i);
        if (pyg_boxed_check(item, GNOME_KEYRING_TYPE_ACCESS_CONTROL))
            acl = g_list_prepend(acl, pyg_boxed_get(item, GnomeKeyringAccessControl));
        else {
            PyErr_SetString(PyExc_TypeError, "acl elements must be of type gnomekeyring.AccessControl");
            g_list_free(acl);
            return NULL;
        }
    }
    acl = g_list_reverse(acl);

    pyg_begin_allow_threads;
    ret = gnome_keyring_item_set_acl_sync(keyring, id, acl);
    pyg_end_allow_threads;

    g_list_free(acl);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    Py_INCREF(Py_None);
    return Py_None;
}

%%
override gnome_keyring_item_get_acl_sync kwargs
static PyObject *
_wrap_gnome_keyring_item_get_acl_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "id", NULL };
    char *keyring;
    unsigned long id;
    gint ret;
    GList *acl, *l;
    PyObject *pyacl;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zk:item_get_acl_sync", kwlist, &keyring, &id))
        return NULL;
    pyg_begin_allow_threads;
    ret = gnome_keyring_item_get_acl_sync(keyring, id, &acl);
    pyg_end_allow_threads;

    pyacl = PyList_New(0);
    for (l = acl; l; l = l->next) {
          /* steals ownership of the acl from the list */
        PyObject *item = pyg_boxed_new(GNOME_KEYRING_TYPE_ACCESS_CONTROL, l->data, FALSE, TRUE);
        PyList_Append(pyacl, item);
        Py_DECREF(item);
    }
    g_list_free(acl);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return pyacl;
}

%%
override gnome_keyring_list_item_ids_sync kwargs
static PyObject *
_wrap_gnome_keyring_list_item_ids_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", NULL };
    char *keyring;
    gint ret;
    GList *ids = NULL, *l;
    PyObject *py_ids;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z:list_item_ids_sync", kwlist, &keyring))
        return NULL;
    pyg_begin_allow_threads;
    ret = gnome_keyring_list_item_ids_sync(keyring, &ids);
    pyg_end_allow_threads;

    py_ids = PyList_New(0);
    for (l = ids; l; l = l->next)
    {
        PyObject *item;
        item = PyLong_FromUnsignedLong(GPOINTER_TO_UINT(l->data));
        PyList_Append(py_ids, item);
        Py_DECREF(item);
    }
    g_list_free(ids);
    if (pygnomekeyring_result_check(ret))
        return NULL;
    return py_ids;
}

%%
override gnome_keyring_find_items_sync kwargs
static PyObject *
_wrap_gnome_keyring_find_items_sync(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "type", "attributes", NULL };
    PyObject *py_type = NULL;
    GnomeKeyringAttributeList * attributes;
    GnomeKeyringItemType type;
    gint ret;
    PyObject * py_attributes;
    GList *found = NULL, *l;
    PyObject *py_found;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"OO:find_items_sync", kwlist, &py_type, &py_attributes))
        return NULL;
    if (pyg_enum_get_value(G_TYPE_NONE, py_type, (gint *)&type))
        return NULL;
    attributes = pygnome_keyring_attribute_list_from_pyobject(py_attributes);
    if (!attributes)
        return NULL;
    pyg_begin_allow_threads;
    ret = gnome_keyring_find_items_sync(type, attributes, &found);
    pyg_end_allow_threads;
    gnome_keyring_attribute_list_free(attributes);

    py_found = PyList_New(0);
    for (l = found; l; l = l->next)
    {
        PyObject *item = pyg_boxed_new(GNOME_KEYRING_TYPE_FOUND, l->data, FALSE, TRUE);
        PyList_Append(py_found, item);
        Py_DECREF(item);
    }
    g_list_free(found);

    if (pygnomekeyring_result_check(ret))
        return NULL;
    return py_found;
}

%%
override gnome_keyring_item_create kwargs

static void
_wrap_GnomeKeyringOperationGetIntCallback(GnomeKeyringResult result,
                                          guint32            val,
                                          gpointer           data)
{
    PyGtkCustomNotify *cb_data = data;
    PyObject *ret;
    PyGILState_STATE state;

    state = pyg_gil_state_ensure();

    if (cb_data->data)
        
        ret = PyEval_CallFunction(cb_data->func, "OIO", pygnomekeyring_result_to_exception(result),
                                  val, cb_data->data);
    else
        ret = PyEval_CallFunction(cb_data->func, "OI", pygnomekeyring_result_to_exception(result),
                                  val);
    Py_XDECREF(ret);
    if (PyErr_Occurred())
        PyErr_Print();
    pyg_gil_state_release(state);
}

static PyObject *
_wrap_gnome_keyring_item_create(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "type", "display_name", "attributes",
                              "secret", "update_if_exists", "callback", "user_data", NULL };
    char *keyring, *display_name, *secret;
    int type, update_if_exists;
    PyObject *py_attributes;
    GnomeKeyringAttributeList * attributes;
    PyObject *func, *data = NULL;
    PyGtkCustomNotify *cb_data;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zisOsiO|O:item_create", kwlist,
                                     &keyring, &type, &display_name, &py_attributes,
                                     &secret, &update_if_exists, &func, &data))
        return NULL;

    if (!PyCallable_Check(func)) {
        PyErr_SetString(PyExc_TypeError, "callback function not callable");
        return NULL;
    }
    attributes = pygnome_keyring_attribute_list_from_pyobject(py_attributes);
    cb_data = g_new(PyGtkCustomNotify, 1);
    cb_data->func = func; Py_INCREF(func);
    cb_data->data = data; Py_XINCREF(data);

    gnome_keyring_item_create(keyring, type, display_name, attributes, secret, update_if_exists,
                              _wrap_GnomeKeyringOperationGetIntCallback, cb_data,
                              pygtk_custom_destroy_notify);
    
    gnome_keyring_attribute_list_free(attributes);
    Py_INCREF(Py_None);
    return Py_None;
}

%%
override gnome_keyring_item_get_info kwargs

static void
_wrap_GnomeKeyringOperationGetItemInfoCallback(GnomeKeyringResult    result,
                                               GnomeKeyringItemInfo *info,
                                               gpointer              data)
{
    PyGtkCustomNotify *cb_data = data;
    PyObject *py_info;
    PyObject *ret;
    PyGILState_STATE state;

    state = pyg_gil_state_ensure();
    py_info = pyg_boxed_new(GNOME_KEYRING_TYPE_ITEM_INFO, info, TRUE, TRUE);
    if (cb_data->data)
        ret = PyEval_CallFunction(cb_data->func, "NNO", pygnomekeyring_result_to_exception(result),
                                  py_info, cb_data->data);
    else
        ret = PyEval_CallFunction(cb_data->func, "NN", pygnomekeyring_result_to_exception(result),
                                  py_info);
    Py_XDECREF(ret);
    if (PyErr_Occurred())
        PyErr_Print();
    pyg_gil_state_release(state);
}

static PyObject *
_wrap_gnome_keyring_item_get_info(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "keyring", "id", "callback", "user_data", NULL };
    char *keyring;
    unsigned long id;
    PyObject *func, *data = NULL;
    PyGtkCustomNotify *cb_data;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"zkO|O:item_get_info", kwlist,
                                     &keyring, &id, &func, &data))
        return NULL;

    if (!PyCallable_Check(func)) {
        PyErr_SetString(PyExc_TypeError, "callback function not callable");
        return NULL;
    }
    cb_data = g_new(PyGtkCustomNotify, 1);
    cb_data->func = func; Py_INCREF(func);
    cb_data->data = data; Py_XINCREF(data);

    gnome_keyring_item_get_info(keyring, id,
                              _wrap_GnomeKeyringOperationGetItemInfoCallback, cb_data,
                              pygtk_custom_destroy_notify);

    Py_INCREF(Py_None);
    return Py_None;
}

%%
override gnome_keyring_find_items kwargs

typedef struct _GetItemsData
{
    GnomeKeyringAttributeList *attributes;
    PyObject *func;
    PyObject *data;
} GetItemsData;

void
GetItemsData__free (GetItemsData *data)
{
    gnome_keyring_attribute_list_free(data->attributes);
    Py_XDECREF(data->func);
    Py_XDECREF(data->data);
    g_free(data);
}

static void
_wrap_GnomeKeyringOperationGetListCallback(GnomeKeyringResult result,
                                           GList             *found,
                                           gpointer           data)
{
    GetItemsData *cb_data = data;
    PyObject *py_found;
    PyObject *ret;
    PyGILState_STATE state;
    GList *l;

    state = pyg_gil_state_ensure();

    py_found = PyList_New(0);
    for (l = found; l; l = l->next)
    {
        PyObject *item = pyg_boxed_new(GNOME_KEYRING_TYPE_FOUND, l->data, TRUE, TRUE);
        PyList_Append(py_found, item);
        Py_DECREF(item);
    }
    if (cb_data->data)
        ret = PyEval_CallFunction(cb_data->func, "NNO", pygnomekeyring_result_to_exception(result),
                                  py_found, cb_data->data);
    else
        ret = PyEval_CallFunction(cb_data->func, "NN", pygnomekeyring_result_to_exception(result),
                                  py_found);
    Py_XDECREF(ret);
    if (PyErr_Occurred())
        PyErr_Print();
    pyg_gil_state_release(state);
}

static PyObject *
_wrap_gnome_keyring_find_items(PyObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "type", "attributes", "callback", "user_data", NULL };

    PyObject *py_type;
    GnomeKeyringItemType type;

    PyObject *py_attributes;
    GnomeKeyringAttributeList *attributes;

    PyObject *func, *data = NULL;
    GetItemsData *cb_data;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"OOO|O:find_items", kwlist,
                                     &py_type, &py_attributes, &func, &data))
        return NULL;

    if (pyg_enum_get_value(G_TYPE_NONE, py_type, (gint *)&type))
        return NULL;

    attributes = pygnome_keyring_attribute_list_from_pyobject(py_attributes);
    if (!attributes)
        return NULL;

    if (!PyCallable_Check(func)) {
        PyErr_SetString(PyExc_TypeError, "callback function not callable");
        return NULL;
    }
    cb_data = g_new(GetItemsData, 1);
    cb_data->func = func; Py_INCREF(func);
    cb_data->data = data; Py_XINCREF(data);
    cb_data->attributes = attributes;

    gnome_keyring_find_items(type, attributes,
                             _wrap_GnomeKeyringOperationGetListCallback,
                             cb_data, (GDestroyNotify) GetItemsData__free);

    Py_INCREF(Py_None);
    return Py_None;
}

