~ubuntu-branches/ubuntu/precise/dbus-python/precise

« back to all changes in this revision

Viewing changes to .pc/python3-support.patch/_dbus_bindings/message-append.c

  • Committer: Package Import Robot
  • Author(s): Barry Warsaw
  • Date: 2012-01-12 14:47:33 UTC
  • Revision ID: package-import@ubuntu.com-20120112144733-xtfbmgw30h0j40d2
Tags: 0.84.0-2ubuntu1
* debian/patches:
  - since-0.84.0.patch: Upstream unreleased changes from git tag
    dbus-python-0.84.0 to HEAD.  This is a precursor to the following.
  - python3-support.patch: Upstream unreleased changes from git
    `python3` branch for supporting Python 3. (LP: #893091)
* debian/rules: Enable the test suite.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* D-Bus Message serialization. This contains all the logic to map from
 
2
 * Python objects to D-Bus types.
 
3
 *
 
4
 * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
 
5
 *
 
6
 * Permission is hereby granted, free of charge, to any person
 
7
 * obtaining a copy of this software and associated documentation
 
8
 * files (the "Software"), to deal in the Software without
 
9
 * restriction, including without limitation the rights to use, copy,
 
10
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 
11
 * of the Software, and to permit persons to whom the Software is
 
12
 * furnished to do so, subject to the following conditions:
 
13
 *
 
14
 * The above copyright notice and this permission notice shall be
 
15
 * included in all copies or substantial portions of the Software.
 
16
 *
 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
21
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
22
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
24
 * DEALINGS IN THE SOFTWARE.
 
25
 */
 
26
 
 
27
#include <config.h>
 
28
 
 
29
#include <assert.h>
 
30
 
 
31
#define DBG_IS_TOO_VERBOSE
 
32
#include "types-internal.h"
 
33
#include "message-internal.h"
 
34
 
 
35
/* Return the number of variants wrapping the given object. Return 0
 
36
 * if the object is not a D-Bus type.
 
37
 */
 
38
static long
 
39
get_variant_level(PyObject *obj)
 
40
{
 
41
    if (DBusPyIntBase_Check(obj)) {
 
42
        return ((DBusPyIntBase *)obj)->variant_level;
 
43
    }
 
44
    else if (DBusPyFloatBase_Check(obj)) {
 
45
        return ((DBusPyFloatBase *)obj)->variant_level;
 
46
    }
 
47
    else if (DBusPyArray_Check(obj)) {
 
48
        return ((DBusPyArray *)obj)->variant_level;
 
49
    }
 
50
    else if (DBusPyDict_Check(obj)) {
 
51
        return ((DBusPyDict *)obj)->variant_level;
 
52
    }
 
53
    else if (DBusPyString_Check(obj)) {
 
54
        return ((DBusPyString *)obj)->variant_level;
 
55
    }
 
56
    else if (DBusPyLongBase_Check(obj) ||
 
57
             DBusPyStrBase_Check(obj) ||
 
58
             DBusPyStruct_Check(obj)) {
 
59
        return dbus_py_variant_level_get(obj);
 
60
    }
 
61
    else {
 
62
        return 0;
 
63
    }
 
64
}
 
65
 
 
66
char dbus_py_Message_append__doc__[] = (
 
67
"set_args(*args[, **kwargs])\n\n"
 
68
"Set the message's arguments from the positional parameter, according to\n"
 
69
"the signature given by the ``signature`` keyword parameter.\n"
 
70
"\n"
 
71
"The following type conversions are supported:\n\n"
 
72
"=============================== ===========================\n"
 
73
"D-Bus (in signature)            Python\n"
 
74
"=============================== ===========================\n"
 
75
"boolean (b)                     any object (via bool())\n"
 
76
"byte (y)                        string of length 1\n"
 
77
"                                any integer\n"
 
78
"any integer type                any integer\n"
 
79
"double (d)                      any float\n"
 
80
"object path                     anything with a __dbus_object_path__ attribute\n"
 
81
"string, signature, object path  str (must be UTF-8) or unicode\n"
 
82
"dict (a{...})                   any mapping\n"
 
83
"array (a...)                    any iterable over appropriate objects\n"
 
84
"struct ((...))                  any iterable over appropriate objects\n"
 
85
"variant                         any object above (guess type as below)\n"
 
86
"=============================== ===========================\n"
 
87
"\n"
 
88
"Here 'any integer' means anything on which int() or long()\n"
 
89
"(as appropriate) will work, except for basestring subclasses.\n"
 
90
"'Any float' means anything on which float() will work, except\n"
 
91
"for basestring subclasses.\n"
 
92
"\n"
 
93
"If there is no signature, guess from the arguments using\n"
 
94
"the static method `Message.guess_signature`.\n"
 
95
);
 
96
 
 
97
char dbus_py_Message_guess_signature__doc__[] = (
 
98
"guess_signature(*args) -> Signature [static method]\n\n"
 
99
"Guess a D-Bus signature which should be used to encode the given\n"
 
100
"Python objects.\n"
 
101
"\n"
 
102
"The signature is constructed as follows:\n\n"
 
103
"+-------------------------------+---------------------------+\n"
 
104
"|Python                         |D-Bus                      |\n"
 
105
"+===============================+===========================+\n"
 
106
"|D-Bus type, variant_level > 0  |variant (v)                |\n"
 
107
"+-------------------------------+---------------------------+\n"
 
108
"|D-Bus type, variant_level == 0 |the corresponding type     |\n"
 
109
"+-------------------------------+---------------------------+\n"
 
110
"|anything with a                |object path                |\n"
 
111
"|__dbus_object_path__ attribute |                           |\n"
 
112
"+-------------------------------+---------------------------+\n"
 
113
"|bool                           |boolean (y)                |\n"
 
114
"+-------------------------------+---------------------------+\n"
 
115
"|any other int subclass         |int32 (i)                  |\n"
 
116
"+-------------------------------+---------------------------+\n"
 
117
"|any other long subclass        |int64 (x)                  |\n"
 
118
"+-------------------------------+---------------------------+\n"
 
119
"|any other float subclass       |double (d)                 |\n"
 
120
"+-------------------------------+---------------------------+\n"
 
121
"|any other str subclass         |string (s)                 |\n"
 
122
"+-------------------------------+---------------------------+\n"
 
123
"|any other unicode subclass     |string (s)                 |\n"
 
124
"+-------------------------------+---------------------------+\n"
 
125
"|any other tuple subclass       |struct ((...))             |\n"
 
126
"+-------------------------------+---------------------------+\n"
 
127
"|any other list subclass        |array (a...), guess        |\n"
 
128
"|                               |contents' type according to|\n"
 
129
"|                               |type of first item         |\n"
 
130
"+-------------------------------+---------------------------+\n"
 
131
"|any other dict subclass        |dict (a{...}), guess key,  |\n"
 
132
"|                               |value type according to    |\n"
 
133
"|                               |types for an arbitrary item|\n"
 
134
"+-------------------------------+---------------------------+\n"
 
135
"|anything else                  |raise TypeError            |\n"
 
136
"+-------------------------------+---------------------------+\n"
 
137
);
 
138
 
 
139
/* return a new reference, possibly to None */
 
140
static PyObject *
 
141
get_object_path(PyObject *obj)
 
142
{
 
143
    PyObject *magic_attr = PyObject_GetAttr(obj, dbus_py__dbus_object_path__const);
 
144
 
 
145
    if (magic_attr) {
 
146
        if (PyString_Check(magic_attr)) {
 
147
            return magic_attr;
 
148
        }
 
149
        else {
 
150
            Py_CLEAR(magic_attr);
 
151
            PyErr_SetString(PyExc_TypeError, "__dbus_object_path__ must be "
 
152
                            "a string");
 
153
            return NULL;
 
154
        }
 
155
    }
 
156
    else {
 
157
        /* Ignore exceptions, except for SystemExit and KeyboardInterrupt */
 
158
        if (PyErr_ExceptionMatches(PyExc_SystemExit) ||
 
159
            PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
 
160
            return NULL;
 
161
        PyErr_Clear();
 
162
        Py_RETURN_NONE;
 
163
    }
 
164
}
 
165
 
 
166
/* Return a new reference. If the object is a variant and variant_level_ptr
 
167
 * is not NULL, put the variant level in the variable pointed to, and
 
168
 * return the contained type instead of "v". */
 
169
static PyObject *
 
170
_signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr)
 
171
{
 
172
    PyObject *magic_attr;
 
173
    long variant_level = get_variant_level(obj);
 
174
    if (variant_level_ptr) {
 
175
        *variant_level_ptr = variant_level;
 
176
    }
 
177
    else if (variant_level > 0) {
 
178
        return PyString_FromString(DBUS_TYPE_VARIANT_AS_STRING);
 
179
    }
 
180
 
 
181
    if (obj == Py_True || obj == Py_False) {
 
182
      return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
 
183
    }
 
184
 
 
185
    magic_attr = get_object_path(obj);
 
186
    if (!magic_attr)
 
187
        return NULL;
 
188
    if (magic_attr != Py_None) {
 
189
        Py_CLEAR(magic_attr);
 
190
        return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
 
191
    }
 
192
    Py_CLEAR(magic_attr);
 
193
 
 
194
    /* Ordering is important: some of these are subclasses of each other. */
 
195
    if (PyInt_Check(obj)) {
 
196
        if (DBusPyInt16_Check(obj))
 
197
            return PyString_FromString(DBUS_TYPE_INT16_AS_STRING);
 
198
        else if (DBusPyInt32_Check(obj))
 
199
            return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
 
200
        else if (DBusPyByte_Check(obj))
 
201
            return PyString_FromString(DBUS_TYPE_BYTE_AS_STRING);
 
202
        else if (DBusPyUInt16_Check(obj))
 
203
            return PyString_FromString(DBUS_TYPE_UINT16_AS_STRING);
 
204
        else if (DBusPyBoolean_Check(obj))
 
205
            return PyString_FromString(DBUS_TYPE_BOOLEAN_AS_STRING);
 
206
        else
 
207
            return PyString_FromString(DBUS_TYPE_INT32_AS_STRING);
 
208
    }
 
209
    else if (PyLong_Check(obj)) {
 
210
        if (DBusPyInt64_Check(obj))
 
211
            return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
 
212
        else if (DBusPyUInt32_Check(obj))
 
213
            return PyString_FromString(DBUS_TYPE_UINT32_AS_STRING);
 
214
        else if (DBusPyUInt64_Check(obj))
 
215
            return PyString_FromString(DBUS_TYPE_UINT64_AS_STRING);
 
216
        else
 
217
            return PyString_FromString(DBUS_TYPE_INT64_AS_STRING);
 
218
    }
 
219
    else if (PyUnicode_Check(obj))
 
220
        return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
 
221
#if defined(DBUS_TYPE_UNIX_FD)
 
222
    else if (DBusPyUnixFd_Check(obj))
 
223
        return PyString_FromString(DBUS_TYPE_UNIX_FD_AS_STRING);
 
224
#endif
 
225
    else if (PyFloat_Check(obj)) {
 
226
#ifdef WITH_DBUS_FLOAT32
 
227
        if (DBusPyDouble_Check(obj))
 
228
            return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
 
229
        else if (DBusPyFloat_Check(obj))
 
230
            return PyString_FromString(DBUS_TYPE_FLOAT_AS_STRING);
 
231
        else
 
232
#endif
 
233
            return PyString_FromString(DBUS_TYPE_DOUBLE_AS_STRING);
 
234
    }
 
235
    else if (PyString_Check(obj)) {
 
236
        if (DBusPyObjectPath_Check(obj))
 
237
            return PyString_FromString(DBUS_TYPE_OBJECT_PATH_AS_STRING);
 
238
        else if (DBusPySignature_Check(obj))
 
239
            return PyString_FromString(DBUS_TYPE_SIGNATURE_AS_STRING);
 
240
        else if (DBusPyByteArray_Check(obj))
 
241
            return PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING
 
242
                                       DBUS_TYPE_BYTE_AS_STRING);
 
243
        else
 
244
            return PyString_FromString(DBUS_TYPE_STRING_AS_STRING);
 
245
    }
 
246
    else if (PyTuple_Check(obj)) {
 
247
        Py_ssize_t len = PyTuple_GET_SIZE(obj);
 
248
        PyObject *list = PyList_New(len + 2);   /* new ref */
 
249
        PyObject *item;                         /* temporary new ref */
 
250
        PyObject *empty_str;                    /* temporary new ref */
 
251
        PyObject *ret;
 
252
        Py_ssize_t i;
 
253
 
 
254
        if (!list) return NULL;
 
255
        if (len == 0) {
 
256
            PyErr_SetString(PyExc_ValueError, "D-Bus structs cannot be empty");
 
257
            Py_CLEAR(list);
 
258
            return NULL;
 
259
        }
 
260
        /* Set the first and last elements of list to be the parentheses */
 
261
        item = PyString_FromString(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
 
262
        if (PyList_SetItem(list, 0, item) < 0) {
 
263
            Py_CLEAR(list);
 
264
            return NULL;
 
265
        }
 
266
        item = PyString_FromString(DBUS_STRUCT_END_CHAR_AS_STRING);
 
267
        if (PyList_SetItem(list, len + 1, item) < 0) {
 
268
            Py_CLEAR(list);
 
269
            return NULL;
 
270
        }
 
271
        if (!item || !PyList_GET_ITEM(list, 0)) {
 
272
            Py_CLEAR(list);
 
273
            return NULL;
 
274
        }
 
275
        item = NULL;
 
276
 
 
277
        for (i = 0; i < len; i++) {
 
278
            item = PyTuple_GetItem(obj, i);
 
279
            if (!item) {
 
280
                Py_CLEAR(list);
 
281
                return NULL;
 
282
            }
 
283
            item = _signature_string_from_pyobject(item, NULL);
 
284
            if (!item) {
 
285
                Py_CLEAR(list);
 
286
                return NULL;
 
287
            }
 
288
            if (PyList_SetItem(list, i + 1, item) < 0) {
 
289
                Py_CLEAR(list);
 
290
                return NULL;
 
291
            }
 
292
            item = NULL;
 
293
        }
 
294
        empty_str = PyString_FromString("");
 
295
        if (!empty_str) {
 
296
            /* really shouldn't happen */
 
297
            Py_CLEAR(list);
 
298
            return NULL;
 
299
        }
 
300
        ret = PyObject_CallMethod(empty_str, "join", "(O)", list); /* new ref */
 
301
        /* whether ret is NULL or not, */
 
302
        Py_CLEAR(empty_str);
 
303
        Py_CLEAR(list);
 
304
        return ret;
 
305
    }
 
306
    else if (PyList_Check(obj)) {
 
307
        PyObject *tmp;
 
308
        PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING);
 
309
        if (!ret) return NULL;
 
310
        if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) {
 
311
            PyString_Concat(&ret, ((DBusPyArray *)obj)->signature);
 
312
            return ret;
 
313
        }
 
314
        if (PyList_GET_SIZE(obj) == 0) {
 
315
            /* No items, so fail. Or should we guess "av"? */
 
316
            PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
 
317
                            "from an empty list");
 
318
            return NULL;
 
319
        }
 
320
        tmp = PyList_GetItem(obj, 0);
 
321
        tmp = _signature_string_from_pyobject(tmp, NULL);
 
322
        if (!tmp) return NULL;
 
323
        PyString_ConcatAndDel(&ret, tmp);
 
324
        return ret;
 
325
    }
 
326
    else if (PyDict_Check(obj)) {
 
327
        PyObject *key, *value, *keysig, *valuesig;
 
328
        Py_ssize_t pos = 0;
 
329
        PyObject *ret = NULL;
 
330
 
 
331
        if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) {
 
332
            const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature);
 
333
 
 
334
            return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
 
335
                                        DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
 
336
                                        "%s"
 
337
                                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
 
338
                                       sig);
 
339
        }
 
340
        if (!PyDict_Next(obj, &pos, &key, &value)) {
 
341
            /* No items, so fail. Or should we guess "a{vv}"? */
 
342
            PyErr_SetString(PyExc_ValueError, "Unable to guess signature "
 
343
                             "from an empty dict");
 
344
            return NULL;
 
345
        }
 
346
        keysig = _signature_string_from_pyobject(key, NULL);
 
347
        valuesig = _signature_string_from_pyobject(value, NULL);
 
348
        if (keysig && valuesig) {
 
349
            ret = PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING
 
350
                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
 
351
                                       "%s%s"
 
352
                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
 
353
                                      PyString_AS_STRING(keysig),
 
354
                                      PyString_AS_STRING(valuesig));
 
355
        }
 
356
        Py_CLEAR(keysig);
 
357
        Py_CLEAR(valuesig);
 
358
        return ret;
 
359
    }
 
360
    else {
 
361
        PyErr_Format(PyExc_TypeError, "Don't know how which D-Bus type "
 
362
                     "to use to encode type \"%s\"",
 
363
                     Py_TYPE(obj)->tp_name);
 
364
        return NULL;
 
365
    }
 
366
}
 
367
 
 
368
PyObject *
 
369
dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args)
 
370
{
 
371
    PyObject *tmp, *ret = NULL;
 
372
 
 
373
    if (!args) {
 
374
        if (!PyErr_Occurred()) {
 
375
            PyErr_BadInternalCall();
 
376
        }
 
377
        return NULL;
 
378
    }
 
379
 
 
380
#ifdef USING_DBG
 
381
    fprintf(stderr, "DBG/%ld: called Message_guess_signature", (long)getpid());
 
382
    PyObject_Print(args, stderr, 0);
 
383
    fprintf(stderr, "\n");
 
384
#endif
 
385
 
 
386
    if (!PyTuple_Check(args)) {
 
387
        DBG("%s", "Message_guess_signature: args not a tuple");
 
388
        PyErr_BadInternalCall();
 
389
        return NULL;
 
390
    }
 
391
 
 
392
    /* if there were no args, easy */
 
393
    if (PyTuple_GET_SIZE(args) == 0) {
 
394
        DBG("%s", "Message_guess_signature: no args, so return Signature('')");
 
395
        return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", "");
 
396
    }
 
397
 
 
398
    /* if there were args, the signature we want is, by construction,
 
399
     * exactly the signature we get for the tuple args, except that we don't
 
400
     * want the parentheses. */
 
401
    tmp = _signature_string_from_pyobject(args, NULL);
 
402
    if (!tmp) {
 
403
        DBG("%s", "Message_guess_signature: failed");
 
404
        return NULL;
 
405
    }
 
406
    if (!PyString_Check(tmp) || PyString_GET_SIZE(tmp) < 2) {
 
407
        PyErr_SetString(PyExc_RuntimeError, "Internal error: "
 
408
                        "_signature_string_from_pyobject returned "
 
409
                        "a bad result");
 
410
        Py_CLEAR(tmp);
 
411
        return NULL;
 
412
    }
 
413
    ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)",
 
414
                                PyString_AS_STRING(tmp) + 1,
 
415
                                PyString_GET_SIZE(tmp) - 2);
 
416
    DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret,
 
417
        ret ? PyString_AS_STRING(ret) : "(NULL)");
 
418
    Py_CLEAR(tmp);
 
419
    return ret;
 
420
}
 
421
 
 
422
static int _message_iter_append_pyobject(DBusMessageIter *appender,
 
423
                                         DBusSignatureIter *sig_iter,
 
424
                                         PyObject *obj,
 
425
                                         dbus_bool_t *more);
 
426
static int _message_iter_append_variant(DBusMessageIter *appender,
 
427
                                        PyObject *obj);
 
428
 
 
429
static int
 
430
_message_iter_append_string(DBusMessageIter *appender,
 
431
                            int sig_type, PyObject *obj,
 
432
                            dbus_bool_t allow_object_path_attr)
 
433
{
 
434
    char *s;
 
435
 
 
436
    if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) {
 
437
        PyObject *object_path = get_object_path (obj);
 
438
 
 
439
        if (object_path == Py_None) {
 
440
            Py_CLEAR(object_path);
 
441
        }
 
442
        else if (!object_path) {
 
443
            return -1;
 
444
        }
 
445
        else {
 
446
            int ret = _message_iter_append_string(appender, sig_type,
 
447
                                                  object_path, FALSE);
 
448
            Py_CLEAR(object_path);
 
449
            return ret;
 
450
        }
 
451
    }
 
452
 
 
453
    if (PyString_Check(obj)) {
 
454
        PyObject *unicode;
 
455
 
 
456
        /* Raise TypeError if the string has embedded NULs */
 
457
        if (PyString_AsStringAndSize(obj, &s, NULL) < 0) return -1;
 
458
        /* Surely there's a faster stdlib way to validate UTF-8... */
 
459
        unicode = PyUnicode_DecodeUTF8(s, PyString_GET_SIZE(obj), NULL);
 
460
        if (!unicode) {
 
461
            PyErr_SetString(PyExc_UnicodeError, "String parameters "
 
462
                            "to be sent over D-Bus must be valid UTF-8");
 
463
            return -1;
 
464
        }
 
465
        Py_CLEAR(unicode);
 
466
 
 
467
        DBG("Performing actual append: string %s", s);
 
468
        if (!dbus_message_iter_append_basic(appender, sig_type,
 
469
                                            &s)) {
 
470
            PyErr_NoMemory();
 
471
            return -1;
 
472
        }
 
473
    }
 
474
    else if (PyUnicode_Check(obj)) {
 
475
        PyObject *utf8 = PyUnicode_AsUTF8String(obj);
 
476
        if (!utf8) return -1;
 
477
        /* Raise TypeError if the string has embedded NULs */
 
478
        if (PyString_AsStringAndSize(utf8, &s, NULL) < 0) return -1;
 
479
        DBG("Performing actual append: string (from unicode) %s", s);
 
480
        if (!dbus_message_iter_append_basic(appender, sig_type, &s)) {
 
481
            Py_CLEAR(utf8);
 
482
            PyErr_NoMemory();
 
483
            return -1;
 
484
        }
 
485
        Py_CLEAR(utf8);
 
486
    }
 
487
    else {
 
488
        PyErr_SetString(PyExc_TypeError,
 
489
                        "Expected a string or unicode object");
 
490
        return -1;
 
491
    }
 
492
    return 0;
 
493
}
 
494
 
 
495
static int
 
496
_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
 
497
{
 
498
    unsigned char y;
 
499
 
 
500
    if (PyString_Check(obj)) {
 
501
        if (PyString_GET_SIZE(obj) != 1) {
 
502
            PyErr_Format(PyExc_ValueError, "Expected a string of "
 
503
                         "length 1 byte, but found %d bytes",
 
504
                         (int) PyString_GET_SIZE(obj));
 
505
            return -1;
 
506
        }
 
507
        y = *(unsigned char *)PyString_AS_STRING(obj);
 
508
    }
 
509
    else {
 
510
        long i = PyInt_AsLong(obj);
 
511
 
 
512
        if (i == -1 && PyErr_Occurred()) return -1;
 
513
        if (i < 0 || i > 0xff) {
 
514
            PyErr_Format(PyExc_ValueError, "%d outside range for a "
 
515
                         "byte value", (int)i);
 
516
            return -1;
 
517
        }
 
518
        y = i;
 
519
    }
 
520
    DBG("Performing actual append: byte \\x%02x", (unsigned)y);
 
521
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
 
522
        PyErr_NoMemory();
 
523
        return -1;
 
524
    }
 
525
    return 0;
 
526
}
 
527
 
 
528
static dbus_bool_t
 
529
dbuspy_message_iter_close_container(DBusMessageIter *iter,
 
530
                                    DBusMessageIter *sub,
 
531
                                    dbus_bool_t is_ok)
 
532
{
 
533
    if (!is_ok) {
 
534
        dbus_message_iter_abandon_container(iter, sub);
 
535
        return TRUE;
 
536
    }
 
537
    return dbus_message_iter_close_container(iter, sub);
 
538
}
 
539
 
 
540
#if defined(DBUS_TYPE_UNIX_FD)
 
541
static int
 
542
_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
 
543
{
 
544
    int fd;
 
545
 
 
546
    if (PyInt_Check(obj)) {
 
547
        fd = PyInt_AsLong(obj);
 
548
    } else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
 
549
        fd = dbus_py_unix_fd_get_fd(obj);
 
550
    } else {
 
551
        return -1;
 
552
    }
 
553
 
 
554
    DBG("Performing actual append: fd %d", fd);
 
555
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
 
556
        PyErr_NoMemory();
 
557
        return -1;
 
558
    }
 
559
    return 0;
 
560
}
 
561
#endif
 
562
 
 
563
static int
 
564
_message_iter_append_dictentry(DBusMessageIter *appender,
 
565
                               DBusSignatureIter *sig_iter,
 
566
                               PyObject *dict, PyObject *key)
 
567
{
 
568
    DBusSignatureIter sub_sig_iter;
 
569
    DBusMessageIter sub;
 
570
    int ret = -1;
 
571
    PyObject *value = PyObject_GetItem(dict, key);
 
572
    dbus_bool_t more;
 
573
 
 
574
    if (!value) return -1;
 
575
 
 
576
#ifdef USING_DBG
 
577
    fprintf(stderr, "Append dictentry: ");
 
578
    PyObject_Print(key, stderr, 0);
 
579
    fprintf(stderr, " => ");
 
580
    PyObject_Print(value, stderr, 0);
 
581
    fprintf(stderr, "\n");
 
582
#endif
 
583
 
 
584
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
585
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
586
#ifdef USING_DBG
 
587
    {
 
588
        char *s;
 
589
        s = dbus_signature_iter_get_signature(sig_iter);
 
590
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
591
        dbus_free(s);
 
592
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
593
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
594
        dbus_free(s);
 
595
    }
 
596
#endif
 
597
 
 
598
    DBG("%s", "Opening DICT_ENTRY container");
 
599
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
 
600
                                          NULL, &sub)) {
 
601
        PyErr_NoMemory();
 
602
        goto out;
 
603
    }
 
604
    ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
 
605
    if (ret == 0) {
 
606
        ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
 
607
    }
 
608
    DBG("%s", "Closing DICT_ENTRY container");
 
609
    if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
 
610
        PyErr_NoMemory();
 
611
        ret = -1;
 
612
    }
 
613
out:
 
614
    Py_CLEAR(value);
 
615
    return ret;
 
616
}
 
617
 
 
618
static int
 
619
_message_iter_append_multi(DBusMessageIter *appender,
 
620
                           const DBusSignatureIter *sig_iter,
 
621
                           int mode, PyObject *obj)
 
622
{
 
623
    DBusMessageIter sub_appender;
 
624
    DBusSignatureIter sub_sig_iter;
 
625
    PyObject *contents;
 
626
    int ret;
 
627
    PyObject *iterator = PyObject_GetIter(obj);
 
628
    char *sig = NULL;
 
629
    int container = mode;
 
630
    dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
 
631
    int inner_type;
 
632
    dbus_bool_t more;
 
633
 
 
634
    assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
 
635
            mode == DBUS_TYPE_STRUCT);
 
636
 
 
637
#ifdef USING_DBG
 
638
    fprintf(stderr, "Appending multiple: ");
 
639
    PyObject_Print(obj, stderr, 0);
 
640
    fprintf(stderr, "\n");
 
641
#endif
 
642
 
 
643
    if (!iterator) return -1;
 
644
    if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
 
645
 
 
646
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
647
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
648
#ifdef USING_DBG
 
649
    {
 
650
        char *s;
 
651
        s = dbus_signature_iter_get_signature(sig_iter);
 
652
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
653
        dbus_free(s);
 
654
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
655
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
656
        dbus_free(s);
 
657
    }
 
658
#endif
 
659
    inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
 
660
 
 
661
    if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
 
662
        sig = dbus_signature_iter_get_signature(&sub_sig_iter);
 
663
        if (!sig) {
 
664
            PyErr_NoMemory();
 
665
            ret = -1;
 
666
            goto out;
 
667
        }
 
668
    }
 
669
    /* else leave sig set to NULL. */
 
670
 
 
671
    DBG("Opening '%c' container", container);
 
672
    if (!dbus_message_iter_open_container(appender, container,
 
673
                                          sig, &sub_appender)) {
 
674
        PyErr_NoMemory();
 
675
        ret = -1;
 
676
        goto out;
 
677
    }
 
678
    ret = 0;
 
679
    more = TRUE;
 
680
    while ((contents = PyIter_Next(iterator))) {
 
681
 
 
682
        if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
 
683
            DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
684
            dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
685
#ifdef USING_DBG
 
686
            {
 
687
                char *s;
 
688
                s = dbus_signature_iter_get_signature(sig_iter);
 
689
                DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
690
                dbus_free(s);
 
691
                s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
692
                DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
693
                dbus_free(s);
 
694
            }
 
695
#endif
 
696
        }
 
697
        else /* struct */ {
 
698
            if (!more) {
 
699
                PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
 
700
                             "D-Bus signature than in Python arguments ");
 
701
                ret = -1;
 
702
                break;
 
703
            }
 
704
        }
 
705
 
 
706
        if (mode == DBUS_TYPE_DICT_ENTRY) {
 
707
            ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
 
708
                                                 obj, contents);
 
709
        }
 
710
        else if (mode == DBUS_TYPE_ARRAY && is_byte_array
 
711
                 && inner_type == DBUS_TYPE_VARIANT) {
 
712
            /* Subscripting a ByteArray gives a str of length 1, but if the
 
713
             * container is a ByteArray and the parameter is an array of
 
714
             * variants, we want to produce an array of variants containing
 
715
             * bytes, not strings.
 
716
             */
 
717
            PyObject *args = Py_BuildValue("(O)", contents);
 
718
            PyObject *byte;
 
719
 
 
720
            if (!args)
 
721
                break;
 
722
            byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
 
723
            Py_CLEAR(args);
 
724
            if (!byte)
 
725
                break;
 
726
            ret = _message_iter_append_variant(&sub_appender, byte);
 
727
            Py_CLEAR(byte);
 
728
        }
 
729
        else {
 
730
            /* advances sub_sig_iter and sets more on success - for array
 
731
             * this doesn't matter, for struct it's essential */
 
732
            ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
 
733
                                                contents, &more);
 
734
        }
 
735
 
 
736
        Py_CLEAR(contents);
 
737
        if (ret < 0) {
 
738
            break;
 
739
        }
 
740
    }
 
741
 
 
742
    if (PyErr_Occurred()) {
 
743
        ret = -1;
 
744
    }
 
745
    else if (mode == DBUS_TYPE_STRUCT && more) {
 
746
        PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
 
747
                     "signature than in Python arguments ");
 
748
        ret = -1;
 
749
    }
 
750
 
 
751
    /* This must be run as cleanup, even on failure. */
 
752
    DBG("Closing '%c' container", container);
 
753
    if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
 
754
        PyErr_NoMemory();
 
755
        ret = -1;
 
756
    }
 
757
 
 
758
out:
 
759
    Py_CLEAR(iterator);
 
760
    dbus_free(sig);
 
761
    return ret;
 
762
}
 
763
 
 
764
static int
 
765
_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
 
766
                                          PyObject *obj)
 
767
{
 
768
    /* a bit of a faster path for byte arrays that are strings */
 
769
    Py_ssize_t len = PyString_GET_SIZE(obj);
 
770
    const char *s;
 
771
    DBusMessageIter sub;
 
772
    int ret;
 
773
 
 
774
    s = PyString_AS_STRING(obj);
 
775
    DBG("%s", "Opening ARRAY container");
 
776
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
 
777
                                          DBUS_TYPE_BYTE_AS_STRING, &sub)) {
 
778
        PyErr_NoMemory();
 
779
        return -1;
 
780
    }
 
781
    DBG("Appending fixed array of %d bytes", (int)len);
 
782
    if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
 
783
        ret = 0;
 
784
    }
 
785
    else {
 
786
        PyErr_NoMemory();
 
787
        ret = -1;
 
788
    }
 
789
    DBG("%s", "Closing ARRAY container");
 
790
    if (!dbus_message_iter_close_container(appender, &sub)) {
 
791
        PyErr_NoMemory();
 
792
        return -1;
 
793
    }
 
794
    return ret;
 
795
}
 
796
 
 
797
/* Encode some Python object into a D-Bus variant slot. */
 
798
static int
 
799
_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
 
800
{
 
801
    DBusSignatureIter obj_sig_iter;
 
802
    const char *obj_sig_str;
 
803
    PyObject *obj_sig;
 
804
    int ret;
 
805
    long variant_level;
 
806
    dbus_bool_t dummy;
 
807
 
 
808
    /* Separate the object into the contained object, and the number of
 
809
     * variants it's wrapped in. */
 
810
    obj_sig = _signature_string_from_pyobject(obj, &variant_level);
 
811
    if (!obj_sig) return -1;
 
812
 
 
813
    obj_sig_str = PyString_AsString(obj_sig);
 
814
    if (!obj_sig_str) return -1;
 
815
 
 
816
    if (variant_level < 1) {
 
817
        variant_level = 1;
 
818
    }
 
819
 
 
820
    dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
 
821
 
 
822
    { /* scope for variant_iters */
 
823
        DBusMessageIter variant_iters[variant_level];
 
824
        long i;
 
825
 
 
826
        for (i = 0; i < variant_level; i++) {
 
827
            DBusMessageIter *child = &variant_iters[i];
 
828
            /* The first is a special case: its parent is the iter passed in
 
829
             * to this function, instead of being the previous one in the
 
830
             * stack
 
831
             */
 
832
            DBusMessageIter *parent = (i == 0
 
833
                                        ? appender
 
834
                                        : &(variant_iters[i-1]));
 
835
            /* The last is also a special case: it contains the actual
 
836
             * object, rather than another variant
 
837
             */
 
838
            const char *sig_str = (i == variant_level-1
 
839
                                        ? obj_sig_str
 
840
                                        : DBUS_TYPE_VARIANT_AS_STRING);
 
841
 
 
842
            DBG("Opening VARIANT container %p inside %p containing '%s'",
 
843
                child, parent, sig_str);
 
844
            if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
 
845
                                                  sig_str, child)) {
 
846
                PyErr_NoMemory();
 
847
                ret = -1;
 
848
                goto out;
 
849
            }
 
850
        }
 
851
 
 
852
        /* Put the object itself into the innermost variant */
 
853
        ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
 
854
                                            &obj_sig_iter, obj, &dummy);
 
855
 
 
856
        /* here we rely on i (and variant_level) being a signed long */
 
857
        for (i = variant_level - 1; i >= 0; i--) {
 
858
            DBusMessageIter *child = &variant_iters[i];
 
859
            /* The first is a special case: its parent is the iter passed in
 
860
             * to this function, instead of being the previous one in the
 
861
             * stack
 
862
             */
 
863
            DBusMessageIter *parent = (i == 0 ? appender
 
864
                                              : &(variant_iters[i-1]));
 
865
 
 
866
            DBG("Closing VARIANT container %p inside %p", child, parent);
 
867
            if (!dbus_message_iter_close_container(parent, child)) {
 
868
                PyErr_NoMemory();
 
869
                ret = -1;
 
870
                goto out;
 
871
            }
 
872
        }
 
873
 
 
874
    }
 
875
 
 
876
out:
 
877
    Py_CLEAR(obj_sig);
 
878
    return ret;
 
879
}
 
880
 
 
881
/* On success, *more is set to whether there's more in the signature. */
 
882
static int
 
883
_message_iter_append_pyobject(DBusMessageIter *appender,
 
884
                              DBusSignatureIter *sig_iter,
 
885
                              PyObject *obj,
 
886
                              dbus_bool_t *more)
 
887
{
 
888
    int sig_type = dbus_signature_iter_get_current_type(sig_iter);
 
889
    union {
 
890
      dbus_bool_t b;
 
891
      double d;
 
892
      dbus_uint16_t uint16;
 
893
      dbus_int16_t int16;
 
894
      dbus_uint32_t uint32;
 
895
      dbus_int32_t int32;
 
896
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
 
897
      dbus_uint64_t uint64;
 
898
      dbus_int64_t int64;
 
899
#endif
 
900
    } u;
 
901
    int ret = -1;
 
902
 
 
903
#ifdef USING_DBG
 
904
    fprintf(stderr, "Appending object at %p: ", obj);
 
905
    PyObject_Print(obj, stderr, 0);
 
906
    fprintf(stderr, " into appender at %p, dbus wants type %c\n",
 
907
            appender, sig_type);
 
908
#endif
 
909
 
 
910
    switch (sig_type) {
 
911
      /* The numeric types are relatively simple to deal with, so are
 
912
       * inlined here. */
 
913
 
 
914
      case DBUS_TYPE_BOOLEAN:
 
915
          if (PyObject_IsTrue(obj)) {
 
916
              u.b = 1;
 
917
          }
 
918
          else {
 
919
              u.b = 0;
 
920
          }
 
921
          DBG("Performing actual append: bool(%ld)", (long)u.b);
 
922
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.b)) {
 
923
              PyErr_NoMemory();
 
924
              ret = -1;
 
925
              break;
 
926
          }
 
927
          ret = 0;
 
928
          break;
 
929
 
 
930
      case DBUS_TYPE_DOUBLE:
 
931
          u.d = PyFloat_AsDouble(obj);
 
932
          if (PyErr_Occurred()) {
 
933
              ret = -1;
 
934
              break;
 
935
          }
 
936
          DBG("Performing actual append: double(%f)", u.d);
 
937
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
 
938
              PyErr_NoMemory();
 
939
              ret = -1;
 
940
              break;
 
941
          }
 
942
          ret = 0;
 
943
          break;
 
944
 
 
945
#ifdef WITH_DBUS_FLOAT32
 
946
      case DBUS_TYPE_FLOAT:
 
947
          u.d = PyFloat_AsDouble(obj);
 
948
          if (PyErr_Occurred()) {
 
949
              ret = -1;
 
950
              break;
 
951
          }
 
952
          u.f = (float)u.d;
 
953
          DBG("Performing actual append: float(%f)", u.f);
 
954
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
 
955
              PyErr_NoMemory();
 
956
              ret = -1;
 
957
              break;
 
958
          }
 
959
          ret = 0;
 
960
          break;
 
961
#endif
 
962
 
 
963
          /* The integer types are all basically the same - we delegate to
 
964
          intNN_range_check() */
 
965
#define PROCESS_INTEGER(size) \
 
966
          u.size = dbus_py_##size##_range_check(obj);\
 
967
          if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
 
968
              ret = -1; \
 
969
              break; \
 
970
          }\
 
971
          DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
 
972
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
 
973
              PyErr_NoMemory();\
 
974
              ret = -1;\
 
975
              break;\
 
976
          } \
 
977
          ret = 0;
 
978
 
 
979
      case DBUS_TYPE_INT16:
 
980
          PROCESS_INTEGER(int16)
 
981
          break;
 
982
      case DBUS_TYPE_UINT16:
 
983
          PROCESS_INTEGER(uint16)
 
984
          break;
 
985
      case DBUS_TYPE_INT32:
 
986
          PROCESS_INTEGER(int32)
 
987
          break;
 
988
      case DBUS_TYPE_UINT32:
 
989
          PROCESS_INTEGER(uint32)
 
990
          break;
 
991
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
 
992
      case DBUS_TYPE_INT64:
 
993
          PROCESS_INTEGER(int64)
 
994
          break;
 
995
      case DBUS_TYPE_UINT64:
 
996
          PROCESS_INTEGER(uint64)
 
997
          break;
 
998
#else
 
999
      case DBUS_TYPE_INT64:
 
1000
      case DBUS_TYPE_UINT64:
 
1001
          PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
 
1002
                          "types are not supported on this platform");
 
1003
          ret = -1;
 
1004
          break;
 
1005
#endif
 
1006
#undef PROCESS_INTEGER
 
1007
 
 
1008
      /* Now the more complicated cases, which are delegated to helper
 
1009
       * functions (although in practice, the compiler will hopefully
 
1010
       * inline them anyway). */
 
1011
 
 
1012
      case DBUS_TYPE_STRING:
 
1013
      case DBUS_TYPE_SIGNATURE:
 
1014
      case DBUS_TYPE_OBJECT_PATH:
 
1015
          ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
 
1016
          break;
 
1017
 
 
1018
      case DBUS_TYPE_BYTE:
 
1019
          ret = _message_iter_append_byte(appender, obj);
 
1020
          break;
 
1021
 
 
1022
      case DBUS_TYPE_ARRAY:
 
1023
          /* 3 cases - it might actually be a dict, or it might be a byte array
 
1024
           * being copied from a string (for which we have a faster path),
 
1025
           * or it might be a generic array. */
 
1026
 
 
1027
          sig_type = dbus_signature_iter_get_element_type(sig_iter);
 
1028
          if (sig_type == DBUS_TYPE_DICT_ENTRY)
 
1029
            ret = _message_iter_append_multi(appender, sig_iter,
 
1030
                                             DBUS_TYPE_DICT_ENTRY, obj);
 
1031
          else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
 
1032
            ret = _message_iter_append_string_as_byte_array(appender, obj);
 
1033
          else
 
1034
            ret = _message_iter_append_multi(appender, sig_iter,
 
1035
                                             DBUS_TYPE_ARRAY, obj);
 
1036
          DBG("_message_iter_append_multi(): %d", ret);
 
1037
          break;
 
1038
 
 
1039
      case DBUS_TYPE_STRUCT:
 
1040
          ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
 
1041
          break;
 
1042
 
 
1043
      case DBUS_TYPE_VARIANT:
 
1044
          ret = _message_iter_append_variant(appender, obj);
 
1045
          break;
 
1046
 
 
1047
      case DBUS_TYPE_INVALID:
 
1048
          PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
 
1049
                          "signature than in Python arguments");
 
1050
          ret = -1;
 
1051
          break;
 
1052
 
 
1053
#if defined(DBUS_TYPE_UNIX_FD)
 
1054
      case DBUS_TYPE_UNIX_FD:
 
1055
          ret = _message_iter_append_unixfd(appender, obj);
 
1056
          break;
 
1057
#endif
 
1058
 
 
1059
      default:
 
1060
          PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
 
1061
                       "signature", sig_type);
 
1062
          ret = -1;
 
1063
          break;
 
1064
    }
 
1065
    if (ret < 0) return -1;
 
1066
 
 
1067
    DBG("Advancing signature iter at %p", sig_iter);
 
1068
    *more = dbus_signature_iter_next(sig_iter);
 
1069
#ifdef USING_DBG
 
1070
    DBG("- result: %ld, type %02x '%c'", (long)(*more),
 
1071
        (int)dbus_signature_iter_get_current_type(sig_iter),
 
1072
        (int)dbus_signature_iter_get_current_type(sig_iter));
 
1073
#endif
 
1074
    return 0;
 
1075
}
 
1076
 
 
1077
 
 
1078
PyObject *
 
1079
dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
 
1080
{
 
1081
    const char *signature = NULL;
 
1082
    PyObject *signature_obj = NULL;
 
1083
    DBusSignatureIter sig_iter;
 
1084
    DBusMessageIter appender;
 
1085
    static char *argnames[] = {"signature", NULL};
 
1086
    dbus_bool_t more;
 
1087
 
 
1088
    if (!self->msg) return DBusPy_RaiseUnusableMessage();
 
1089
 
 
1090
#ifdef USING_DBG
 
1091
    fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
 
1092
    PyObject_Print(args, stderr, 0);
 
1093
    if (kwargs) {
 
1094
        fprintf(stderr, ", **");
 
1095
        PyObject_Print(kwargs, stderr, 0);
 
1096
    }
 
1097
    fprintf(stderr, ")\n");
 
1098
#endif
 
1099
 
 
1100
    /* only use kwargs for this step: deliberately ignore args for now */
 
1101
    if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
 
1102
                                     argnames, &signature)) return NULL;
 
1103
 
 
1104
    if (!signature) {
 
1105
        DBG("%s", "No signature for message, guessing...");
 
1106
        signature_obj = dbus_py_Message_guess_signature(NULL, args);
 
1107
        if (!signature_obj) return NULL;
 
1108
        signature = PyString_AS_STRING(signature_obj);
 
1109
    }
 
1110
    /* from here onwards, you have to do a goto rather than returning NULL
 
1111
    to make sure signature_obj gets freed */
 
1112
 
 
1113
    /* iterate over args and the signature, together */
 
1114
    if (!dbus_signature_validate(signature, NULL)) {
 
1115
        PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
 
1116
        goto err;
 
1117
    }
 
1118
    dbus_message_iter_init_append(self->msg, &appender);
 
1119
 
 
1120
    if (signature[0] != '\0') {
 
1121
        int i = 0;
 
1122
 
 
1123
        more = TRUE;
 
1124
        dbus_signature_iter_init(&sig_iter, signature);
 
1125
        while (more) {
 
1126
            if (i >= PyTuple_GET_SIZE(args)) {
 
1127
                PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
 
1128
                                "signature than in Python arguments");
 
1129
                goto hosed;
 
1130
            }
 
1131
            if (_message_iter_append_pyobject(&appender, &sig_iter,
 
1132
                                              PyTuple_GET_ITEM(args, i),
 
1133
                                              &more) < 0) {
 
1134
                goto hosed;
 
1135
            }
 
1136
            i++;
 
1137
        }
 
1138
        if (i < PyTuple_GET_SIZE(args)) {
 
1139
            PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
 
1140
                    "signature than in Python arguments");
 
1141
            goto hosed;
 
1142
        }
 
1143
    }
 
1144
 
 
1145
    /* success! */
 
1146
    Py_CLEAR(signature_obj);
 
1147
    Py_RETURN_NONE;
 
1148
 
 
1149
hosed:
 
1150
    /* "If appending any of the arguments fails due to lack of memory,
 
1151
     * generally the message is hosed and you have to start over" -libdbus docs
 
1152
     * Enforce this by throwing away the message structure.
 
1153
     */
 
1154
    dbus_message_unref(self->msg);
 
1155
    self->msg = NULL;
 
1156
err:
 
1157
    Py_CLEAR(signature_obj);
 
1158
    return NULL;
 
1159
}
 
1160
 
 
1161
/* vim:set ft=c cino< sw=4 sts=4 et: */