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

« back to all changes in this revision

Viewing changes to .pc/since-0.84.0.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
                     obj->ob_type->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
            PyErr_NoMemory();
 
482
            return -1;
 
483
        }
 
484
        Py_CLEAR(utf8);
 
485
    }
 
486
    else {
 
487
        PyErr_SetString(PyExc_TypeError,
 
488
                        "Expected a string or unicode object");
 
489
        return -1;
 
490
    }
 
491
    return 0;
 
492
}
 
493
 
 
494
static int
 
495
_message_iter_append_byte(DBusMessageIter *appender, PyObject *obj)
 
496
{
 
497
    unsigned char y;
 
498
 
 
499
    if (PyString_Check(obj)) {
 
500
        if (PyString_GET_SIZE(obj) != 1) {
 
501
            PyErr_Format(PyExc_ValueError, "Expected a string of "
 
502
                         "length 1 byte, but found %d bytes",
 
503
                         (int) PyString_GET_SIZE(obj));
 
504
            return -1;
 
505
        }
 
506
        y = *(unsigned char *)PyString_AS_STRING(obj);
 
507
    }
 
508
    else {
 
509
        long i = PyInt_AsLong(obj);
 
510
 
 
511
        if (i == -1 && PyErr_Occurred()) return -1;
 
512
        if (i < 0 || i > 0xff) {
 
513
            PyErr_Format(PyExc_ValueError, "%d outside range for a "
 
514
                         "byte value", (int)i);
 
515
            return -1;
 
516
        }
 
517
        y = i;
 
518
    }
 
519
    DBG("Performing actual append: byte \\x%02x", (unsigned)y);
 
520
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_BYTE, &y)) {
 
521
        PyErr_NoMemory();
 
522
        return -1;
 
523
    }
 
524
    return 0;
 
525
}
 
526
 
 
527
static dbus_bool_t
 
528
dbuspy_message_iter_close_container(DBusMessageIter *iter,
 
529
                                    DBusMessageIter *sub,
 
530
                                    dbus_bool_t is_ok)
 
531
{
 
532
#ifdef HAVE_DBUS_MESSAGE_ITER_ABANDON_CONTAINER
 
533
    if (!is_ok) {
 
534
        dbus_message_iter_abandon_container(iter, sub);
 
535
        return TRUE;
 
536
    }
 
537
#else
 
538
    (void) is_ok;
 
539
#endif
 
540
    return dbus_message_iter_close_container(iter, sub);
 
541
}
 
542
 
 
543
#if defined(DBUS_TYPE_UNIX_FD)
 
544
static int
 
545
_message_iter_append_unixfd(DBusMessageIter *appender, PyObject *obj)
 
546
{
 
547
    int fd;
 
548
 
 
549
    if (PyInt_Check(obj)) {
 
550
        fd = PyInt_AsLong(obj);
 
551
    } else if (PyObject_IsInstance(obj, (PyObject*) &DBusPyUnixFd_Type)) {
 
552
        fd = dbus_py_unix_fd_get_fd(obj);
 
553
    } else {
 
554
        return -1;
 
555
    }
 
556
 
 
557
    DBG("Performing actual append: fd %d", fd);
 
558
    if (!dbus_message_iter_append_basic(appender, DBUS_TYPE_UNIX_FD, &fd)) {
 
559
        PyErr_NoMemory();
 
560
        return -1;
 
561
    }
 
562
    return 0;
 
563
}
 
564
#endif
 
565
 
 
566
static int
 
567
_message_iter_append_dictentry(DBusMessageIter *appender,
 
568
                               DBusSignatureIter *sig_iter,
 
569
                               PyObject *dict, PyObject *key)
 
570
{
 
571
    DBusSignatureIter sub_sig_iter;
 
572
    DBusMessageIter sub;
 
573
    int ret = -1;
 
574
    PyObject *value = PyObject_GetItem(dict, key);
 
575
    dbus_bool_t more;
 
576
 
 
577
    if (!value) return -1;
 
578
 
 
579
#ifdef USING_DBG
 
580
    fprintf(stderr, "Append dictentry: ");
 
581
    PyObject_Print(key, stderr, 0);
 
582
    fprintf(stderr, " => ");
 
583
    PyObject_Print(value, stderr, 0);
 
584
    fprintf(stderr, "\n");
 
585
#endif
 
586
 
 
587
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
588
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
589
#ifdef USING_DBG
 
590
    {
 
591
        char *s;
 
592
        s = dbus_signature_iter_get_signature(sig_iter);
 
593
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
594
        dbus_free(s);
 
595
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
596
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
597
        dbus_free(s);
 
598
    }
 
599
#endif
 
600
 
 
601
    DBG("%s", "Opening DICT_ENTRY container");
 
602
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_DICT_ENTRY,
 
603
                                          NULL, &sub)) {
 
604
        PyErr_NoMemory();
 
605
        goto out;
 
606
    }
 
607
    ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more);
 
608
    if (ret == 0) {
 
609
        ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more);
 
610
    }
 
611
    DBG("%s", "Closing DICT_ENTRY container");
 
612
    if (!dbuspy_message_iter_close_container(appender, &sub, (ret == 0))) {
 
613
        PyErr_NoMemory();
 
614
        ret = -1;
 
615
    }
 
616
out:
 
617
    Py_CLEAR(value);
 
618
    return ret;
 
619
}
 
620
 
 
621
static int
 
622
_message_iter_append_multi(DBusMessageIter *appender,
 
623
                           const DBusSignatureIter *sig_iter,
 
624
                           int mode, PyObject *obj)
 
625
{
 
626
    DBusMessageIter sub_appender;
 
627
    DBusSignatureIter sub_sig_iter;
 
628
    PyObject *contents;
 
629
    int ret;
 
630
    PyObject *iterator = PyObject_GetIter(obj);
 
631
    char *sig = NULL;
 
632
    int container = mode;
 
633
    dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj);
 
634
    int inner_type;
 
635
    dbus_bool_t more;
 
636
 
 
637
    assert(mode == DBUS_TYPE_DICT_ENTRY || mode == DBUS_TYPE_ARRAY ||
 
638
            mode == DBUS_TYPE_STRUCT);
 
639
 
 
640
#ifdef USING_DBG
 
641
    fprintf(stderr, "Appending multiple: ");
 
642
    PyObject_Print(obj, stderr, 0);
 
643
    fprintf(stderr, "\n");
 
644
#endif
 
645
 
 
646
    if (!iterator) return -1;
 
647
    if (mode == DBUS_TYPE_DICT_ENTRY) container = DBUS_TYPE_ARRAY;
 
648
 
 
649
    DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
650
    dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
651
#ifdef USING_DBG
 
652
    {
 
653
        char *s;
 
654
        s = dbus_signature_iter_get_signature(sig_iter);
 
655
        DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
656
        dbus_free(s);
 
657
        s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
658
        DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
659
        dbus_free(s);
 
660
    }
 
661
#endif
 
662
    inner_type = dbus_signature_iter_get_current_type(&sub_sig_iter);
 
663
 
 
664
    if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
 
665
        sig = dbus_signature_iter_get_signature(&sub_sig_iter);
 
666
        if (!sig) {
 
667
            PyErr_NoMemory();
 
668
            ret = -1;
 
669
            goto out;
 
670
        }
 
671
    }
 
672
    /* else leave sig set to NULL. */
 
673
 
 
674
    DBG("Opening %c container", container);
 
675
    if (!dbus_message_iter_open_container(appender, container,
 
676
                                          sig, &sub_appender)) {
 
677
        PyErr_NoMemory();
 
678
        ret = -1;
 
679
        goto out;
 
680
    }
 
681
    ret = 0;
 
682
    more = TRUE;
 
683
    while ((contents = PyIter_Next(iterator))) {
 
684
 
 
685
        if (mode == DBUS_TYPE_ARRAY || mode == DBUS_TYPE_DICT_ENTRY) {
 
686
            DBG("Recursing signature iterator %p -> %p", sig_iter, &sub_sig_iter);
 
687
            dbus_signature_iter_recurse(sig_iter, &sub_sig_iter);
 
688
#ifdef USING_DBG
 
689
            {
 
690
                char *s;
 
691
                s = dbus_signature_iter_get_signature(sig_iter);
 
692
                DBG("Signature of parent iterator %p is %s", sig_iter, s);
 
693
                dbus_free(s);
 
694
                s = dbus_signature_iter_get_signature(&sub_sig_iter);
 
695
                DBG("Signature of sub-iterator %p is %s", &sub_sig_iter, s);
 
696
                dbus_free(s);
 
697
            }
 
698
#endif
 
699
        }
 
700
        else /* struct */ {
 
701
            if (!more) {
 
702
                PyErr_Format(PyExc_TypeError, "Fewer items found in struct's "
 
703
                             "D-Bus signature than in Python arguments ");
 
704
                ret = -1;
 
705
                break;
 
706
            }
 
707
        }
 
708
 
 
709
        if (mode == DBUS_TYPE_DICT_ENTRY) {
 
710
            ret = _message_iter_append_dictentry(&sub_appender, &sub_sig_iter,
 
711
                                                 obj, contents);
 
712
        }
 
713
        else if (mode == DBUS_TYPE_ARRAY && is_byte_array
 
714
                 && inner_type == DBUS_TYPE_VARIANT) {
 
715
            /* Subscripting a ByteArray gives a str of length 1, but if the
 
716
             * container is a ByteArray and the parameter is an array of
 
717
             * variants, we want to produce an array of variants containing
 
718
             * bytes, not strings.
 
719
             */
 
720
            PyObject *args = Py_BuildValue("(O)", contents);
 
721
            PyObject *byte;
 
722
 
 
723
            if (!args)
 
724
                break;
 
725
            byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL);
 
726
            Py_CLEAR(args);
 
727
            if (!byte)
 
728
                break;
 
729
            ret = _message_iter_append_variant(&sub_appender, byte);
 
730
            Py_CLEAR(byte);
 
731
        }
 
732
        else {
 
733
            /* advances sub_sig_iter and sets more on success - for array
 
734
             * this doesn't matter, for struct it's essential */
 
735
            ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter,
 
736
                                                contents, &more);
 
737
        }
 
738
 
 
739
        Py_CLEAR(contents);
 
740
        if (ret < 0) {
 
741
            break;
 
742
        }
 
743
    }
 
744
 
 
745
    if (PyErr_Occurred()) {
 
746
        ret = -1;
 
747
    }
 
748
    else if (mode == DBUS_TYPE_STRUCT && more) {
 
749
        PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus "
 
750
                     "signature than in Python arguments ");
 
751
        ret = -1;
 
752
    }
 
753
 
 
754
    /* This must be run as cleanup, even on failure. */
 
755
    DBG("Closing %c container", container);
 
756
    if (!dbuspy_message_iter_close_container(appender, &sub_appender, (ret == 0))) {
 
757
        PyErr_NoMemory();
 
758
        ret = -1;
 
759
    }
 
760
 
 
761
out:
 
762
    Py_CLEAR(iterator);
 
763
    dbus_free(sig);
 
764
    return ret;
 
765
}
 
766
 
 
767
static int
 
768
_message_iter_append_string_as_byte_array(DBusMessageIter *appender,
 
769
                                          PyObject *obj)
 
770
{
 
771
    /* a bit of a faster path for byte arrays that are strings */
 
772
    Py_ssize_t len = PyString_GET_SIZE(obj);
 
773
    const char *s;
 
774
    DBusMessageIter sub;
 
775
    int ret;
 
776
 
 
777
    s = PyString_AS_STRING(obj);
 
778
    DBG("%s", "Opening ARRAY container");
 
779
    if (!dbus_message_iter_open_container(appender, DBUS_TYPE_ARRAY,
 
780
                                          DBUS_TYPE_BYTE_AS_STRING, &sub)) {
 
781
        PyErr_NoMemory();
 
782
        return -1;
 
783
    }
 
784
    DBG("Appending fixed array of %d bytes", len);
 
785
    if (dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &s, len)) {
 
786
        ret = 0;
 
787
    }
 
788
    else {
 
789
        PyErr_NoMemory();
 
790
        ret = -1;
 
791
    }
 
792
    DBG("%s", "Closing ARRAY container");
 
793
    if (!dbus_message_iter_close_container(appender, &sub)) {
 
794
        PyErr_NoMemory();
 
795
        return -1;
 
796
    }
 
797
    return ret;
 
798
}
 
799
 
 
800
/* Encode some Python object into a D-Bus variant slot. */
 
801
static int
 
802
_message_iter_append_variant(DBusMessageIter *appender, PyObject *obj)
 
803
{
 
804
    DBusSignatureIter obj_sig_iter;
 
805
    const char *obj_sig_str;
 
806
    PyObject *obj_sig;
 
807
    int ret;
 
808
    long variant_level;
 
809
    dbus_bool_t dummy;
 
810
 
 
811
    /* Separate the object into the contained object, and the number of
 
812
     * variants it's wrapped in. */
 
813
    obj_sig = _signature_string_from_pyobject(obj, &variant_level);
 
814
    if (!obj_sig) return -1;
 
815
 
 
816
    obj_sig_str = PyString_AsString(obj_sig);
 
817
    if (!obj_sig_str) return -1;
 
818
 
 
819
    if (variant_level < 1) {
 
820
        variant_level = 1;
 
821
    }
 
822
 
 
823
    dbus_signature_iter_init(&obj_sig_iter, obj_sig_str);
 
824
 
 
825
    { /* scope for variant_iters */
 
826
        DBusMessageIter variant_iters[variant_level];
 
827
        long i;
 
828
 
 
829
        for (i = 0; i < variant_level; i++) {
 
830
            DBusMessageIter *child = &variant_iters[i];
 
831
            /* The first is a special case: its parent is the iter passed in
 
832
             * to this function, instead of being the previous one in the
 
833
             * stack
 
834
             */
 
835
            DBusMessageIter *parent = (i == 0
 
836
                                        ? appender
 
837
                                        : &(variant_iters[i-1]));
 
838
            /* The last is also a special case: it contains the actual
 
839
             * object, rather than another variant
 
840
             */
 
841
            const char *sig_str = (i == variant_level-1
 
842
                                        ? obj_sig_str
 
843
                                        : DBUS_TYPE_VARIANT_AS_STRING);
 
844
 
 
845
            DBG("Opening VARIANT container %p inside %p containing '%s'",
 
846
                child, parent, sig_str);
 
847
            if (!dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
 
848
                                                  sig_str, child)) {
 
849
                PyErr_NoMemory();
 
850
                ret = -1;
 
851
                goto out;
 
852
            }
 
853
        }
 
854
 
 
855
        /* Put the object itself into the innermost variant */
 
856
        ret = _message_iter_append_pyobject(&variant_iters[variant_level-1],
 
857
                                            &obj_sig_iter, obj, &dummy);
 
858
 
 
859
        /* here we rely on i (and variant_level) being a signed long */
 
860
        for (i = variant_level - 1; i >= 0; i--) {
 
861
            DBusMessageIter *child = &variant_iters[i];
 
862
            /* The first is a special case: its parent is the iter passed in
 
863
             * to this function, instead of being the previous one in the
 
864
             * stack
 
865
             */
 
866
            DBusMessageIter *parent = (i == 0 ? appender
 
867
                                              : &(variant_iters[i-1]));
 
868
 
 
869
            DBG("Closing VARIANT container %p inside %p", child, parent);
 
870
            if (!dbus_message_iter_close_container(parent, child)) {
 
871
                PyErr_NoMemory();
 
872
                ret = -1;
 
873
                goto out;
 
874
            }
 
875
        }
 
876
 
 
877
    }
 
878
 
 
879
out:
 
880
    Py_CLEAR(obj_sig);
 
881
    return ret;
 
882
}
 
883
 
 
884
/* On success, *more is set to whether there's more in the signature. */
 
885
static int
 
886
_message_iter_append_pyobject(DBusMessageIter *appender,
 
887
                              DBusSignatureIter *sig_iter,
 
888
                              PyObject *obj,
 
889
                              dbus_bool_t *more)
 
890
{
 
891
    int sig_type = dbus_signature_iter_get_current_type(sig_iter);
 
892
    union {
 
893
      dbus_bool_t b;
 
894
      double d;
 
895
      dbus_uint16_t uint16;
 
896
      dbus_int16_t int16;
 
897
      dbus_uint32_t uint32;
 
898
      dbus_int32_t int32;
 
899
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
 
900
      dbus_uint64_t uint64;
 
901
      dbus_int64_t int64;
 
902
#endif
 
903
    } u;
 
904
    int ret = -1;
 
905
 
 
906
#ifdef USING_DBG
 
907
    fprintf(stderr, "Appending object at %p: ", obj);
 
908
    PyObject_Print(obj, stderr, 0);
 
909
    fprintf(stderr, " into appender at %p, dbus wants type %c\n",
 
910
            appender, sig_type);
 
911
#endif
 
912
 
 
913
    switch (sig_type) {
 
914
      /* The numeric types are relatively simple to deal with, so are
 
915
       * inlined here. */
 
916
 
 
917
      case DBUS_TYPE_BOOLEAN:
 
918
          if (PyObject_IsTrue(obj)) {
 
919
              u.b = 1;
 
920
          }
 
921
          else {
 
922
              u.b = 0;
 
923
          }
 
924
          DBG("Performing actual append: bool(%ld)", (long)u.b);
 
925
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.b)) {
 
926
              PyErr_NoMemory();
 
927
              ret = -1;
 
928
              break;
 
929
          }
 
930
          ret = 0;
 
931
          break;
 
932
 
 
933
      case DBUS_TYPE_DOUBLE:
 
934
          u.d = PyFloat_AsDouble(obj);
 
935
          if (PyErr_Occurred()) {
 
936
              ret = -1;
 
937
              break;
 
938
          }
 
939
          DBG("Performing actual append: double(%f)", u.d);
 
940
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.d)) {
 
941
              PyErr_NoMemory();
 
942
              ret = -1;
 
943
              break;
 
944
          }
 
945
          ret = 0;
 
946
          break;
 
947
 
 
948
#ifdef WITH_DBUS_FLOAT32
 
949
      case DBUS_TYPE_FLOAT:
 
950
          u.d = PyFloat_AsDouble(obj);
 
951
          if (PyErr_Occurred()) {
 
952
              ret = -1;
 
953
              break;
 
954
          }
 
955
          u.f = (float)u.d;
 
956
          DBG("Performing actual append: float(%f)", u.f);
 
957
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.f)) {
 
958
              PyErr_NoMemory();
 
959
              ret = -1;
 
960
              break;
 
961
          }
 
962
          ret = 0;
 
963
          break;
 
964
#endif
 
965
 
 
966
          /* The integer types are all basically the same - we delegate to
 
967
          intNN_range_check() */
 
968
#define PROCESS_INTEGER(size) \
 
969
          u.size = dbus_py_##size##_range_check(obj);\
 
970
          if (u.size == (dbus_##size##_t)(-1) && PyErr_Occurred()) {\
 
971
              ret = -1; \
 
972
              break; \
 
973
          }\
 
974
          DBG("Performing actual append: " #size "(%lld)", (long long)u.size); \
 
975
          if (!dbus_message_iter_append_basic(appender, sig_type, &u.size)) {\
 
976
              PyErr_NoMemory();\
 
977
              ret = -1;\
 
978
              break;\
 
979
          } \
 
980
          ret = 0;
 
981
 
 
982
      case DBUS_TYPE_INT16:
 
983
          PROCESS_INTEGER(int16)
 
984
          break;
 
985
      case DBUS_TYPE_UINT16:
 
986
          PROCESS_INTEGER(uint16)
 
987
          break;
 
988
      case DBUS_TYPE_INT32:
 
989
          PROCESS_INTEGER(int32)
 
990
          break;
 
991
      case DBUS_TYPE_UINT32:
 
992
          PROCESS_INTEGER(uint32)
 
993
          break;
 
994
#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG)
 
995
      case DBUS_TYPE_INT64:
 
996
          PROCESS_INTEGER(int64)
 
997
          break;
 
998
      case DBUS_TYPE_UINT64:
 
999
          PROCESS_INTEGER(uint64)
 
1000
          break;
 
1001
#else
 
1002
      case DBUS_TYPE_INT64:
 
1003
      case DBUS_TYPE_UINT64:
 
1004
          PyErr_SetString(PyExc_NotImplementedError, "64-bit integer "
 
1005
                          "types are not supported on this platform");
 
1006
          ret = -1;
 
1007
          break;
 
1008
#endif
 
1009
#undef PROCESS_INTEGER
 
1010
 
 
1011
      /* Now the more complicated cases, which are delegated to helper
 
1012
       * functions (although in practice, the compiler will hopefully
 
1013
       * inline them anyway). */
 
1014
 
 
1015
      case DBUS_TYPE_STRING:
 
1016
      case DBUS_TYPE_SIGNATURE:
 
1017
      case DBUS_TYPE_OBJECT_PATH:
 
1018
          ret = _message_iter_append_string(appender, sig_type, obj, TRUE);
 
1019
          break;
 
1020
 
 
1021
      case DBUS_TYPE_BYTE:
 
1022
          ret = _message_iter_append_byte(appender, obj);
 
1023
          break;
 
1024
 
 
1025
      case DBUS_TYPE_ARRAY:
 
1026
          /* 3 cases - it might actually be a dict, or it might be a byte array
 
1027
           * being copied from a string (for which we have a faster path),
 
1028
           * or it might be a generic array. */
 
1029
 
 
1030
          sig_type = dbus_signature_iter_get_element_type(sig_iter);
 
1031
          if (sig_type == DBUS_TYPE_DICT_ENTRY)
 
1032
            ret = _message_iter_append_multi(appender, sig_iter,
 
1033
                                             DBUS_TYPE_DICT_ENTRY, obj);
 
1034
          else if (sig_type == DBUS_TYPE_BYTE && PyString_Check(obj))
 
1035
            ret = _message_iter_append_string_as_byte_array(appender, obj);
 
1036
          else
 
1037
            ret = _message_iter_append_multi(appender, sig_iter,
 
1038
                                             DBUS_TYPE_ARRAY, obj);
 
1039
          DBG("_message_iter_append_multi(): %d", ret);
 
1040
          break;
 
1041
 
 
1042
      case DBUS_TYPE_STRUCT:
 
1043
          ret = _message_iter_append_multi(appender, sig_iter, sig_type, obj);
 
1044
          break;
 
1045
 
 
1046
      case DBUS_TYPE_VARIANT:
 
1047
          ret = _message_iter_append_variant(appender, obj);
 
1048
          break;
 
1049
 
 
1050
      case DBUS_TYPE_INVALID:
 
1051
          PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
 
1052
                          "signature than in Python arguments");
 
1053
          ret = -1;
 
1054
          break;
 
1055
 
 
1056
#if defined(DBUS_TYPE_UNIX_FD)
 
1057
      case DBUS_TYPE_UNIX_FD:
 
1058
          ret = _message_iter_append_unixfd(appender, obj);
 
1059
          break;
 
1060
#endif
 
1061
 
 
1062
      default:
 
1063
          PyErr_Format(PyExc_TypeError, "Unknown type '\\x%x' in D-Bus "
 
1064
                       "signature", sig_type);
 
1065
          ret = -1;
 
1066
          break;
 
1067
    }
 
1068
    if (ret < 0) return -1;
 
1069
 
 
1070
    DBG("Advancing signature iter at %p", sig_iter);
 
1071
    *more = dbus_signature_iter_next(sig_iter);
 
1072
#ifdef USING_DBG
 
1073
    DBG("- result: %ld, type %02x '%c'", (long)(*more),
 
1074
        (int)dbus_signature_iter_get_current_type(sig_iter),
 
1075
        (int)dbus_signature_iter_get_current_type(sig_iter));
 
1076
#endif
 
1077
    return 0;
 
1078
}
 
1079
 
 
1080
 
 
1081
PyObject *
 
1082
dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs)
 
1083
{
 
1084
    const char *signature = NULL;
 
1085
    PyObject *signature_obj = NULL;
 
1086
    DBusSignatureIter sig_iter;
 
1087
    DBusMessageIter appender;
 
1088
    static char *argnames[] = {"signature", NULL};
 
1089
    dbus_bool_t more;
 
1090
 
 
1091
    if (!self->msg) return DBusPy_RaiseUnusableMessage();
 
1092
 
 
1093
#ifdef USING_DBG
 
1094
    fprintf(stderr, "DBG/%ld: called Message_append(*", (long)getpid());
 
1095
    PyObject_Print(args, stderr, 0);
 
1096
    if (kwargs) {
 
1097
        fprintf(stderr, ", **");
 
1098
        PyObject_Print(kwargs, stderr, 0);
 
1099
    }
 
1100
    fprintf(stderr, ")\n");
 
1101
#endif
 
1102
 
 
1103
    /* only use kwargs for this step: deliberately ignore args for now */
 
1104
    if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, "|z:append",
 
1105
                                     argnames, &signature)) return NULL;
 
1106
 
 
1107
    if (!signature) {
 
1108
        DBG("%s", "No signature for message, guessing...");
 
1109
        signature_obj = dbus_py_Message_guess_signature(NULL, args);
 
1110
        if (!signature_obj) return NULL;
 
1111
        signature = PyString_AS_STRING(signature_obj);
 
1112
    }
 
1113
    /* from here onwards, you have to do a goto rather than returning NULL
 
1114
    to make sure signature_obj gets freed */
 
1115
 
 
1116
    /* iterate over args and the signature, together */
 
1117
    if (!dbus_signature_validate(signature, NULL)) {
 
1118
        PyErr_SetString(PyExc_ValueError, "Corrupt type signature");
 
1119
        goto err;
 
1120
    }
 
1121
    dbus_message_iter_init_append(self->msg, &appender);
 
1122
 
 
1123
    if (signature[0] != '\0') {
 
1124
        int i = 0;
 
1125
 
 
1126
        more = TRUE;
 
1127
        dbus_signature_iter_init(&sig_iter, signature);
 
1128
        while (more) {
 
1129
            if (i >= PyTuple_GET_SIZE(args)) {
 
1130
                PyErr_SetString(PyExc_TypeError, "More items found in D-Bus "
 
1131
                                "signature than in Python arguments");
 
1132
                goto hosed;
 
1133
            }
 
1134
            if (_message_iter_append_pyobject(&appender, &sig_iter,
 
1135
                                              PyTuple_GET_ITEM(args, i),
 
1136
                                              &more) < 0) {
 
1137
                goto hosed;
 
1138
            }
 
1139
            i++;
 
1140
        }
 
1141
        if (i < PyTuple_GET_SIZE(args)) {
 
1142
            PyErr_SetString(PyExc_TypeError, "Fewer items found in D-Bus "
 
1143
                    "signature than in Python arguments");
 
1144
            goto hosed;
 
1145
        }
 
1146
    }
 
1147
 
 
1148
    /* success! */
 
1149
    Py_CLEAR(signature_obj);
 
1150
    Py_RETURN_NONE;
 
1151
 
 
1152
hosed:
 
1153
    /* "If appending any of the arguments fails due to lack of memory,
 
1154
     * generally the message is hosed and you have to start over" -libdbus docs
 
1155
     * Enforce this by throwing away the message structure.
 
1156
     */
 
1157
    dbus_message_unref(self->msg);
 
1158
    self->msg = NULL;
 
1159
err:
 
1160
    Py_CLEAR(signature_obj);
 
1161
    return NULL;
 
1162
}
 
1163
 
 
1164
/* vim:set ft=c cino< sw=4 sts=4 et: */