Blame _dbus_bindings/message-append.c

Packit 130fc8
/* D-Bus Message serialization. This contains all the logic to map from
Packit 130fc8
 * Python objects to D-Bus types.
Packit 130fc8
 *
Packit 130fc8
 * Copyright (C) 2006 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
#include <assert.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
/* Return the number of variants wrapping the given object. Return 0
Packit 130fc8
 * if the object is not a D-Bus type.
Packit 130fc8
 */
Packit 130fc8
static long
Packit 130fc8
get_variant_level(PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    if (DBusPyString_Check(obj)) {
Packit 130fc8
        return ((DBusPyString *)obj)->variant_level;
Packit 130fc8
    }
Packit 130fc8
#ifndef PY3
Packit 130fc8
    else if (DBusPyIntBase_Check(obj)) {
Packit 130fc8
        return ((DBusPyIntBase *)obj)->variant_level;
Packit 130fc8
    }
Packit 130fc8
#endif
Packit 130fc8
    else if (DBusPyFloatBase_Check(obj)) {
Packit 130fc8
        return ((DBusPyFloatBase *)obj)->variant_level;
Packit 130fc8
    }
Packit 130fc8
    else if (DBusPyArray_Check(obj)) {
Packit 130fc8
        return ((DBusPyArray *)obj)->variant_level;
Packit 130fc8
    }
Packit 130fc8
    else if (DBusPyDict_Check(obj)) {
Packit 130fc8
        return ((DBusPyDict *)obj)->variant_level;
Packit 130fc8
    }
Packit 130fc8
    else if (DBusPyLongBase_Check(obj) ||
Packit 130fc8
#ifdef PY3
Packit 130fc8
             DBusPyBytesBase_Check(obj) ||
Packit 130fc8
#endif
Packit 130fc8
             DBusPyStrBase_Check(obj) ||
Packit 130fc8
             DBusPyStruct_Check(obj)) {
Packit 130fc8
        return dbus_py_variant_level_get(obj);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        return 0;
Packit 130fc8
    }
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
char dbus_py_Message_append__doc__[] = (
Packit 130fc8
"set_args(*args[, **kwargs])\n\n"
Packit 130fc8
"Set the message's arguments from the positional parameter, according to\n"
Packit 130fc8
"the signature given by the ``signature`` keyword parameter.\n"
Packit 130fc8
"\n"
Packit 130fc8
"The following type conversions are supported:\n\n"
Packit 130fc8
"=============================== ===========================\n"
Packit 130fc8
"D-Bus (in signature)            Python\n"
Packit 130fc8
"=============================== ===========================\n"
Packit 130fc8
"boolean (b)                     any object (via bool())\n"
Packit 130fc8
"byte (y)                        string of length 1\n"
Packit 130fc8
"                                any integer\n"
Packit 130fc8
"any integer type                any integer\n"
Packit 130fc8
"double (d)                      any float\n"
Packit 130fc8
"object path                     anything with a __dbus_object_path__ attribute\n"
Packit 130fc8
"string, signature, object path  str (must be UTF-8) or unicode\n"
Packit 130fc8
"dict (a{...})                   any mapping\n"
Packit 130fc8
"array (a...)                    any iterable over appropriate objects\n"
Packit 130fc8
"struct ((...))                  any iterable over appropriate objects\n"
Packit 130fc8
"variant                         any object above (guess type as below)\n"
Packit 130fc8
"=============================== ===========================\n"
Packit 130fc8
"\n"
Packit 130fc8
"Here 'any integer' means anything on which int() or long()\n"
Packit 130fc8
"(as appropriate) will work, except for basestring subclasses.\n"
Packit 130fc8
"'Any float' means anything on which float() will work, except\n"
Packit 130fc8
"for basestring subclasses.\n"
Packit 130fc8
"\n"
Packit 130fc8
"If there is no signature, guess from the arguments using\n"
Packit 130fc8
"the static method `Message.guess_signature`.\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
char dbus_py_Message_guess_signature__doc__[] = (
Packit 130fc8
"guess_signature(*args) -> Signature [static method]\n\n"
Packit 130fc8
"Guess a D-Bus signature which should be used to encode the given\n"
Packit 130fc8
"Python objects.\n"
Packit 130fc8
"\n"
Packit 130fc8
"The signature is constructed as follows:\n\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|Python                         |D-Bus                      |\n"
Packit 130fc8
"+===============================+===========================+\n"
Packit 130fc8
"|D-Bus type, variant_level > 0  |variant (v)                |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|D-Bus type, variant_level == 0 |the corresponding type     |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|anything with a                |object path                |\n"
Packit 130fc8
"|__dbus_object_path__ attribute |                           |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|bool                           |boolean (y)                |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other int subclass         |int32 (i)                  |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other long subclass        |int64 (x)                  |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other float subclass       |double (d)                 |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other str subclass         |string (s)                 |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other unicode subclass     |string (s)                 |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other tuple subclass       |struct ((...))             |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other list subclass        |array (a...), guess        |\n"
Packit 130fc8
"|                               |contents' type according to|\n"
Packit 130fc8
"|                               |type of first item         |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|any other dict subclass        |dict (a{...}), guess key,  |\n"
Packit 130fc8
"|                               |value type according to    |\n"
Packit 130fc8
"|                               |types for an arbitrary item|\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
"|anything else                  |raise TypeError            |\n"
Packit 130fc8
"+-------------------------------+---------------------------+\n"
Packit 130fc8
);
Packit 130fc8
Packit 130fc8
/* return a new reference, possibly to None */
Packit 130fc8
static PyObject *
Packit 130fc8
get_object_path(PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
Packit 130fc8
Packit 130fc8
    if (magic_attr) {
Packit 130fc8
        if (PyUnicode_Check(magic_attr) || PyBytes_Check(magic_attr)) {
Packit 130fc8
            return magic_attr;
Packit 130fc8
        }
Packit 130fc8
        else {
Packit 130fc8
            Py_CLEAR(magic_attr);
Packit 130fc8
            PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
Packit 130fc8
                            "a string");
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
Packit 130fc8
        if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
Packit 130fc8
            PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
Packit 130fc8
            return NULL;
Packit 130fc8
        PyErr_Clear();
Packit 130fc8
        Py_RETURN_NONE;
Packit 130fc8
    }
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* Return a new reference. If the object is a variant and variant_level_ptr
Packit 130fc8
 * is not NULL, put the variant level in the variable pointed to, and
Packit 130fc8
 * return the contained type instead of "v". */
Packit 130fc8
static PyObject *
Packit 130fc8
_signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
Packit 130fc8
{
Packit 130fc8
    PyObject *magic_attr;
Packit 130fc8
    long variant_level = get_variant_level(obj);
Packit 130fc8
Packit 130fc8
    if (variant_level < 0)
Packit 130fc8
        return NULL;
Packit 130fc8
Packit 130fc8
    if (variant_level_ptr) {
Packit 130fc8
        *variant_level_ptr = variant_level;
Packit 130fc8
    }
Packit 130fc8
    else if (variant_level > 0) {
Packit 130fc8
        return NATIVESTR_FROMSTR(DBUS_TYPE_VARIANT_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (obj == Py_True || obj == Py_False) {
Packit 130fc8
      return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    magic_attr = get_object_path(obj);
Packit 130fc8
    if (!magic_attr)
Packit 130fc8
        return NULL;
Packit 130fc8
    if (magic_attr != Py_None) {
Packit 130fc8
        Py_CLEAR(magic_attr);
Packit 130fc8
        return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
    Py_CLEAR(magic_attr);
Packit 130fc8
Packit 130fc8
    /* Ordering is important: some of these are subclasses of each other. */
Packit 130fc8
#ifdef PY3
Packit 130fc8
    if (PyLong_Check(obj)) {
Packit 130fc8
        if (DBusPyUInt64_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
Packit 130fc8
        else if (DBusPyInt64_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
Packit 130fc8
        else if (DBusPyUInt32_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
Packit 130fc8
        else if (DBusPyInt32_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
Packit 130fc8
        else if (DBusPyUInt16_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
Packit 130fc8
        else if (DBusPyInt16_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
Packit 130fc8
        else if (DBusPyByte_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
Packit 130fc8
        else if (DBusPyBoolean_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
#else  /* !PY3 */
Packit 130fc8
    if (PyInt_Check(obj)) {
Packit 130fc8
        if (DBusPyInt16_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT16_AS_STRING);
Packit 130fc8
        else if (DBusPyInt32_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
Packit 130fc8
        else if (DBusPyByte_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_BYTE_AS_STRING);
Packit 130fc8
        else if (DBusPyUInt16_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT16_AS_STRING);
Packit 130fc8
        else if (DBusPyBoolean_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_BOOLEAN_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT32_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
    else if (PyLong_Check(obj)) {
Packit 130fc8
        if (DBusPyInt64_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
Packit 130fc8
        else if (DBusPyUInt32_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT32_AS_STRING);
Packit 130fc8
        else if (DBusPyUInt64_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_UINT64_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
#endif  /* PY3 */
Packit 130fc8
    else if (PyUnicode_Check(obj)) {
Packit 130fc8
        /* Object paths and signatures are unicode subtypes in Python 3
Packit 130fc8
         * (the first two cases will never be true in Python 2) */
Packit 130fc8
        if (DBusPyObjectPath_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
Packit 130fc8
        else if (DBusPySignature_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
#if defined(DBUS_TYPE_UNIX_FD)
Packit 130fc8
    else if (DBusPyUnixFd_Check(obj))
Packit 130fc8
        return NATIVESTR_FROMSTR(DBUS_TYPE_UNIX_FD_AS_STRING);
Packit 130fc8
#endif
Packit 130fc8
    else if (PyFloat_Check(obj)) {
Packit 130fc8
#ifdef WITH_DBUS_FLOAT32
Packit 130fc8
        if (DBusPyDouble_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
Packit 130fc8
        else if (DBusPyFloat_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_FLOAT_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
#endif
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
    else if (PyBytes_Check(obj)) {
Packit 130fc8
        /* Object paths and signatures are bytes subtypes in Python 2
Packit 130fc8
         * (the first two cases will never be true in Python 3) */
Packit 130fc8
        if (DBusPyObjectPath_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING);
Packit 130fc8
        else if (DBusPySignature_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING);
Packit 130fc8
        else if (DBusPyByteArray_Check(obj))
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING
Packit 130fc8
                                     DBUS_TYPE_BYTE_AS_STRING);
Packit 130fc8
        else
Packit 130fc8
            return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING);
Packit 130fc8
    }
Packit 130fc8
    else if (PyTuple_Check(obj)) {
Packit 130fc8
        Py_ssize_t len = PyTuple_GET_SIZE(obj);
Packit 130fc8
        PyObject *list = PyList_New(len + 2);   /* new ref */
Packit 130fc8
        PyObject *item;                         /* temporary new ref */
Packit 130fc8
        PyObject *empty_str;                    /* temporary new ref */
Packit 130fc8
        PyObject *ret;
Packit 130fc8
        Py_ssize_t i;
Packit 130fc8
Packit 130fc8
        if (!list) return NULL;
Packit 130fc8
        if (len == 0) {
Packit 130fc8
            PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        /* Set the first and last elements of list to be the parentheses */
Packit 130fc8
        item = NATIVESTR_FROMSTR(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
Packit 130fc8
        if (PyList_SetItem(list, 0, item) < 0) {
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        item = NATIVESTR_FROMSTR(DBUS_STRUCT_END_CHAR_AS_STRING);
Packit 130fc8
        if (PyList_SetItem(list, len + 1, item) < 0) {
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        if (!item || !PyList_GET_ITEM(list, 0)) {
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        item = NULL;
Packit 130fc8
Packit 130fc8
        for (i = 0; i < len; i++) {
Packit 130fc8
            item = PyTuple_GetItem(obj, i);
Packit 130fc8
            if (!item) {
Packit 130fc8
                Py_CLEAR(list);
Packit 130fc8
                return NULL;
Packit 130fc8
            }
Packit 130fc8
            item = _signature_string_from_pyobject(item, NULL);
Packit 130fc8
            if (!item) {
Packit 130fc8
                Py_CLEAR(list);
Packit 130fc8
                return NULL;
Packit 130fc8
            }
Packit 130fc8
            if (PyList_SetItem(list, i + 1, item) < 0) {
Packit 130fc8
                Py_CLEAR(list);
Packit 130fc8
                return NULL;
Packit 130fc8
            }
Packit 130fc8
            item = NULL;
Packit 130fc8
        }
Packit 130fc8
        empty_str = NATIVESTR_FROMSTR("");
Packit 130fc8
        if (!empty_str) {
Packit 130fc8
            /* really shouldn't happen */
Packit 130fc8
            Py_CLEAR(list);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
Packit 130fc8
        /* whether ret is NULL or not, */
Packit 130fc8
        Py_CLEAR(empty_str);
Packit 130fc8
        Py_CLEAR(list);
Packit 130fc8
        return ret;
Packit 130fc8
    }
Packit 130fc8
    else if (PyList_Check(obj)) {
Packit 130fc8
        PyObject *tmp;
Packit 130fc8
        PyObject *ret = NATIVESTR_FROMSTR(DBUS_TYPE_ARRAY_AS_STRING);
Packit 130fc8
        if (!ret) return NULL;
Packit 130fc8
#ifdef PY3
Packit 130fc8
        if (DBusPyArray_Check(obj) &&
Packit 130fc8
            PyUnicode_Check(((DBusPyArray *)obj)->signature))
Packit 130fc8
        {
Packit 130fc8
            PyObject *concat = PyUnicode_Concat(
Packit 130fc8
                ret, ((DBusPyArray *)obj)->signature);
Packit 130fc8
            Py_CLEAR(ret);
Packit 130fc8
            return concat;
Packit 130fc8
        }
Packit 130fc8
#else
Packit 130fc8
        if (DBusPyArray_Check(obj) &&
Packit 130fc8
            PyBytes_Check(((DBusPyArray *)obj)->signature))
Packit 130fc8
        {
Packit 130fc8
            PyBytes_Concat(&ret, ((DBusPyArray *)obj)->signature);
Packit 130fc8
            return ret;
Packit 130fc8
        }
Packit 130fc8
#endif
Packit 130fc8
        if (PyList_GET_SIZE(obj) == 0) {
Packit 130fc8
            /* No items, so fail. Or should we guess "av"? */
Packit 130fc8
            PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
Packit 130fc8
                            "from an empty list");
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        tmp = PyList_GetItem(obj, 0);
Packit 130fc8
        tmp = _signature_string_from_pyobject(tmp, NULL);
Packit 130fc8
        if (!tmp) return NULL;
Packit 130fc8
#ifdef PY3
Packit 130fc8
        {
Packit 130fc8
            PyObject *concat = PyUnicode_Concat(ret, tmp);
Packit 130fc8
            Py_CLEAR(ret);
Packit 130fc8
            Py_CLEAR(tmp);
Packit 130fc8
            return concat;
Packit 130fc8
        }
Packit 130fc8
#else
Packit 130fc8
        PyBytes_ConcatAndDel(&ret, tmp);
Packit 130fc8
        return ret;
Packit 130fc8
#endif
Packit 130fc8
    }
Packit 130fc8
    else if (PyDict_Check(obj)) {
Packit 130fc8
        PyObject *key, *value, *keysig, *valuesig;
Packit 130fc8
        Py_ssize_t pos = 0;
Packit 130fc8
        PyObject *ret = NULL;
Packit 130fc8
Packit 130fc8
#ifdef PY3
Packit 130fc8
        if (DBusPyDict_Check(obj) &&
Packit 130fc8
            PyUnicode_Check(((DBusPyDict *)obj)->signature))
Packit 130fc8
        {
Packit 130fc8
            return PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
Packit 130fc8
                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
Packit 130fc8
                                         "%U"
Packit 130fc8
                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
Packit 130fc8
                                        ((DBusPyDict *)obj)->signature);
Packit 130fc8
        }
Packit 130fc8
#else
Packit 130fc8
        if (DBusPyDict_Check(obj) &&
Packit 130fc8
            PyBytes_Check(((DBusPyDict *)obj)->signature))
Packit 130fc8
        {
Packit 130fc8
            const char *sig = PyBytes_AS_STRING(((DBusPyDict *)obj)->signature);
Packit 130fc8
Packit 130fc8
            return PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
Packit 130fc8
                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
Packit 130fc8
                                       "%s"
Packit 130fc8
                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
Packit 130fc8
                                      sig);
Packit 130fc8
        }
Packit 130fc8
#endif
Packit 130fc8
        if (!PyDict_Next(obj, &pos, &key, &value)) {
Packit 130fc8
            /* No items, so fail. Or should we guess "a{vv}"? */
Packit 130fc8
            PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
Packit 130fc8
                             "from an empty dict");
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        keysig = _signature_string_from_pyobject(key, NULL);
Packit 130fc8
        valuesig = _signature_string_from_pyobject(value, NULL);
Packit 130fc8
        if (keysig && valuesig) {
Packit 130fc8
#ifdef PY3
Packit 130fc8
            ret = PyUnicode_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
Packit 130fc8
                                        DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
Packit 130fc8
                                        "%U%U"
Packit 130fc8
                                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
Packit 130fc8
                                       keysig, valuesig);
Packit 130fc8
#else
Packit 130fc8
            ret = PyBytes_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
Packit 130fc8
                                      DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
Packit 130fc8
                                      "%s%s"
Packit 130fc8
                                      DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
Packit 130fc8
                                     PyBytes_AS_STRING(keysig),
Packit 130fc8
                                     PyBytes_AS_STRING(valuesig));
Packit 130fc8
#endif
Packit 130fc8
        }
Packit 130fc8
        Py_CLEAR(keysig);
Packit 130fc8
        Py_CLEAR(valuesig);
Packit 130fc8
        return ret;
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        PyErr_Format(PyExc_TypeError, "Don't know which D-Bus type "
Packit 130fc8
                     "to use to encode type \"%s\"",
Packit 130fc8
                     Py_TYPE(obj)->tp_name);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
PyObject *
Packit 130fc8
dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
Packit 130fc8
{
Packit 130fc8
    PyObject *tmp, *ret = NULL;
Packit 130fc8
Packit 130fc8
    if (!args) {
Packit 130fc8
        if (!PyErr_Occurred()) {
Packit 130fc8
            PyErr_BadInternalCall();
Packit 130fc8
        }
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
Packit 130fc8
    PyObject_Print(args, stderr, 0);
Packit 130fc8
    fprintf(stderr, "\n");
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    if (!PyTuple_Check(args)) {
Packit 130fc8
        DBG("%s", "Message_guess_signature: args not a tuple");
Packit 130fc8
        PyErr_BadInternalCall();
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* if there were no args, easy */
Packit 130fc8
    if (PyTuple_GET_SIZE(args) == 0) {
Packit 130fc8
        DBG("%s", "Message_guess_signature: no args, so return Signature('')");
Packit 130fc8
        return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* if there were args, the signature we want is, by construction,
Packit 130fc8
     * exactly the signature we get for the tuple args, except that we don't
Packit 130fc8
     * want the parentheses. */
Packit 130fc8
    tmp = _signature_string_from_pyobject(args, NULL);
Packit 130fc8
    if (!tmp) {
Packit 130fc8
        DBG("%s", "Message_guess_signature: failed");
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    if (PyUnicode_Check(tmp)) {
Packit 130fc8
        PyObject *as_bytes = PyUnicode_AsUTF8String(tmp);
Packit 130fc8
        Py_CLEAR(tmp);
Packit 130fc8
        if (!as_bytes)
Packit 130fc8
            return NULL;
Packit 130fc8
        if (PyBytes_GET_SIZE(as_bytes) < 2) {
Packit 130fc8
            PyErr_SetString(PyExc_RuntimeError, "Internal error: "
Packit 130fc8
                            "_signature_string_from_pyobject returned "
Packit 130fc8
                            "a bad result");
Packit 130fc8
            Py_CLEAR(as_bytes);
Packit 130fc8
            return NULL;
Packit 130fc8
        }
Packit 130fc8
        tmp = as_bytes;
Packit 130fc8
    }
Packit 130fc8
    if (!PyBytes_Check(tmp) || PyBytes_GET_SIZE(tmp) < 2) {
Packit 130fc8
        PyErr_SetString(PyExc_RuntimeError, "Internal error: "
Packit 130fc8
                        "_signature_string_from_pyobject returned "
Packit 130fc8
                        "a bad result");
Packit 130fc8
        Py_CLEAR(tmp);
Packit 130fc8
        return NULL;
Packit 130fc8
    }
Packit 130fc8
    ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
Packit 130fc8
                                PyBytes_AS_STRING(tmp) + 1,
Packit 130fc8
                                PyBytes_GET_SIZE(tmp) - 2);
Packit 130fc8
    Py_CLEAR(tmp);
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int _message_iter_append_pyobject(DBusMessageIter *appender,
Packit 130fc8
                                         DBusSignatureIter *sig_iter,
Packit 130fc8
                                         PyObject *obj,
Packit 130fc8
                                         dbus_bool_t *more);
Packit 130fc8
static int _message_iter_append_variant(DBusMessageIter *appender,
Packit 130fc8
                                        PyObject *obj);
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_string(DBusMessageIter *appender,
Packit 130fc8
                            int sig_type, PyObject *obj,
Packit 130fc8
                            dbus_bool_t allow_object_path_attr)
Packit 130fc8
{
Packit 130fc8
    char *s;
Packit 130fc8
    PyObject *utf8;
Packit 130fc8
Packit 130fc8
    if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
Packit 130fc8
        PyObject *object_path = get_object_path (obj);
Packit 130fc8
Packit 130fc8
        if (object_path == Py_None) {
Packit 130fc8
            Py_CLEAR(object_path);
Packit 130fc8
        }
Packit 130fc8
        else if (!object_path) {
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        else {
Packit 130fc8
            int ret = _message_iter_append_string(appender, sig_type,
Packit 130fc8
                                                  object_path, FALSE);
Packit 130fc8
            Py_CLEAR(object_path);
Packit 130fc8
            return ret;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (PyBytes_Check(obj)) {
Packit 130fc8
        utf8 = obj;
Packit 130fc8
        Py_INCREF(obj);
Packit 130fc8
    }
Packit 130fc8
    else if (PyUnicode_Check(obj)) {
Packit 130fc8
        utf8 = PyUnicode_AsUTF8String(obj);
Packit 130fc8
        if (!utf8) return -1;
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        PyErr_SetString(PyExc_TypeError,
Packit 130fc8
                        "Expected a string or unicode object");
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* Raise TypeError if the string has embedded NULs */
Packit 130fc8
    if (PyBytes_AsStringAndSize(utf8, &s, NULL) < 0)
Packit 130fc8
        return -1;
Packit 130fc8
Packit 130fc8
    /* Validate UTF-8, strictly */
Packit 130fc8
    if (!dbus_validate_utf8(s, NULL)) {
Packit 130fc8
        PyErr_SetString(PyExc_UnicodeError, "String parameters "
Packit 130fc8
                        "to be sent over D-Bus must be valid UTF-8 "
Packit 130fc8
                        "with no noncharacter code points");
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    DBG("Performing actual append: string (from unicode) %s", s);
Packit 130fc8
    if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
Packit 130fc8
        Py_CLEAR(utf8);
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    Py_CLEAR(utf8);
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    unsigned char y;
Packit 130fc8
Packit 130fc8
    if (PyBytes_Check(obj)) {
Packit 130fc8
        if (PyBytes_GET_SIZE(obj) != 1) {
Packit 130fc8
            PyErr_Format(PyExc_ValueError,
Packit 130fc8
                         "Expected a length-1 bytes but found %d bytes",
Packit 130fc8
                         (int)PyBytes_GET_SIZE(obj));
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        y = *(unsigned char *)PyBytes_AS_STRING(obj);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        /* on Python 2 this accepts either int or long */
Packit 130fc8
        long i = PyLong_AsLong(obj);
Packit 130fc8
Packit 130fc8
        if (i == -1 && PyErr_Occurred()) return -1;
Packit 130fc8
        if (i < 0 || i > 0xff) {
Packit 130fc8
            PyErr_Format(PyExc_ValueError,
Packit 130fc8
                         "%d outside range for a byte value",
Packit 130fc8
                         (int)i);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        y = i;
Packit 130fc8
    }
Packit 130fc8
    DBG("Performing actual append: byte \\x%02x", (unsigned)y);
Packit 130fc8
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static dbus_bool_t
Packit 130fc8
dbuspy_message_iter_close_container(DBusMessageIter *iter,
Packit 130fc8
                                    DBusMessageIter *sub,
Packit 130fc8
                                    dbus_bool_t is_ok)
Packit 130fc8
{
Packit 130fc8
    if (!is_ok) {
Packit 130fc8
        dbus_message_iter_abandon_container(iter, sub);
Packit 130fc8
        return TRUE;
Packit 130fc8
    }
Packit 130fc8
    return dbus_message_iter_close_container(iter, sub);
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
#if defined(DBUS_TYPE_UNIX_FD)
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    int fd;
Packit 130fc8
    long original_fd;
Packit 130fc8
Packit 130fc8
    if (INTORLONG_CHECK(obj))
Packit 130fc8
    {
Packit 130fc8
        /* on Python 2 this accepts either int or long */
Packit 130fc8
        original_fd = PyLong_AsLong(obj);
Packit 130fc8
        if (original_fd == -1 && PyErr_Occurred())
Packit 130fc8
            return -1;
Packit 130fc8
        if (original_fd < INT_MIN || original_fd > INT_MAX) {
Packit 130fc8
            PyErr_Format(PyExc_ValueError, "out of int range: %ld",
Packit 130fc8
                         original_fd);
Packit 130fc8
            return -1;
Packit 130fc8
        }
Packit 130fc8
        fd = (int)original_fd;
Packit 130fc8
    }
Packit 130fc8
    else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
Packit 130fc8
        fd = dbus_py_unix_fd_get_fd(obj);
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    DBG("Performing actual append: fd %d", fd);
Packit 130fc8
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_dictentry(DBusMessageIter *appender,
Packit 130fc8
                               DBusSignatureIter *sig_iter,
Packit 130fc8
                               PyObject *dict, PyObject *key)
Packit 130fc8
{
Packit 130fc8
    DBusSignatureIter sub_sig_iter;
Packit 130fc8
    DBusMessageIter sub;
Packit 130fc8
    int ret = -1;
Packit 130fc8
    PyObject *value = PyObject_GetItem(dict, key);
Packit 130fc8
    dbus_bool_t more;
Packit 130fc8
Packit 130fc8
    if (!value) return -1;
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "Append dictentry: ");
Packit 130fc8
    PyObject_Print(key, stderr, 0);
Packit 130fc8
    fprintf(stderr, " => ");
Packit 130fc8
    PyObject_Print(value, stderr, 0);
Packit 130fc8
    fprintf(stderr, "\n");
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
Packit 130fc8
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    {
Packit 130fc8
        char *s;
Packit 130fc8
        s = dbus_signature_iter_get_signature(sig_iter);
Packit 130fc8
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
Packit 130fc8
        dbus_free(s);
Packit 130fc8
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
Packit 130fc8
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
Packit 130fc8
        dbus_free(s);
Packit 130fc8
    }
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    DBG("%s", "Opening DICT_ENTRY container");
Packit 130fc8
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
Packit 130fc8
                                          NULL, &sub)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        goto out;
Packit 130fc8
    }
Packit 130fc8
    ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
Packit 130fc8
    if (ret == 0) {
Packit 130fc8
        ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
Packit 130fc8
    }
Packit 130fc8
    DBG("%s", "Closing DICT_ENTRY container");
Packit 130fc8
    if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        ret = -1;
Packit 130fc8
    }
Packit 130fc8
out:
Packit 130fc8
    Py_CLEAR(value);
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_multi(DBusMessageIter *appender,
Packit 130fc8
                           const DBusSignatureIter *sig_iter,
Packit 130fc8
                           int mode, PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    DBusMessageIter sub_appender;
Packit 130fc8
    DBusSignatureIter sub_sig_iter;
Packit 130fc8
    PyObject *contents;
Packit 130fc8
    int ret;
Packit 130fc8
    PyObject *iterator = PyObject_GetIter(obj);
Packit 130fc8
    char *sig = NULL;
Packit 130fc8
    int container = mode;
Packit 130fc8
    dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
Packit 130fc8
    int inner_type;
Packit 130fc8
    dbus_bool_t more;
Packit 130fc8
Packit 130fc8
    assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
Packit 130fc8
            mode == DBUS_TYPE_STRUCT);
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "Appending multiple: ");
Packit 130fc8
    PyObject_Print(obj, stderr, 0);
Packit 130fc8
    fprintf(stderr, "\n");
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    if (!iterator) return -1;
Packit 130fc8
    if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
Packit 130fc8
Packit 130fc8
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
Packit 130fc8
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    {
Packit 130fc8
        char *s;
Packit 130fc8
        s = dbus_signature_iter_get_signature(sig_iter);
Packit 130fc8
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
Packit 130fc8
        dbus_free(s);
Packit 130fc8
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
Packit 130fc8
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
Packit 130fc8
        dbus_free(s);
Packit 130fc8
    }
Packit 130fc8
#endif
Packit 130fc8
    inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
Packit 130fc8
Packit 130fc8
    if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
Packit 130fc8
        sig = dbus_signature_iter_get_signature(&sub_sig_iter);
Packit 130fc8
        if (!sig) {
Packit 130fc8
            PyErr_NoMemory();
Packit 130fc8
            ret = -1;
Packit 130fc8
            goto out;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
    /* else leave sig set to NULL. */
Packit 130fc8
Packit 130fc8
    DBG("Opening '%c' container", container);
Packit 130fc8
    if (!dbus_message_iter_open_container(appender, container,
Packit 130fc8
                                          sig, &sub_appender)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        ret = -1;
Packit 130fc8
        goto out;
Packit 130fc8
    }
Packit 130fc8
    ret = 0;
Packit 130fc8
    more = TRUE;
Packit 130fc8
    while ((contents = PyIter_Next(iterator))) {
Packit 130fc8
Packit 130fc8
        if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
Packit 130fc8
            DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
Packit 130fc8
            dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
            {
Packit 130fc8
                char *s;
Packit 130fc8
                s = dbus_signature_iter_get_signature(sig_iter);
Packit 130fc8
                DBG("Signature of parent iterator %p is %s", sig_iter, s);
Packit 130fc8
                dbus_free(s);
Packit 130fc8
                s = dbus_signature_iter_get_signature(&sub_sig_iter);
Packit 130fc8
                DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
Packit 130fc8
                dbus_free(s);
Packit 130fc8
            }
Packit 130fc8
#endif
Packit 130fc8
        }
Packit 130fc8
        else /* struct */ {
Packit 130fc8
            if (!more) {
Packit 130fc8
                PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
Packit 130fc8
                             "D-Bus signature than in Python arguments ");
Packit 130fc8
                ret = -1;
Packit 130fc8
                break;
Packit 130fc8
            }
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        if (mode == DBUS_TYPE_DICT_ENTRY) {
Packit 130fc8
            ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
Packit 130fc8
                                                 obj, contents);
Packit 130fc8
        }
Packit 130fc8
        else if (mode == DBUS_TYPE_ARRAY && is_byte_array
Packit 130fc8
                 && inner_type == DBUS_TYPE_VARIANT) {
Packit 130fc8
            /* Subscripting a ByteArray gives a str of length 1, but if the
Packit 130fc8
             * container is a ByteArray and the parameter is an array of
Packit 130fc8
             * variants, we want to produce an array of variants containing
Packit 130fc8
             * bytes, not strings.
Packit 130fc8
             */
Packit 130fc8
            PyObject *args = Py_BuildValue("(O)", contents);
Packit 130fc8
            PyObject *byte;
Packit 130fc8
Packit 130fc8
            if (!args)
Packit 130fc8
                break;
Packit 130fc8
            byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
Packit 130fc8
            Py_CLEAR(args);
Packit 130fc8
            if (!byte)
Packit 130fc8
                break;
Packit 130fc8
            ret = _message_iter_append_variant(&sub_appender, byte);
Packit 130fc8
            Py_CLEAR(byte);
Packit 130fc8
        }
Packit 130fc8
        else {
Packit 130fc8
            /* advances sub_sig_iter and sets more on success - for array
Packit 130fc8
             * this doesn't matter, for struct it's essential */
Packit 130fc8
            ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
Packit 130fc8
                                                contents, &more);
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        Py_CLEAR(contents);
Packit 130fc8
        if (ret < 0) {
Packit 130fc8
            break;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (PyErr_Occurred()) {
Packit 130fc8
        ret = -1;
Packit 130fc8
    }
Packit 130fc8
    else if (mode == DBUS_TYPE_STRUCT && more) {
Packit 130fc8
        PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
Packit 130fc8
                     "signature than in Python arguments ");
Packit 130fc8
        ret = -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* This must be run as cleanup, even on failure. */
Packit 130fc8
    DBG("Closing '%c' container", container);
Packit 130fc8
    if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        ret = -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
out:
Packit 130fc8
    Py_CLEAR(iterator);
Packit 130fc8
    dbus_free(sig);
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
Packit 130fc8
                                          PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    /* a bit of a faster path for byte arrays that are strings */
Packit 130fc8
    Py_ssize_t len = PyBytes_GET_SIZE(obj);
Packit 130fc8
    const char *s;
Packit 130fc8
    DBusMessageIter sub;
Packit 130fc8
    int ret;
Packit 130fc8
Packit 130fc8
    s = PyBytes_AS_STRING(obj);
Packit 130fc8
    DBG("%s", "Opening ARRAY container");
Packit 130fc8
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
Packit 130fc8
                                          DBUS_TYPE_BYTE_AS_STRING, &sub)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    DBG("Appending fixed array of %d bytes", (int)len);
Packit 130fc8
    if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
Packit 130fc8
        ret = 0;
Packit 130fc8
    }
Packit 130fc8
    else {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        ret = -1;
Packit 130fc8
    }
Packit 130fc8
    DBG("%s", "Closing ARRAY container");
Packit 130fc8
    if (!dbus_message_iter_close_container(appender, &sub)) {
Packit 130fc8
        PyErr_NoMemory();
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* Encode some Python object into a D-Bus variant slot. */
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
Packit 130fc8
{
Packit 130fc8
    DBusSignatureIter obj_sig_iter;
Packit 130fc8
    const char *obj_sig_str;
Packit 130fc8
    PyObject *obj_sig;
Packit 130fc8
    int ret;
Packit 130fc8
    long variant_level;
Packit 130fc8
    dbus_bool_t dummy;
Packit 130fc8
    DBusMessageIter *variant_iters = NULL;
Packit 130fc8
Packit 130fc8
    /* Separate the object into the contained object, and the number of
Packit 130fc8
     * variants it's wrapped in. */
Packit 130fc8
    obj_sig = _signature_string_from_pyobject(obj, &variant_level);
Packit 130fc8
    if (!obj_sig) return -1;
Packit 130fc8
Packit 130fc8
    if (PyUnicode_Check(obj_sig)) {
Packit 130fc8
        PyObject *obj_sig_as_bytes = PyUnicode_AsUTF8String(obj_sig);
Packit 130fc8
        Py_CLEAR(obj_sig);
Packit 130fc8
        if (!obj_sig_as_bytes)
Packit 130fc8
            return -1;
Packit 130fc8
        obj_sig = obj_sig_as_bytes;
Packit 130fc8
    }
Packit 130fc8
    obj_sig_str = PyBytes_AsString(obj_sig);
Packit 130fc8
    if (!obj_sig_str) {
Packit 130fc8
        Py_CLEAR(obj_sig);
Packit 130fc8
        return -1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    if (variant_level < 1) {
Packit 130fc8
        variant_level = 1;
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
Packit 130fc8
Packit 130fc8
    {
Packit 130fc8
        long i;
Packit 130fc8
Packit 130fc8
        variant_iters = calloc (variant_level, sizeof (DBusMessageIter));
Packit 130fc8
Packit 130fc8
        if (!variant_iters) {
Packit 130fc8
            PyErr_NoMemory();
Packit 130fc8
            ret = -1;
Packit 130fc8
            goto out;
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        for (i = 0; i < variant_level; i++) {
Packit 130fc8
            DBusMessageIter *child = &variant_iters[i];
Packit 130fc8
            /* The first is a special case: its parent is the iter passed in
Packit 130fc8
             * to this function, instead of being the previous one in the
Packit 130fc8
             * stack
Packit 130fc8
             */
Packit 130fc8
            DBusMessageIter *parent = (i == 0
Packit 130fc8
                                        ? appender
Packit 130fc8
                                        : &(variant_iters[i-1]));
Packit 130fc8
            /* The last is also a special case: it contains the actual
Packit 130fc8
             * object, rather than another variant
Packit 130fc8
             */
Packit 130fc8
            const char *sig_str = (i == variant_level-1
Packit 130fc8
                                        ? obj_sig_str
Packit 130fc8
                                        : DBUS_TYPE_VARIANT_AS_STRING);
Packit 130fc8
Packit 130fc8
            DBG("Opening VARIANT container %p inside %p containing '%s'",
Packit 130fc8
                child, parent, sig_str);
Packit 130fc8
            if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
Packit 130fc8
                                                  sig_str, child)) {
Packit 130fc8
                PyErr_NoMemory();
Packit 130fc8
                ret = -1;
Packit 130fc8
                goto out;
Packit 130fc8
            }
Packit 130fc8
        }
Packit 130fc8
Packit 130fc8
        /* Put the object itself into the innermost variant */
Packit 130fc8
        ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
Packit 130fc8
                                            &obj_sig_iter, obj, &dummy);
Packit 130fc8
Packit 130fc8
        /* here we rely on i (and variant_level) being a signed long */
Packit 130fc8
        for (i = variant_level - 1; i >= 0; i--) {
Packit 130fc8
            DBusMessageIter *child = &variant_iters[i];
Packit 130fc8
            /* The first is a special case: its parent is the iter passed in
Packit 130fc8
             * to this function, instead of being the previous one in the
Packit 130fc8
             * stack
Packit 130fc8
             */
Packit 130fc8
            DBusMessageIter *parent = (i == 0 ? appender
Packit 130fc8
                                              : &(variant_iters[i-1]));
Packit 130fc8
Packit 130fc8
            DBG("Closing VARIANT container %p inside %p", child, parent);
Packit 130fc8
            if (!dbus_message_iter_close_container(parent, child)) {
Packit 130fc8
                PyErr_NoMemory();
Packit 130fc8
                ret = -1;
Packit 130fc8
                goto out;
Packit 130fc8
            }
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
out:
Packit 130fc8
    if (variant_iters != NULL)
Packit 130fc8
        free (variant_iters);
Packit 130fc8
Packit 130fc8
    Py_CLEAR(obj_sig);
Packit 130fc8
    return ret;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* On success, *more is set to whether there's more in the signature. */
Packit 130fc8
static int
Packit 130fc8
_message_iter_append_pyobject(DBusMessageIter *appender,
Packit 130fc8
                              DBusSignatureIter *sig_iter,
Packit 130fc8
                              PyObject *obj,
Packit 130fc8
                              dbus_bool_t *more)
Packit 130fc8
{
Packit 130fc8
    int sig_type = dbus_signature_iter_get_current_type(sig_iter);
Packit 130fc8
    DBusBasicValue u;
Packit 130fc8
    int ret = -1;
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "Appending object at %p: ", obj);
Packit 130fc8
    PyObject_Print(obj, stderr, 0);
Packit 130fc8
    fprintf(stderr, " into appender at %p, dbus wants type %c\n",
Packit 130fc8
            appender, sig_type);
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
    switch (sig_type) {
Packit 130fc8
      /* The numeric types are relatively simple to deal with, so are
Packit 130fc8
       * inlined here. */
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_BOOLEAN:
Packit 130fc8
          if (PyObject_IsTrue(obj)) {
Packit 130fc8
              u.bool_val = 1;
Packit 130fc8
          }
Packit 130fc8
          else {
Packit 130fc8
              u.bool_val = 0;
Packit 130fc8
          }
Packit 130fc8
          DBG("Performing actual append: bool(%ld)", (long)u.bool_val);
Packit 130fc8
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.bool_val)) {
Packit 130fc8
              PyErr_NoMemory();
Packit 130fc8
              ret = -1;
Packit 130fc8
              break;
Packit 130fc8
          }
Packit 130fc8
          ret = 0;
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_DOUBLE:
Packit 130fc8
          u.dbl = PyFloat_AsDouble(obj);
Packit 130fc8
          if (PyErr_Occurred()) {
Packit 130fc8
              ret = -1;
Packit 130fc8
              break;
Packit 130fc8
          }
Packit 130fc8
          DBG("Performing actual append: double(%f)", u.dbl);
Packit 130fc8
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.dbl)) {
Packit 130fc8
              PyErr_NoMemory();
Packit 130fc8
              ret = -1;
Packit 130fc8
              break;
Packit 130fc8
          }
Packit 130fc8
          ret = 0;
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
#ifdef WITH_DBUS_FLOAT32
Packit 130fc8
      case DBUS_TYPE_FLOAT:
Packit 130fc8
          u.dbl = PyFloat_AsDouble(obj);
Packit 130fc8
          if (PyErr_Occurred()) {
Packit 130fc8
              ret = -1;
Packit 130fc8
              break;
Packit 130fc8
          }
Packit 130fc8
          /* FIXME: DBusBasicValue will need to grow a float member if
Packit 130fc8
           * float32 becomes supported */
Packit 130fc8
          u.f = (float)u.dbl;
Packit 130fc8
          DBG("Performing actual append: float(%f)", u.f);
Packit 130fc8
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
Packit 130fc8
              PyErr_NoMemory();
Packit 130fc8
              ret = -1;
Packit 130fc8
              break;
Packit 130fc8
          }
Packit 130fc8
          ret = 0;
Packit 130fc8
          break;
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
          /* The integer types are all basically the same - we delegate to
Packit 130fc8
          intNN_range_check() */
Packit 130fc8
#define PROCESS_INTEGER(size, member) \
Packit 130fc8
          u.member = dbus_py_##size##_range_check(obj);\
Packit 130fc8
          if (u.member == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
Packit 130fc8
              ret = -1; \
Packit 130fc8
              break; \
Packit 130fc8
          }\
Packit 130fc8
          DBG("Performing actual append: " #size "(%lld)", (long long)u.member); \
Packit 130fc8
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.member)) {\
Packit 130fc8
              PyErr_NoMemory();\
Packit 130fc8
              ret = -1;\
Packit 130fc8
              break;\
Packit 130fc8
          } \
Packit 130fc8
          ret = 0;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_INT16:
Packit 130fc8
          PROCESS_INTEGER(int16, i16)
Packit 130fc8
          break;
Packit 130fc8
      case DBUS_TYPE_UINT16:
Packit 130fc8
          PROCESS_INTEGER(uint16, u16)
Packit 130fc8
          break;
Packit 130fc8
      case DBUS_TYPE_INT32:
Packit 130fc8
          PROCESS_INTEGER(int32, i32)
Packit 130fc8
          break;
Packit 130fc8
      case DBUS_TYPE_UINT32:
Packit 130fc8
          PROCESS_INTEGER(uint32, u32)
Packit 130fc8
          break;
Packit 130fc8
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
Packit 130fc8
      case DBUS_TYPE_INT64:
Packit 130fc8
          PROCESS_INTEGER(int64, i64)
Packit 130fc8
          break;
Packit 130fc8
      case DBUS_TYPE_UINT64:
Packit 130fc8
          PROCESS_INTEGER(uint64, u64)
Packit 130fc8
          break;
Packit 130fc8
#else
Packit 130fc8
      case DBUS_TYPE_INT64:
Packit 130fc8
      case DBUS_TYPE_UINT64:
Packit 130fc8
          PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
Packit 130fc8
                          "types are not supported on this platform");
Packit 130fc8
          ret = -1;
Packit 130fc8
          break;
Packit 130fc8
#endif
Packit 130fc8
#undef PROCESS_INTEGER
Packit 130fc8
Packit 130fc8
      /* Now the more complicated cases, which are delegated to helper
Packit 130fc8
       * functions (although in practice, the compiler will hopefully
Packit 130fc8
       * inline them anyway). */
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_STRING:
Packit 130fc8
      case DBUS_TYPE_SIGNATURE:
Packit 130fc8
      case DBUS_TYPE_OBJECT_PATH:
Packit 130fc8
          ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_BYTE:
Packit 130fc8
          ret = _message_iter_append_byte(appender, obj);
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_ARRAY:
Packit 130fc8
          /* 3 cases - it might actually be a dict, or it might be a byte array
Packit 130fc8
           * being copied from a string (for which we have a faster path),
Packit 130fc8
           * or it might be a generic array. */
Packit 130fc8
Packit 130fc8
          sig_type = dbus_signature_iter_get_element_type(sig_iter);
Packit 130fc8
          if (sig_type == DBUS_TYPE_DICT_ENTRY)
Packit 130fc8
            ret = _message_iter_append_multi(appender, sig_iter,
Packit 130fc8
                                             DBUS_TYPE_DICT_ENTRY, obj);
Packit 130fc8
          else if (sig_type == DBUS_TYPE_BYTE && PyBytes_Check(obj))
Packit 130fc8
            ret = _message_iter_append_string_as_byte_array(appender, obj);
Packit 130fc8
          else
Packit 130fc8
            ret = _message_iter_append_multi(appender, sig_iter,
Packit 130fc8
                                             DBUS_TYPE_ARRAY, obj);
Packit 130fc8
          DBG("_message_iter_append_multi(): %d", ret);
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_STRUCT:
Packit 130fc8
          ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_VARIANT:
Packit 130fc8
          ret = _message_iter_append_variant(appender, obj);
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
      case DBUS_TYPE_INVALID:
Packit 130fc8
          PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
Packit 130fc8
                          "signature than in Python arguments");
Packit 130fc8
          ret = -1;
Packit 130fc8
          break;
Packit 130fc8
Packit 130fc8
#if defined(DBUS_TYPE_UNIX_FD)
Packit 130fc8
      case DBUS_TYPE_UNIX_FD:
Packit 130fc8
          ret = _message_iter_append_unixfd(appender, obj);
Packit 130fc8
          break;
Packit 130fc8
#endif
Packit 130fc8
Packit 130fc8
      default:
Packit 130fc8
          PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
Packit 130fc8
                       "signature", sig_type);
Packit 130fc8
          ret = -1;
Packit 130fc8
          break;
Packit 130fc8
    }
Packit 130fc8
    if (ret < 0) return -1;
Packit 130fc8
Packit 130fc8
    DBG("Advancing signature iter at %p", sig_iter);
Packit 130fc8
    *more = dbus_signature_iter_next(sig_iter);
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    DBG("- result: %ld, type %02x '%c'", (long)(*more),
Packit 130fc8
        (int)dbus_signature_iter_get_current_type(sig_iter),
Packit 130fc8
        (int)dbus_signature_iter_get_current_type(sig_iter));
Packit 130fc8
#endif
Packit 130fc8
    return 0;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
Packit 130fc8
PyObject *
Packit 130fc8
dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
Packit 130fc8
{
Packit 130fc8
    const char *signature = NULL;
Packit 130fc8
    PyObject *signature_obj = NULL;
Packit 130fc8
    DBusSignatureIter sig_iter;
Packit 130fc8
    DBusMessageIter appender;
Packit 130fc8
    static char *argnames[] = {"signature", NULL};
Packit 130fc8
    dbus_bool_t more;
Packit 130fc8
Packit 130fc8
    if (!self->msg) return DBusPy_RaiseUnusableMessage();
Packit 130fc8
Packit 130fc8
#ifdef USING_DBG
Packit 130fc8
    fprintf(stderr, "DBG/%ld: called Message_append(*", (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
    /* only use kwargs for this step: deliberately ignore args for now */
Packit 130fc8
    if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
Packit 130fc8
                                     argnames, &signature)) return NULL;
Packit 130fc8
Packit 130fc8
    if (!signature) {
Packit 130fc8
        DBG("%s", "No signature for message, guessing...");
Packit 130fc8
        signature_obj = dbus_py_Message_guess_signature(NULL, args);
Packit 130fc8
        if (!signature_obj) return NULL;
Packit 130fc8
        if (PyUnicode_Check(signature_obj)) {
Packit 130fc8
            PyObject *signature_as_bytes;
Packit 130fc8
            signature_as_bytes = PyUnicode_AsUTF8String(signature_obj);
Packit 130fc8
            Py_CLEAR(signature_obj);
Packit 130fc8
            if (!signature_as_bytes)
Packit 130fc8
                return NULL;
Packit 130fc8
            signature_obj = signature_as_bytes;
Packit 130fc8
        }
Packit 130fc8
        else {
Packit 130fc8
            assert(PyBytes_Check(signature_obj));
Packit 130fc8
        }
Packit 130fc8
        signature = PyBytes_AS_STRING(signature_obj);
Packit 130fc8
    }
Packit 130fc8
    /* from here onwards, you have to do a goto rather than returning NULL
Packit 130fc8
    to make sure signature_obj gets freed */
Packit 130fc8
Packit 130fc8
    /* iterate over args and the signature, together */
Packit 130fc8
    if (!dbus_signature_validate(signature, NULL)) {
Packit 130fc8
        PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
Packit 130fc8
        goto err;
Packit 130fc8
    }
Packit 130fc8
    dbus_message_iter_init_append(self->msg, &appender);
Packit 130fc8
Packit 130fc8
    if (signature[0] != '\0') {
Packit 130fc8
        int i = 0;
Packit 130fc8
Packit 130fc8
        more = TRUE;
Packit 130fc8
        dbus_signature_iter_init(&sig_iter, signature);
Packit 130fc8
        while (more) {
Packit 130fc8
            if (i >= PyTuple_GET_SIZE(args)) {
Packit 130fc8
                PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
Packit 130fc8
                                "signature than in Python arguments");
Packit 130fc8
                goto hosed;
Packit 130fc8
            }
Packit 130fc8
            if (_message_iter_append_pyobject(&appender, &sig_iter,
Packit 130fc8
                                              PyTuple_GET_ITEM(args, i),
Packit 130fc8
                                              &more) < 0) {
Packit 130fc8
                goto hosed;
Packit 130fc8
            }
Packit 130fc8
            i++;
Packit 130fc8
        }
Packit 130fc8
        if (i < PyTuple_GET_SIZE(args)) {
Packit 130fc8
            PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
Packit 130fc8
                    "signature than in Python arguments");
Packit 130fc8
            goto hosed;
Packit 130fc8
        }
Packit 130fc8
    }
Packit 130fc8
Packit 130fc8
    /* success! */
Packit 130fc8
    Py_CLEAR(signature_obj);
Packit 130fc8
    Py_RETURN_NONE;
Packit 130fc8
Packit 130fc8
hosed:
Packit 130fc8
    /* "If appending any of the arguments fails due to lack of memory,
Packit 130fc8
     * generally the message is hosed and you have to start over" -libdbus docs
Packit 130fc8
     * Enforce this by throwing away the message structure.
Packit 130fc8
     */
Packit 130fc8
    dbus_message_unref(self->msg);
Packit 130fc8
    self->msg = NULL;
Packit 130fc8
err:
Packit 130fc8
    Py_CLEAR(signature_obj);
Packit 130fc8
    return NULL;
Packit 130fc8
}
Packit 130fc8
Packit 130fc8
/* vim:set ft=c cino< sw=4 sts=4 et: */