Blame _dbus_bindings/message-get-args.c

Packit 130fc8
/* D-Bus Message unserialization. This contains all the logic to map from
Packit 130fc8
 * D-Bus types to Python objects.
Packit 130fc8
 *
Packit 130fc8
 * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
Packit 130fc8
 *
Packit 130fc8
 * Permission is hereby granted, free of charge, to any person
Packit 130fc8
 * obtaining a copy of this software and associated documentation
Packit 130fc8
 * files (the "Software"), to deal in the Software without
Packit 130fc8
 * restriction, including without limitation the rights to use, copy,
Packit 130fc8
 * modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 130fc8
 * of the Software, and to permit persons to whom the Software is
Packit 130fc8
 * furnished to do so, subject to the following conditions:
Packit 130fc8
 *
Packit 130fc8
 * The above copyright notice and this permission notice shall be
Packit 130fc8
 * included in all copies or substantial portions of the Software.
Packit 130fc8
 *
Packit 130fc8
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 130fc8
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 130fc8
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 130fc8
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 130fc8
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Packit 130fc8
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Packit 130fc8
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Packit 130fc8
 * DEALINGS IN THE SOFTWARE.
Packit 130fc8
 */
Packit 130fc8
Packit 130fc8
#include "dbus_bindings-internal.h"
Packit 130fc8
Packit 130fc8
#define DBG_IS_TOO_VERBOSE
Packit 130fc8
#include "compat-internal.h"
Packit 130fc8
#include "types-internal.h"
Packit 130fc8
#include "message-internal.h"
Packit 130fc8
Packit 130fc8
char dbus_py_Message_get_args_list__doc__[] = (
Packit 130fc8
"get_args_list(**kwargs) -> list\n\n"
Packit 130fc8
"Return the message's arguments. Keyword arguments control the translation\n"
Packit 130fc8
"of D-Bus types to Python:\n"
Packit 130fc8
"\n"
Packit 130fc8
":Keywords:\n"
Packit 130fc8
"   `byte_arrays` : bool\n"
Packit 130fc8
"       If true, convert arrays of byte (signature 'ay') into dbus.ByteArray,\n"
Packit 130fc8
"       a str subclass. In practice, this is usually what you want, but\n"
Packit 130fc8
"       it's off by default for consistency.\n"
Packit 130fc8
"\n"
Packit 130fc8
"       If false (default), convert them into a dbus.Array of Bytes.\n"
Packit 130fc8
#ifndef PY3
Packit 130fc8
"   `utf8_strings` : bool\n"
Packit 130fc8
"       If true, return D-Bus strings as Python 8-bit strings (of UTF-8).\n"
Packit 130fc8
"       If false (default), return D-Bus strings as Python unicode objects.\n"
Packit 130fc8
#endif
Packit 130fc8
"\n"
Packit 130fc8
"Most of the type mappings should be fairly obvious:\n"
Packit 130fc8
"\n"
Packit 130fc8
"===============  ===================================================\n"
Packit 130fc8
"D-Bus            Python\n"
Packit 130fc8
"===============  ===================================================\n"
Packit 130fc8
"byte (y)         dbus.Byte (int subclass)\n"
Packit 130fc8
"bool (b)         dbus.Boolean (int subclass)\n"
Packit 130fc8
"Signature (g)    dbus.Signature (str subclass)\n"
Packit 130fc8
"intNN, uintNN    dbus.IntNN, dbus.UIntNN (int or long subclasses)\n"
Packit 130fc8
"double (d)       dbus.Double\n"
Packit 130fc8
"string (s)       dbus.String (unicode subclass)\n"
Packit 130fc8
"                 (or dbus.UTF8String, str subclass, if utf8_strings set)\n"
Packit 130fc8
"Object path (o)  dbus.ObjectPath (str subclass)\n"
Packit 130fc8
"dict (a{...})    dbus.Dictionary\n"
Packit 130fc8
"array (a...)     dbus.Array (list subclass) containing appropriate types\n"
Packit 130fc8
"byte array (ay)  dbus.ByteArray (str subclass) if byte_arrays set; or\n"
Packit 130fc8
"                 list of Byte\n"
Packit 130fc8
"struct ((...))   dbus.Struct (tuple subclass) of appropriate types\n"
Packit 130fc8
"variant (v)      contained type, but with variant_level > 0\n"
Packit 130fc8
"===============  ===================================================\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
typedef struct {
Packit 130fc8
    int byte_arrays;
Packit 130fc8
#ifndef PY3
Packit 130fc8
    int utf8_strings;
Packit 130fc8
#endif
Packit 130fc8
} Message_get_args_options;
Packit 130fc8
Packit 130fc8
static PyObject *_message_iter_get_pyobject(DBusMessageIter *iter,
Packit 130fc8
                                            Message_get_args_options *opts,
Packit 130fc8
                                            long extra_variants);
Packit 130fc8
Packit 130fc8
/* Append all the items iterated over to the given Python list object.
Packit 130fc8
   * Return 0 on success/-1 with exception on failure. */
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list,
Packit 130fc8
                                 Message_get_args_options *opts)
Packit 130fc8
{
Packit 130fc8
    int ret, type;
Packit 130fc8
    while ((type = dbus_message_iter_get_arg_type(iter))
Packit 130fc8
            != DBUS_TYPE_INVALID) {
Packit 130fc8
        PyObject *item;
Packit 130fc8
        DBG("type == %d '%c'", type, type);
Packit 130fc8
Packit 130fc8
        item = _message_iter_get_pyobject(iter, opts, 0);
Packit 130fc8
        if (!item) return -1;
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
        fprintf(stderr, "DBG/%ld: appending to list: %p == ", (long)getpid(), item);
Packit 130fc8
        PyObject_Print(item, stderr, 0);
Packit 130fc8
        fprintf(stderr, " of type %p\n", Py_TYPE(item));
Packit 130fc8
#endif
Packit 130fc8
        ret = PyList_Append(list, item);
Packit 130fc8
        Py_CLEAR(item);
Packit 130fc8
        if (ret < 0) return -1;
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
        fprintf(stderr, "DBG/%ld: list now contains: ", (long)getpid());
Packit 130fc8
        PyObject_Print(list, stderr, 0);
Packit 130fc8
        fprintf(stderr, "\n");
Packit 130fc8
#endif
Packit 130fc8
        dbus_message_iter_next(iter);
Packit 130fc8
    }
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static inline PyObject *
Packit 130fc8
_message_iter_get_dict(DBusMessageIter *iter,
Packit 130fc8
                       Message_get_args_options *opts,
Packit 130fc8
                       PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    DBusMessageIter entries;
Packit 130fc8
    char *sig_str = dbus_message_iter_get_signature(iter);
Packit 130fc8
    PyObject *sig;
Packit 130fc8
    PyObject *ret;
Packit 130fc8
    int status;
Packit 130fc8
Packit 130fc8
    if (!sig_str) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
Packit 130fc8
                                "(s#)", sig_str+2,
Packit 130fc8
                                (Py_ssize_t)strlen(sig_str)-3);
Packit 130fc8
    dbus_free(sig_str);
Packit 130fc8
    if (!sig) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig);
Packit 130fc8
    Py_CLEAR(sig);
Packit 130fc8
    if (status < 0) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs);
Packit 130fc8
    if (!ret) {
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    dbus_message_iter_recurse(iter, &entries);
Packit 130fc8
    while (dbus_message_iter_get_arg_type(&entries) == DBUS_TYPE_DICT_ENTRY) {
Packit 130fc8
        PyObject *key = NULL;
Packit 130fc8
        PyObject *value = NULL;
Packit 130fc8
        DBusMessageIter kv;
Packit 130fc8
Packit 130fc8
        DBG("%s", "dict entry...");
Packit 130fc8
Packit 130fc8
        dbus_message_iter_recurse(&entries, &kv;;
Packit 130fc8
Packit 130fc8
        key = _message_iter_get_pyobject(&kv, opts, 0);
Packit 130fc8
        if (!key) {
Packit 130fc8
            Py_CLEAR(ret);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        dbus_message_iter_next(&kv;;
Packit 130fc8
Packit 130fc8
        value = _message_iter_get_pyobject(&kv, opts, 0);
Packit 130fc8
        if (!value) {
Packit 130fc8
            Py_CLEAR(key);
Packit 130fc8
            Py_CLEAR(ret);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        status = PyDict_SetItem(ret, key, value);
Packit 130fc8
        Py_CLEAR(key);
Packit 130fc8
        Py_CLEAR(value);
Packit 130fc8
Packit 130fc8
        if (status < 0) {
Packit 130fc8
            Py_CLEAR(ret);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        dbus_message_iter_next(&entries);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* Returns a new reference. */
Packit 130fc8
static PyObject *
Packit 130fc8
_message_iter_get_pyobject(DBusMessageIter *iter,
Packit 130fc8
                           Message_get_args_options *opts,
Packit 130fc8
                           long variant_level)
Packit 130fc8
{
Packit 130fc8
    DBusBasicValue u;
Packit 130fc8
    int type = dbus_message_iter_get_arg_type(iter);
Packit 130fc8
    PyObject *args = NULL;
Packit 130fc8
    PyObject *kwargs = NULL;
Packit 130fc8
    PyObject *ret = NULL;
Packit 130fc8
Packit 130fc8
    /* If the variant-level is >0, prepare a dict for the kwargs.
Packit 130fc8
     * For variant wrappers optimize slightly by skipping this.
Packit 130fc8
     */
Packit 130fc8
    if (variant_level > 0 && type != DBUS_TYPE_VARIANT) {
Packit 130fc8
        PyObject *variant_level_int;
Packit 130fc8
Packit 130fc8
        variant_level_int = NATIVEINT_FROMLONG(variant_level);
Packit 130fc8
        if (!variant_level_int) {
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        kwargs = PyDict_New();
Packit 130fc8
        if (!kwargs) {
Packit 130fc8
            Py_CLEAR(variant_level_int);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        if (PyDict_SetItem(kwargs, dbus_py_variant_level_const,
Packit 130fc8
                           variant_level_int) < 0) {
Packit 130fc8
            Py_CLEAR(variant_level_int);
Packit 130fc8
            Py_CLEAR(kwargs);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        Py_CLEAR(variant_level_int);
Packit 130fc8
    }
Packit 130fc8
    /* From here down you need to break from the switch to exit, so the
Packit 130fc8
     * dict is freed if necessary
Packit 130fc8
     */
Packit 130fc8
Packit 130fc8
    switch (type) {
Packit 130fc8
        PyObject *unicode;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_STRING:
Packit 130fc8
            DBG("%s", "found a string");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.str);
Packit 130fc8
#ifndef PY3
Packit 130fc8
            if (opts->utf8_strings) {
Packit 130fc8
                args = Py_BuildValue("(s)", u.str);
Packit 130fc8
                if (!args) break;
Packit 130fc8
                ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type,
Packit 130fc8
                                    args, kwargs);
Packit 130fc8
            }
Packit 130fc8
            else {
Packit 130fc8
#endif
Packit 130fc8
                unicode = PyUnicode_DecodeUTF8(u.str, strlen(u.str), NULL);
Packit 130fc8
                if (!unicode) {
Packit 130fc8
                    break;
Packit 130fc8
                }
Packit 130fc8
                args = Py_BuildValue("(N)", unicode);
Packit 130fc8
                if (!args) {
Packit 130fc8
                    break;
Packit 130fc8
                }
Packit 130fc8
                ret = PyObject_Call((PyObject *)&DBusPyString_Type,
Packit 130fc8
                                    args, kwargs);
Packit 130fc8
#ifndef PY3
Packit 130fc8
            }
Packit 130fc8
#endif
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_SIGNATURE:
Packit 130fc8
            DBG("%s", "found a signature");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.str);
Packit 130fc8
            args = Py_BuildValue("(s)", u.str);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_OBJECT_PATH:
Packit 130fc8
            DBG("%s", "found an object path");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.str);
Packit 130fc8
            args = Py_BuildValue("(s)", u.str);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_DOUBLE:
Packit 130fc8
            DBG("%s", "found a double");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.dbl);
Packit 130fc8
            args = Py_BuildValue("(f)", u.dbl);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
#ifdef WITH_DBUS_FLOAT32
Packit 130fc8
        case DBUS_TYPE_FLOAT:
Packit 130fc8
            DBG("%s", "found a float");
Packit 130fc8
            /* FIXME: DBusBasicValue will need to grow a float member if
Packit 130fc8
             * float32 becomes supported */
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.f);
Packit 130fc8
            args = Py_BuildValue("(f)", (double)u.f);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_INT16:
Packit 130fc8
            DBG("%s", "found an int16");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.i16);
Packit 130fc8
            args = Py_BuildValue("(i)", (int)u.i16);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_UINT16:
Packit 130fc8
            DBG("%s", "found a uint16");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.u16);
Packit 130fc8
            args = Py_BuildValue("(i)", (int)u.u16);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_INT32:
Packit 130fc8
            DBG("%s", "found an int32");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.i32);
Packit 130fc8
            args = Py_BuildValue("(l)", (long)u.i32);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_UINT32:
Packit 130fc8
            DBG("%s", "found a uint32");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.u32);
Packit 130fc8
            args = Py_BuildValue("(k)", (unsigned long)u.u32);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
#ifdef DBUS_TYPE_UNIX_FD
Packit 130fc8
        case DBUS_TYPE_UNIX_FD:
Packit 130fc8
            DBG("%s", "found an unix fd");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.fd);
Packit 130fc8
            args = Py_BuildValue("(i)", u.fd);
Packit 130fc8
            if (args) {
Packit 130fc8
                ret = PyObject_Call((PyObject *)&DBusPyUnixFd_Type, args,
Packit 130fc8
                                    kwargs);
Packit 130fc8
            }
Packit 130fc8
            if (u.fd >= 0) {
Packit 130fc8
                close(u.fd);
Packit 130fc8
            }
Packit 130fc8
            break;
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
Packit 130fc8
        case DBUS_TYPE_INT64:
Packit 130fc8
            DBG("%s", "found an int64");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.i64);
Packit 130fc8
            args = Py_BuildValue("(L)", (PY_LONG_LONG)u.i64);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_UINT64:
Packit 130fc8
            DBG("%s", "found a uint64");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.u64);
Packit 130fc8
            args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)u.u64);
Packit 130fc8
            if (!args) break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
#else
Packit 130fc8
        case DBUS_TYPE_INT64:
Packit 130fc8
        case DBUS_TYPE_UINT64:
Packit 130fc8
            PyErr_SetString(PyExc_NotImplementedError,
Packit 130fc8
                            "64-bit integer types are not supported on "
Packit 130fc8
                            "this platform");
Packit 130fc8
            break;
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_BYTE:
Packit 130fc8
            DBG("%s", "found a byte");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.byt);
Packit 130fc8
            args = Py_BuildValue("(l)", (long)u.byt);
Packit 130fc8
            if (!args)
Packit 130fc8
                break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_BOOLEAN:
Packit 130fc8
            DBG("%s", "found a bool");
Packit 130fc8
            dbus_message_iter_get_basic(iter, &u.bool_val);
Packit 130fc8
            args = Py_BuildValue("(l)", (long)u.bool_val);
Packit 130fc8
            if (!args)
Packit 130fc8
                break;
Packit 130fc8
            ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs);
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_ARRAY:
Packit 130fc8
            DBG("%s", "found an array...");
Packit 130fc8
            /* Dicts are arrays of DBUS_TYPE_DICT_ENTRY on the wire.
Packit 130fc8
            Also, we special-case arrays of DBUS_TYPE_BYTE sometimes. */
Packit 130fc8
            type = dbus_message_iter_get_element_type(iter);
Packit 130fc8
            if (type == DBUS_TYPE_DICT_ENTRY) {
Packit 130fc8
                DBG("%s", "no, actually it's a dict...");
Packit 130fc8
                if (!kwargs) {
Packit 130fc8
                    kwargs = PyDict_New();
Packit 130fc8
                    if (!kwargs) break;
Packit 130fc8
                }
Packit 130fc8
                ret = _message_iter_get_dict(iter, opts, kwargs);
Packit 130fc8
            }
Packit 130fc8
            else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) {
Packit 130fc8
                DBusMessageIter sub;
Packit 130fc8
                int n;
Packit 130fc8
Packit 130fc8
                DBG("%s", "actually, a byte array...");
Packit 130fc8
                dbus_message_iter_recurse(iter, &sub);
Packit 130fc8
                dbus_message_iter_get_fixed_array(&sub,
Packit 130fc8
                                                  (const unsigned char **)&u.str,
Packit 130fc8
                                                  &n);
Packit 130fc8
                if (n == 0 && u.str == NULL) {
Packit 130fc8
                    /* fd.o #21831: s# turns (NULL, 0) into None, but
Packit 130fc8
                     * dbus_message_iter_get_fixed_array produces (NULL, 0)
Packit 130fc8
                     * for an empty byte-blob... */
Packit 130fc8
                    u.str = "";
Packit 130fc8
                }
Packit 130fc8
#ifdef PY3
Packit 130fc8
                args = Py_BuildValue("(y#)", u.str, (Py_ssize_t)n);
Packit 130fc8
#else
Packit 130fc8
                args = Py_BuildValue("(s#)", u.str, (Py_ssize_t)n);
Packit 130fc8
#endif
Packit 130fc8
                if (!args) break;
Packit 130fc8
                ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type,
Packit 130fc8
                                    args, kwargs);
Packit 130fc8
            }
Packit 130fc8
            else {
Packit 130fc8
                DBusMessageIter sub;
Packit 130fc8
                char *sig;
Packit 130fc8
                PyObject *sig_obj;
Packit 130fc8
                int status;
Packit 130fc8
Packit 130fc8
                DBG("%s", "a normal array...");
Packit 130fc8
                if (!kwargs) {
Packit 130fc8
                    kwargs = PyDict_New();
Packit 130fc8
                    if (!kwargs) break;
Packit 130fc8
                }
Packit 130fc8
                dbus_message_iter_recurse(iter, &sub);
Packit 130fc8
                sig = dbus_message_iter_get_signature(&sub);
Packit 130fc8
                if (!sig) break;
Packit 130fc8
                sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
Packit 130fc8
                                                "(s)", sig);
Packit 130fc8
                dbus_free(sig);
Packit 130fc8
                if (!sig_obj) break;
Packit 130fc8
                status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj);
Packit 130fc8
                Py_CLEAR(sig_obj);
Packit 130fc8
                if (status < 0) break;
Packit 130fc8
                ret = PyObject_Call((PyObject *)&DBusPyArray_Type,
Packit 130fc8
                                    dbus_py_empty_tuple, kwargs);
Packit 130fc8
                if (!ret) break;
Packit 130fc8
                if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) {
Packit 130fc8
                    Py_CLEAR(ret);
Packit 130fc8
                }
Packit 130fc8
            }
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_STRUCT:
Packit 130fc8
            {
Packit 130fc8
                DBusMessageIter sub;
Packit 130fc8
                PyObject *list = PyList_New(0);
Packit 130fc8
                PyObject *tuple;
Packit 130fc8
Packit 130fc8
                DBG("%s", "found a struct...");
Packit 130fc8
                if (!list) break;
Packit 130fc8
                dbus_message_iter_recurse(iter, &sub);
Packit 130fc8
                if (_message_iter_append_all_to_list(&sub, list, opts) < 0) {
Packit 130fc8
                    Py_CLEAR(list);
Packit 130fc8
                    break;
Packit 130fc8
                }
Packit 130fc8
                tuple = Py_BuildValue("(O)", list);
Packit 130fc8
                if (tuple) {
Packit 130fc8
                    ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs);
Packit 130fc8
                }
Packit 130fc8
                else {
Packit 130fc8
                    ret = NULL;
Packit 130fc8
                }
Packit 130fc8
                /* whether successful or not, we take the same action: */
Packit 130fc8
                Py_CLEAR(list);
Packit 130fc8
                Py_CLEAR(tuple);
Packit 130fc8
            }
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        case DBUS_TYPE_VARIANT:
Packit 130fc8
            {
Packit 130fc8
                DBusMessageIter sub;
Packit 130fc8
Packit 130fc8
                DBG("%s", "found a variant...");
Packit 130fc8
                dbus_message_iter_recurse(iter, &sub);
Packit 130fc8
                ret = _message_iter_get_pyobject(&sub, opts, variant_level+1);
Packit 130fc8
            }
Packit 130fc8
            break;
Packit 130fc8
Packit 130fc8
        default:
Packit 130fc8
            PyErr_Format(PyExc_TypeError, "Unknown type '\\%x' in D-Bus "
Packit 130fc8
                         "message", type);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    Py_CLEAR(args);
Packit 130fc8
    Py_CLEAR(kwargs);
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyObject *
Packit 130fc8
dbus_py_Message_get_args_list(Message *self, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
#ifdef PY3
Packit 130fc8
    Message_get_args_options opts = { 0 };
Packit 130fc8
    static char *argnames[] = { "byte_arrays", NULL };
Packit 130fc8
#else
Packit 130fc8
    Message_get_args_options opts = { 0, 0 };
Packit 130fc8
    static char *argnames[] = { "byte_arrays", "utf8_strings", NULL };
Packit 130fc8
#endif
Packit 130fc8
    PyObject *list;
Packit 130fc8
    DBusMessageIter iter;
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "DBG/%ld: called Message_get_args_list(self, *",
Packit 130fc8
            (long)getpid());
Packit 130fc8
    PyObject_Print(args, stderr, 0);
Packit 130fc8
    if (kwargs) {
Packit 130fc8
        fprintf(stderr, ", **");
Packit 130fc8
        PyObject_Print(kwargs, stderr, 0);
Packit 130fc8
    }
Packit 130fc8
    fprintf(stderr, ")\n");
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    if (PyTuple_Size(args) != 0) {
Packit 130fc8
        PyErr_SetString(PyExc_TypeError, "get_args_list takes no positional "
Packit 130fc8
                        "arguments");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
#ifdef PY3
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:get_args_list",
Packit 130fc8
                                     argnames,
Packit 130fc8
                                     &(opts.byte_arrays))) return NULL;
Packit 130fc8
#else
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:get_args_list",
Packit 130fc8
                                     argnames,
Packit 130fc8
                                     &(opts.byte_arrays),
Packit 130fc8
                                     &(opts.utf8_strings))) return NULL;
Packit 130fc8
#endif
Packit 130fc8
    if (!self->msg) return DBusPy_RaiseUnusableMessage();
Packit 130fc8
Packit 130fc8
    list = PyList_New(0);
Packit 130fc8
    if (!list) return NULL;
Packit 130fc8
Packit 130fc8
    /* Iterate over args, if any, appending to list */
Packit 130fc8
    if (dbus_message_iter_init(self->msg, &iter)) {
Packit 130fc8
        if (_message_iter_append_all_to_list(&iter, list, &opts) < 0) {
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            DBG_EXC("%s", "Message_get_args: appending all to list failed:");
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "DBG/%ld: message has args list ", (long)getpid());
Packit 130fc8
    PyObject_Print(list, stderr, 0);
Packit 130fc8
    fprintf(stderr, "\n");
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    return list;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* vim:set ft=c cino< sw=4 sts=4 et: */