2003-10-28 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-message.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c  DBusMessage object
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  * Copyright (C) 2002, 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-internals.h"
26 #include "dbus-marshal.h"
27 #include "dbus-message.h"
28 #include "dbus-message-internal.h"
29 #include "dbus-memory.h"
30 #include "dbus-list.h"
31 #include "dbus-message-builder.h"
32 #include "dbus-dataslot.h"
33 #include <string.h>
34
35 /**
36  * @defgroup DBusMessageInternals DBusMessage implementation details
37  * @ingroup DBusInternals
38  * @brief DBusMessage private implementation details.
39  *
40  * The guts of DBusMessage and its methods.
41  *
42  * @{
43  */
44
45 /**
46  * Cached information about a header field in the message
47  */
48 typedef struct
49 {
50   int name_offset;  /**< Offset to name of field */
51   int value_offset; /**< Offset to value of field */
52 } HeaderField;
53
54 /** Offset to byte order from start of header */
55 #define BYTE_ORDER_OFFSET    0
56 /** Offset to type from start of header */
57 #define TYPE_OFFSET          1
58 /** Offset to flags from start of header */
59 #define FLAGS_OFFSET         2
60 /** Offset to version from start of header */
61 #define VERSION_OFFSET       3
62 /** Offset to header length from start of header */
63 #define HEADER_LENGTH_OFFSET 4
64 /** Offset to body length from start of header */
65 #define BODY_LENGTH_OFFSET   8
66 /** Offset to client serial from start of header */
67 #define CLIENT_SERIAL_OFFSET 12
68
69
70 /**
71  * @brief Internals of DBusMessage
72  * 
73  * Object representing a message received from or to be sent to
74  * another application. This is an opaque object, all members
75  * are private.
76  */
77 struct DBusMessage
78 {
79   DBusAtomic refcount; /**< Reference count */
80
81   DBusString header; /**< Header network data, stored
82                       * separately from body so we can
83                       * independently realloc it.
84                       */
85
86   HeaderField header_fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location
87                                                           * of each field in "header"
88                                                           */
89
90   dbus_uint32_t client_serial; /**< Cached client serial value for speed */
91   dbus_uint32_t reply_serial;  /**< Cached reply serial value for speed */
92   
93   int header_padding; /**< bytes of alignment in header */
94   
95   DBusString body;   /**< Body network data. */
96
97   char byte_order; /**< Message byte order. */
98
99   DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */
100   long size_counter_delta;   /**< Size we incremented the size counters by.   */
101
102   dbus_uint32_t changed_stamp; /**< Incremented when iterators are invalidated. */
103   
104   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
105
106   DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */
107
108   DBusString signature; /**< Signature */
109 };
110
111 enum {
112   DBUS_MESSAGE_ITER_TYPE_MESSAGE,
113   DBUS_MESSAGE_ITER_TYPE_ARRAY,
114   DBUS_MESSAGE_ITER_TYPE_DICT
115 };
116
117 /** typedef for internals of message iterator */
118 typedef struct DBusMessageRealIter DBusMessageRealIter;
119
120 /**
121  * @brief Internals of DBusMessageIter
122  * 
123  * Object representing a position in a message. All fields are internal.
124  */
125 struct DBusMessageRealIter
126 {
127   DBusMessageRealIter *parent_iter; /**< parent iter, or NULL */
128   DBusMessage *message; /**< Message used */
129   dbus_uint32_t changed_stamp; /**< stamp to detect invalid iters */
130   
131   /* This is an int instead of an enum to get a guaranteed size for the dummy: */
132   int type; /**< type of iter */
133   
134   int pos; /**< Current position in the string */
135   int end; /**< position right after the container */
136   int container_start; /**< offset of the start of the container */
137   int container_length_pos; /**< offset of the length of the container */
138   
139   int wrote_dict_key; /**< whether we wrote the dict key for the current dict element */
140
141   int array_type_pos; /**< pointer to the position of the array element type */
142   int array_type_done; /**< TRUE if the array type is fully finished */
143 };
144
145 /**
146  * Gets the data to be sent over the network for this message.
147  * The header and then the body should be written out.
148  * This function is guaranteed to always return the same
149  * data once a message is locked (with _dbus_message_lock()).
150  *
151  * @param message the message.
152  * @param header return location for message header data.
153  * @param body return location for message body data.
154  */
155 void
156 _dbus_message_get_network_data (DBusMessage          *message,
157                                 const DBusString    **header,
158                                 const DBusString    **body)
159 {
160   _dbus_assert (message->locked);
161   
162   *header = &message->header;
163   *body = &message->body;
164 }
165
166 static void
167 clear_header_padding (DBusMessage *message)
168 {
169   _dbus_string_shorten (&message->header,
170                         message->header_padding);
171   message->header_padding = 0;
172 }              
173
174 static dbus_bool_t
175 append_header_padding (DBusMessage *message)
176 {
177   int old_len;
178   old_len = _dbus_string_get_length (&message->header);
179   if (!_dbus_string_align_length (&message->header, 8))
180     return FALSE;
181
182   message->header_padding = _dbus_string_get_length (&message->header) - old_len;
183
184   return TRUE;
185 }
186
187 #ifdef DBUS_BUILD_TESTS
188 /* tests-only until it's actually used */
189 static dbus_int32_t
190 get_int_field (DBusMessage *message,
191                int          field)
192 {
193   int offset;
194
195   _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
196   
197   offset = message->header_fields[field].value_offset;
198   
199   if (offset < 0)
200     return -1; /* useless if -1 is a valid value of course */
201   
202   return _dbus_demarshal_int32 (&message->header,
203                                 message->byte_order,
204                                 offset,
205                                 NULL);
206 }
207 #endif
208
209 static dbus_uint32_t
210 get_uint_field (DBusMessage *message,
211                 int          field)
212 {
213   int offset;
214   
215   _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
216   
217   offset = message->header_fields[field].value_offset;
218   
219   if (offset < 0)
220     return 0; /* useless if 0 is a valid value of course */
221   
222   return _dbus_demarshal_uint32 (&message->header,
223                                  message->byte_order,
224                                  offset,
225                                  NULL);
226 }
227
228 static const char*
229 get_string_field (DBusMessage *message,
230                   int          field,
231                   int         *len)
232 {
233   int offset;
234   const char *data;
235
236   offset = message->header_fields[field].value_offset;
237
238   _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
239   
240   if (offset < 0)
241     return NULL;
242
243   /* offset points to string length, string data follows it */
244   /* FIXME _dbus_demarshal_const_string() that returned
245    * a reference to the string plus its len might be nice.
246    */
247   
248   if (len)
249     *len = _dbus_demarshal_uint32 (&message->header,
250                                    message->byte_order,
251                                    offset,
252                                    NULL);
253
254   data = _dbus_string_get_const_data (&message->header);
255   
256   return data + (offset + 4); 
257 }
258
259 /* returns FALSE if no memory, TRUE with NULL path if no field */
260 static dbus_bool_t
261 get_path_field_decomposed (DBusMessage  *message,
262                            int           field,
263                            char       ***path)
264 {
265   int offset;
266
267   offset = message->header_fields[field].value_offset;
268
269   _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
270   
271   if (offset < 0)
272     {
273       *path = NULL;
274       return TRUE;
275     }
276
277   return _dbus_demarshal_object_path (&message->header,
278                                       message->byte_order,
279                                       offset,
280                                       NULL,
281                                       path, NULL);
282 }
283
284 #ifdef DBUS_BUILD_TESTS
285 static dbus_bool_t
286 append_int_field (DBusMessage *message,
287                   int          field,
288                   int          value)
289 {
290   _dbus_assert (!message->locked);
291
292   clear_header_padding (message);
293   
294   message->header_fields[field].name_offset =
295     _dbus_string_get_length (&message->header);
296   
297   if (!_dbus_string_append_byte (&message->header, field))
298     goto failed;
299
300   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
301     goto failed;
302
303   if (!_dbus_string_align_length (&message->header, 4))
304     goto failed;
305   
306   message->header_fields[field].value_offset =
307     _dbus_string_get_length (&message->header);
308   
309   if (!_dbus_marshal_int32 (&message->header, message->byte_order,
310                             value))
311     goto failed;
312
313   if (!append_header_padding (message))
314     goto failed;
315   
316   return TRUE;
317   
318  failed:
319   _dbus_string_set_length (&message->header,
320                            message->header_fields[field].name_offset);
321   message->header_fields[field].name_offset  = -1;
322   message->header_fields[field].value_offset = -1;
323
324   /* this must succeed because it was allocated on function entry and
325    * DBusString doesn't ever realloc smaller
326    */
327   if (!append_header_padding (message))
328     _dbus_assert_not_reached ("failed to reappend header padding");
329   return FALSE;
330 }
331 #endif
332
333 static dbus_bool_t
334 append_uint_field (DBusMessage *message,
335                    int          field,
336                    int          value)
337 {
338   _dbus_assert (!message->locked);
339
340   clear_header_padding (message);
341   
342   message->header_fields[field].name_offset =
343     _dbus_string_get_length (&message->header);
344   
345   if (!_dbus_string_append_byte (&message->header, field))
346     goto failed;
347
348   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32))
349     goto failed;
350
351   if (!_dbus_string_align_length (&message->header, 4))
352     goto failed;
353   
354   message->header_fields[field].value_offset =
355     _dbus_string_get_length (&message->header);
356   
357   if (!_dbus_marshal_uint32 (&message->header, message->byte_order,
358                              value))
359     goto failed;
360
361   if (!append_header_padding (message))
362     goto failed;
363   
364   return TRUE;
365   
366  failed:
367   _dbus_string_set_length (&message->header,
368                            message->header_fields[field].name_offset);
369   message->header_fields[field].name_offset  = -1;
370   message->header_fields[field].value_offset = -1;
371
372   /* this must succeed because it was allocated on function entry and
373    * DBusString doesn't ever realloc smaller
374    */
375   if (!append_header_padding (message))
376     _dbus_assert_not_reached ("failed to reappend header padding");
377   return FALSE;
378 }
379
380 #define MAX_BYTES_OVERHEAD_TO_APPEND_A_STRING (1 + 1 + 3 + 1 + 8)
381 static dbus_bool_t
382 append_string_field (DBusMessage *message,
383                      int          field,
384                      int          type,
385                      const char  *value)
386 {
387   _dbus_assert (!message->locked);
388
389   clear_header_padding (message);
390   
391   message->header_fields[field].name_offset =
392     _dbus_string_get_length (&message->header);
393   
394   if (!_dbus_string_append_byte (&message->header, field))
395     goto failed;
396   
397   if (!_dbus_string_append_byte (&message->header, type))
398     goto failed;
399
400   if (!_dbus_string_align_length (&message->header, 4))
401     goto failed;
402   
403   message->header_fields[field].value_offset =
404     _dbus_string_get_length (&message->header);
405   
406   if (!_dbus_marshal_string (&message->header, message->byte_order,
407                              value))
408     goto failed;
409
410   if (!append_header_padding (message))
411     goto failed;
412   
413   return TRUE;
414   
415  failed:
416   _dbus_string_set_length (&message->header,
417                            message->header_fields[field].name_offset);
418   message->header_fields[field].name_offset  = -1;
419   message->header_fields[field].value_offset = -1;
420
421   /* this must succeed because it was allocated on function entry and
422    * DBusString doesn't ever realloc smaller
423    */
424   if (!append_header_padding (message))
425     _dbus_assert_not_reached ("failed to reappend header padding");
426   
427   return FALSE;
428 }
429
430 static int
431 get_type_alignment (int type)
432 {
433   int alignment;
434   
435   switch (type)
436     {
437     case DBUS_TYPE_NIL:
438     case DBUS_TYPE_BYTE:
439     case DBUS_TYPE_BOOLEAN:
440       alignment = 0;
441       break;
442
443     case DBUS_TYPE_INT32:
444     case DBUS_TYPE_UINT32:
445     case DBUS_TYPE_STRING:
446     case DBUS_TYPE_OBJECT_PATH:
447       /* These are aligned 4 because they have a length as the
448        * first field;
449        */
450     case DBUS_TYPE_CUSTOM:
451     case DBUS_TYPE_DICT:
452       alignment = 4;
453       break;
454
455     case DBUS_TYPE_INT64:
456     case DBUS_TYPE_UINT64:
457     case DBUS_TYPE_DOUBLE:
458       alignment = 8;
459       break;
460
461     case DBUS_TYPE_ARRAY:
462       _dbus_assert_not_reached ("passed an ARRAY type to get_type_alignment()");
463       break;
464
465     case DBUS_TYPE_INVALID:
466     default:
467       _dbus_assert_not_reached ("passed an invalid or unknown type to get_type_alignment()");
468       break;
469     }
470
471   return alignment;
472 }
473
474 static dbus_bool_t
475 iterate_one_field (const DBusString *str,
476                    int               byte_order,
477                    int               name_offset,
478                    int              *next_offset_p,
479                    int              *field_name_p,
480                    DBusString       *append_copy_to,
481                    int              *copy_name_offset_p,
482                    int              *copy_value_offset_p)
483 {
484   int name, type, array_type;
485   int alignment;
486   int type_len;
487   int type_pos;
488   int value_pos;
489   int value_len;
490   int value_end;
491   int pos;
492
493   _dbus_verbose ("%s: name_offset=%d, append to %p\n",
494                  _DBUS_FUNCTION_NAME, name_offset, append_copy_to);
495   
496   pos = name_offset;
497   
498   name = _dbus_string_get_byte (str, name_offset);
499   pos++;
500
501   type_pos = pos;
502   type = _dbus_string_get_byte (str, type_pos);
503   pos++;
504   type_len = 1;
505
506   array_type = type;
507   /* find out the type of our array */
508   while (array_type == DBUS_TYPE_ARRAY)
509     {
510       pos++;
511       type_len++;
512       array_type = _dbus_string_get_byte (str, pos);
513     }
514
515   _dbus_verbose ("%s: name %d, type '%c' %d at %d len %d, array type '%c' %d\n",
516                  _DBUS_FUNCTION_NAME,
517                  name, type, type, type_pos, type_len, array_type, array_type);
518   
519 #ifndef DBUS_DISABLE_ASSERT
520   if (!_dbus_type_is_valid (array_type))
521     {
522       _dbus_warn ("type '%c' %d is not valid in %s\n",
523                   array_type, array_type, _DBUS_FUNCTION_NAME);
524       _dbus_assert_not_reached ("invalid type");
525     }
526 #endif
527       
528   alignment = get_type_alignment (array_type);
529       
530   if (alignment > 0)
531     pos = _DBUS_ALIGN_VALUE (pos, alignment);
532
533   _dbus_verbose ("%s: alignment %d value at pos %d\n",
534                  _DBUS_FUNCTION_NAME, alignment, pos);
535   
536   /* pos now points to our value */
537   if (!_dbus_marshal_get_arg_end_pos (str, byte_order,
538                                       type, pos, &value_end))
539     _dbus_assert_not_reached ("failed to get the byte after this header");
540
541   value_pos = pos;
542   value_len = value_end - value_pos;
543
544   _dbus_verbose ("%s: value_pos %d value_len %d value_end %d\n",
545                  _DBUS_FUNCTION_NAME, value_pos, value_len, value_end);
546   
547   if (next_offset_p)
548     *next_offset_p = pos + value_len;
549
550   if (field_name_p)
551     *field_name_p = name;
552
553   if (append_copy_to)
554     {
555       int orig_len;
556
557       orig_len = _dbus_string_get_length (append_copy_to);
558
559       if (copy_name_offset_p)
560         *copy_name_offset_p = orig_len;
561       
562       if (!_dbus_string_append_byte (append_copy_to, name))
563         goto failed_copy;
564
565       if (!_dbus_string_copy_len (str, type_pos, type_len,
566                                   append_copy_to,
567                                   _dbus_string_get_length (append_copy_to)))
568         goto failed_copy;
569
570       if (!_dbus_string_align_length (append_copy_to, alignment))
571         goto failed_copy;
572
573       if (copy_value_offset_p)
574         *copy_value_offset_p = _dbus_string_get_length (append_copy_to);
575       
576       if (!_dbus_string_copy_len (str, value_pos, value_len,
577                                   append_copy_to,
578                                   _dbus_string_get_length (append_copy_to)))
579         goto failed_copy;
580       
581       return TRUE;
582
583     failed_copy:
584       _dbus_verbose ("%s: Failed copying old fields to new string\n",
585                      _DBUS_FUNCTION_NAME);
586       _dbus_string_set_length (append_copy_to, orig_len);
587       return FALSE;
588     }
589   else
590     return TRUE;
591 }
592
593 #ifndef DBUS_DISABLE_ASSERT
594 static void
595 verify_header_fields (DBusMessage *message)
596 {
597   int i;
598   i = 0;
599   while (i < DBUS_HEADER_FIELD_LAST)
600     {
601       if (message->header_fields[i].name_offset >= 0)
602         _dbus_assert (_dbus_string_get_byte (&message->header,
603                                              message->header_fields[i].name_offset) ==
604                       i);
605       ++i;
606     }
607 }
608 #else /* DBUS_DISABLE_ASSERT */
609 #define verify_header_fields(x)
610 #endif /* DBUS_DISABLE_ASSERT */
611
612 /* In this function we delete one field and re-align all the fields
613  * following it.
614  */
615 static dbus_bool_t
616 delete_one_and_re_align (DBusMessage *message,
617                          int          name_offset_to_delete)
618 {
619   DBusString copy;
620   int new_fields_front_padding;
621   int next_offset;
622   int field_name;
623   dbus_bool_t retval;
624   HeaderField new_header_fields[DBUS_HEADER_FIELD_LAST];
625   
626   _dbus_assert (name_offset_to_delete < _dbus_string_get_length (&message->header));
627   verify_header_fields (message);
628
629   _dbus_verbose ("%s: Deleting one field at offset %d\n",
630                  _DBUS_FUNCTION_NAME,
631                  name_offset_to_delete);
632   
633   retval = FALSE;
634
635   clear_header_padding (message);
636   
637   if (!_dbus_string_init_preallocated (&copy,
638                                        _dbus_string_get_length (&message->header) -
639                                        name_offset_to_delete + 8))
640     {
641       _dbus_verbose ("%s: Failed to init string to hold copy of fields\n",
642                      _DBUS_FUNCTION_NAME);
643       goto out_0;
644     }
645   
646   /* Align the name offset of the first field in the same way it's
647    * aligned in the real header
648    */
649   new_fields_front_padding = name_offset_to_delete % 8;
650
651   if (!_dbus_string_insert_bytes (&copy, 0, new_fields_front_padding,
652                                   '\0'))
653     _dbus_assert_not_reached ("Should not have failed to insert bytes into preallocated string\n");
654
655   memcpy (new_header_fields, message->header_fields,
656           sizeof (new_header_fields));
657   
658   /* Now just re-marshal each field in the header to our temporary
659    * buffer, skipping the first one. The tricky part is that the
660    * fields are padded as if for previous_name_offset, but are in fact
661    * at unaligned_name_offset
662    */
663
664   if (!iterate_one_field (&message->header,
665                           message->byte_order,
666                           name_offset_to_delete,
667                           &next_offset,
668                           &field_name, NULL, NULL, NULL))
669     _dbus_assert_not_reached ("shouldn't have failed to alloc memory to skip the deleted field");
670
671   if (field_name < DBUS_HEADER_FIELD_LAST)
672     {
673       new_header_fields[field_name].name_offset = -1;
674       new_header_fields[field_name].value_offset = -1;
675     }
676   
677   while (next_offset < _dbus_string_get_length (&message->header))
678     {
679       int copy_name_offset;
680       int copy_value_offset;
681
682       if (!iterate_one_field (&message->header,
683                               message->byte_order,
684                               next_offset,
685                               &next_offset,
686                               &field_name,
687                               &copy,
688                               &copy_name_offset,
689                               &copy_value_offset))
690         {
691           _dbus_verbose ("%s: OOM iterating one field\n",
692                          _DBUS_FUNCTION_NAME);
693           goto out_1;
694         }
695       
696       if (field_name < DBUS_HEADER_FIELD_LAST)
697         {
698           new_header_fields[field_name].name_offset = copy_name_offset - new_fields_front_padding + name_offset_to_delete;
699           new_header_fields[field_name].value_offset = copy_value_offset - new_fields_front_padding + name_offset_to_delete;
700         }
701     }
702
703   if (!_dbus_string_replace_len (&copy,
704                                  new_fields_front_padding,
705                                  _dbus_string_get_length (&copy) - new_fields_front_padding,
706                                  &message->header,
707                                  name_offset_to_delete,
708                                  _dbus_string_get_length (&message->header) - name_offset_to_delete))
709     {
710       _dbus_verbose ("%s: OOM moving copy back into header\n",
711                      _DBUS_FUNCTION_NAME);
712       goto out_1;
713     }
714   
715   memcpy (message->header_fields, new_header_fields,
716           sizeof (new_header_fields));
717   verify_header_fields (message);
718   
719   retval = TRUE;
720   
721  out_1:
722   _dbus_string_free (&copy);
723   
724  out_0:
725   if (!append_header_padding (message))
726     _dbus_assert_not_reached ("Failed to re-append header padding in re_align_field_recurse()");
727   
728   return retval;
729 }
730
731 static dbus_bool_t
732 delete_field (DBusMessage *message,
733               int          field,
734               int          prealloc_header_space)
735 {
736   int offset;
737
738   _dbus_assert (!message->locked);
739
740   /* Prealloc */
741   if (!_dbus_string_lengthen (&message->header, prealloc_header_space))
742     {
743       _dbus_verbose ("failed to prealloc %d bytes header space\n",
744                      prealloc_header_space);
745       return FALSE;
746     }
747   _dbus_string_shorten (&message->header, prealloc_header_space);
748
749   /* Delete */
750   offset = message->header_fields[field].name_offset;
751   if (offset < 0)
752     {
753       _dbus_verbose ("header field didn't exist, no need to delete\n");
754       return TRUE; /* field didn't exist */
755     }
756
757   return delete_one_and_re_align (message, offset);
758 }
759
760 #ifdef DBUS_BUILD_TESTS
761 static dbus_bool_t
762 set_int_field (DBusMessage *message,
763                int          field,
764                int          value)
765 {
766   int offset = message->header_fields[field].value_offset;
767
768   _dbus_assert (!message->locked);
769   
770   if (offset < 0)
771     {
772       /* need to append the field */
773       return append_int_field (message, field, value);
774     }
775   else
776     {
777       _dbus_marshal_set_int32 (&message->header,
778                                message->byte_order,
779                                offset, value);
780
781       return TRUE;
782     }
783 }
784 #endif
785
786 static dbus_bool_t
787 set_uint_field (DBusMessage  *message,
788                 int           field,
789                 dbus_uint32_t value)
790 {
791   int offset = message->header_fields[field].value_offset;
792
793   _dbus_assert (!message->locked);
794   
795   if (offset < 0)
796     {
797       /* need to append the field */
798       return append_uint_field (message, field, value);
799     }
800   else
801     {
802       _dbus_marshal_set_uint32 (&message->header,
803                                 message->byte_order,
804                                 offset, value);
805
806       return TRUE;
807     }
808 }
809
810 static dbus_bool_t
811 set_string_field (DBusMessage *message,
812                   int          field,
813                   int          type,
814                   const char  *value)
815 {
816   int prealloc;
817   
818   _dbus_assert (!message->locked);
819
820   /* the prealloc is so the append_string_field()
821    * below won't fail, leaving us in inconsistent state
822    */
823   prealloc = (value ? strlen (value) : 0) + MAX_BYTES_OVERHEAD_TO_APPEND_A_STRING;
824
825   _dbus_verbose ("set_string_field() field %d prealloc %d\n",
826                  field, prealloc);
827   
828   if (!delete_field (message, field, prealloc))
829     return FALSE;
830
831   if (value != NULL)
832     {
833       /* need to append the field */
834       if (!append_string_field (message, field, type, value))
835         _dbus_assert_not_reached ("Appending string field shouldn't have failed, due to preallocation");
836     }
837   
838   return TRUE;
839 }
840
841 /**
842  * Sets the serial number of a message. 
843  * This can only be done once on a message.
844  * 
845  * @param message the message
846  * @param serial the serial
847  */
848 void
849 _dbus_message_set_serial (DBusMessage  *message,
850                           dbus_int32_t  serial)
851 {
852   _dbus_assert (!message->locked);
853   _dbus_assert (dbus_message_get_serial (message) == 0);
854
855   _dbus_marshal_set_uint32 (&message->header,
856                             message->byte_order,
857                             CLIENT_SERIAL_OFFSET,
858                             serial);
859
860   message->client_serial = serial;
861 }
862
863 /**
864  * Sets the reply serial of a message (the client serial
865  * of the message this is a reply to).
866  *
867  * @param message the message
868  * @param reply_serial the client serial
869  * @returns #FALSE if not enough memory
870  */
871 dbus_bool_t
872 dbus_message_set_reply_serial (DBusMessage   *message,
873                                dbus_uint32_t  reply_serial)
874 {
875   _dbus_assert (!message->locked);
876
877   if (set_uint_field (message,
878                       DBUS_HEADER_FIELD_REPLY_SERIAL,
879                       reply_serial))
880     {
881       message->reply_serial = reply_serial;
882       return TRUE;
883     }
884   else
885     return FALSE;
886 }
887
888 /**
889  * Returns the serial of a message or 0 if none has been specified.
890  * The message's serial number is provided by the application sending
891  * the message and is used to identify replies to this message.  All
892  * messages received on a connection will have a serial, but messages
893  * you haven't sent yet may return 0.
894  *
895  * @param message the message
896  * @returns the client serial
897  */
898 dbus_uint32_t
899 dbus_message_get_serial (DBusMessage *message)
900 {
901   return message->client_serial;
902 }
903
904 /**
905  * Returns the serial that the message is a reply to or 0 if none.
906  *
907  * @param message the message
908  * @returns the reply serial
909  */
910 dbus_uint32_t
911 dbus_message_get_reply_serial  (DBusMessage *message)
912 {
913   return message->reply_serial;
914 }
915
916 /**
917  * Adds a counter to be incremented immediately with the
918  * size of this message, and decremented by the size
919  * of this message when this message if finalized.
920  * The link contains a counter with its refcount already
921  * incremented, but the counter itself not incremented.
922  * Ownership of link and counter refcount is passed to
923  * the message.
924  *
925  * @param message the message
926  * @param link link with counter as data
927  */
928 void
929 _dbus_message_add_size_counter_link (DBusMessage  *message,
930                                      DBusList     *link)
931 {
932   /* right now we don't recompute the delta when message
933    * size changes, and that's OK for current purposes
934    * I think, but could be important to change later.
935    * Do recompute it whenever there are no outstanding counters,
936    * since it's basically free.
937    */
938   if (message->size_counters == NULL)
939     {
940       message->size_counter_delta =
941         _dbus_string_get_length (&message->header) +
942         _dbus_string_get_length (&message->body);
943       
944 #if 0
945       _dbus_verbose ("message has size %ld\n",
946                      message->size_counter_delta);
947 #endif
948     }
949   
950   _dbus_list_append_link (&message->size_counters, link);
951   
952   _dbus_counter_adjust (link->data, message->size_counter_delta);
953 }
954
955 /**
956  * Adds a counter to be incremented immediately with the
957  * size of this message, and decremented by the size
958  * of this message when this message if finalized.
959  *
960  * @param message the message
961  * @param counter the counter
962  * @returns #FALSE if no memory
963  */
964 dbus_bool_t
965 _dbus_message_add_size_counter (DBusMessage *message,
966                                 DBusCounter *counter)
967 {
968   DBusList *link;
969
970   link = _dbus_list_alloc_link (counter);
971   if (link == NULL)
972     return FALSE;
973
974   _dbus_counter_ref (counter);
975   _dbus_message_add_size_counter_link (message, link);
976
977   return TRUE;
978 }
979
980 /**
981  * Removes a counter tracking the size of this message, and decrements
982  * the counter by the size of this message.
983  *
984  * @param message the message
985  * @param link_return return the link used
986  * @param counter the counter
987  */
988 void
989 _dbus_message_remove_size_counter (DBusMessage  *message,
990                                    DBusCounter  *counter,
991                                    DBusList    **link_return)
992 {
993   DBusList *link;
994
995   link = _dbus_list_find_last (&message->size_counters,
996                                counter);
997   _dbus_assert (link != NULL);
998
999   _dbus_list_unlink (&message->size_counters,
1000                      link);
1001   if (link_return)
1002     *link_return = link;
1003   else
1004     _dbus_list_free_link (link);
1005
1006   _dbus_counter_adjust (counter, message->size_counter_delta);
1007
1008   _dbus_counter_unref (counter);
1009 }
1010
1011 static dbus_bool_t
1012 dbus_message_create_header (DBusMessage *message,
1013                             int          type,
1014                             const char  *service,
1015                             const char  *path,
1016                             const char  *interface,
1017                             const char  *member,
1018                             const char  *error_name)
1019 {
1020   unsigned int flags;
1021
1022   _dbus_assert ((interface && member) ||
1023                 (error_name) ||
1024                 !(interface || member || error_name));
1025   
1026   if (!_dbus_string_append_byte (&message->header, message->byte_order))
1027     return FALSE;
1028
1029   if (!_dbus_string_append_byte (&message->header, type))
1030     return FALSE;
1031   
1032   flags = 0;
1033   if (!_dbus_string_append_byte (&message->header, flags))
1034     return FALSE;
1035
1036   if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION))
1037     return FALSE;
1038
1039   /* header length */
1040   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
1041     return FALSE;
1042
1043   /* body length */
1044   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
1045     return FALSE;
1046
1047   /* serial */
1048   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
1049     return FALSE;
1050   
1051   /* Marshal all the fields (Marshall Fields?) */
1052   
1053   if (path != NULL)
1054     {
1055       if (!append_string_field (message,
1056                                 DBUS_HEADER_FIELD_PATH,
1057                                 DBUS_TYPE_OBJECT_PATH,
1058                                 path))
1059         return FALSE;
1060     }
1061   
1062   if (service != NULL)
1063     {
1064       if (!append_string_field (message,
1065                                 DBUS_HEADER_FIELD_SERVICE,
1066                                 DBUS_TYPE_STRING,
1067                                 service))
1068         return FALSE;
1069     }
1070
1071   if (interface != NULL)
1072     {
1073       if (!append_string_field (message,
1074                                 DBUS_HEADER_FIELD_INTERFACE,
1075                                 DBUS_TYPE_STRING,
1076                                 interface))
1077         return FALSE;
1078     }
1079
1080   if (member != NULL)
1081     {
1082       if (!append_string_field (message,
1083                                 DBUS_HEADER_FIELD_MEMBER,
1084                                 DBUS_TYPE_STRING,
1085                                 member))
1086         return FALSE;
1087     }
1088
1089   if (error_name != NULL)
1090     {
1091       if (!append_string_field (message,
1092                                 DBUS_HEADER_FIELD_ERROR_NAME,
1093                                 DBUS_TYPE_STRING,
1094                                 error_name))
1095         return FALSE;
1096     }
1097   
1098   return TRUE;
1099 }
1100
1101 /**
1102  * Locks a message. Allows checking that applications don't keep a
1103  * reference to a message in the outgoing queue and change it
1104  * underneath us. Messages are locked when they enter the outgoing
1105  * queue (dbus_connection_send_message()), and the library complains
1106  * if the message is modified while locked.
1107  *
1108  * @param message the message to lock.
1109  */
1110 void
1111 _dbus_message_lock (DBusMessage  *message)
1112 {
1113   if (!message->locked)
1114     {
1115       /* Fill in our lengths */
1116       _dbus_marshal_set_uint32 (&message->header,
1117                                 message->byte_order,
1118                                 HEADER_LENGTH_OFFSET,
1119                                 _dbus_string_get_length (&message->header));
1120
1121       _dbus_marshal_set_uint32 (&message->header,
1122                                 message->byte_order,
1123                                 BODY_LENGTH_OFFSET,
1124                                 _dbus_string_get_length (&message->body));
1125
1126       message->locked = TRUE;
1127     }
1128 }
1129
1130 /** @} */
1131
1132 /**
1133  * @defgroup DBusMessage DBusMessage
1134  * @ingroup  DBus
1135  * @brief Message to be sent or received over a DBusConnection.
1136  *
1137  * A DBusMessage is the most basic unit of communication over a
1138  * DBusConnection. A DBusConnection represents a stream of messages
1139  * received from a remote application, and a stream of messages
1140  * sent to a remote application.
1141  *
1142  * @{
1143  */
1144
1145 /**
1146  * @typedef DBusMessage
1147  *
1148  * Opaque data type representing a message received from or to be
1149  * sent to another application.
1150  */
1151
1152 static DBusMessage*
1153 dbus_message_new_empty_header (void)
1154 {
1155   DBusMessage *message;
1156   int i;
1157   
1158   message = dbus_new0 (DBusMessage, 1);
1159   if (message == NULL)
1160     return NULL;
1161   
1162   message->refcount.value = 1;
1163   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
1164   message->client_serial = 0;
1165   message->reply_serial = 0;
1166
1167   _dbus_data_slot_list_init (&message->slot_list);
1168   
1169   i = 0;
1170   while (i <= DBUS_HEADER_FIELD_LAST)
1171     {
1172       message->header_fields[i].name_offset  = -1;
1173       message->header_fields[i].value_offset = -1;
1174       ++i;
1175     }
1176   
1177   if (!_dbus_string_init_preallocated (&message->header, 64))
1178     {
1179       dbus_free (message);
1180       return NULL;
1181     }
1182   
1183   if (!_dbus_string_init_preallocated (&message->body, 64))
1184     {
1185       _dbus_string_free (&message->header);
1186       dbus_free (message);
1187       return NULL;
1188     }
1189
1190   if (!_dbus_string_init_preallocated (&message->signature, 4))
1191     {
1192       _dbus_string_free (&message->header);
1193       _dbus_string_free (&message->body);
1194       dbus_free (message);
1195       return NULL;
1196     }
1197   
1198   return message;
1199 }
1200
1201 /**
1202  * Constructs a new message of the given message type.
1203  * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL,
1204  * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth.
1205  *
1206  * @param message_type type of message
1207  * @returns new message or #NULL If no memory
1208  */
1209 DBusMessage*
1210 dbus_message_new (int message_type)
1211 {
1212   DBusMessage *message;
1213
1214   _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL);
1215   
1216   message = dbus_message_new_empty_header ();
1217   if (message == NULL)
1218     return NULL;
1219   
1220   if (!dbus_message_create_header (message,
1221                                    message_type,
1222                                    NULL, NULL, NULL, NULL, NULL))
1223     {
1224       dbus_message_unref (message);
1225       return NULL;
1226     }
1227   
1228   return message;
1229 }
1230
1231 /**
1232  * Constructs a new message to invoke a method on a remote
1233  * object. Returns #NULL if memory can't be allocated for the
1234  * message. The service may be #NULL in which case no service is set;
1235  * this is appropriate when using D-BUS in a peer-to-peer context (no
1236  * message bus). The interface may be #NULL, which means that
1237  * if multiple methods with the given name exist it is undefined
1238  * which one will be invoked.
1239   *
1240  * @param service service that the message should be sent to or #NULL
1241  * @param path object path the message should be sent to
1242  * @param interface interface to invoke method on
1243  * @param method method to invoke
1244  * 
1245  * @returns a new DBusMessage, free with dbus_message_unref()
1246  * @see dbus_message_unref()
1247  */
1248 DBusMessage*
1249 dbus_message_new_method_call (const char *service,
1250                               const char *path,
1251                               const char *interface,
1252                               const char *method)
1253 {
1254   DBusMessage *message;
1255
1256   _dbus_return_val_if_fail (path != NULL, NULL);
1257   _dbus_return_val_if_fail (method != NULL, NULL);
1258   
1259   message = dbus_message_new_empty_header ();
1260   if (message == NULL)
1261     return NULL;
1262   
1263   if (!dbus_message_create_header (message,
1264                                    DBUS_MESSAGE_TYPE_METHOD_CALL,
1265                                    service, path, interface, method, NULL))
1266     {
1267       dbus_message_unref (message);
1268       return NULL;
1269     }
1270   
1271   return message;
1272 }
1273
1274 /**
1275  * Constructs a message that is a reply to a method call. Returns
1276  * #NULL if memory can't be allocated for the message.
1277  *
1278  * @param method_call the message which the created
1279  * message is a reply to.
1280  * @returns a new DBusMessage, free with dbus_message_unref()
1281  * @see dbus_message_new_method_call(), dbus_message_unref()
1282  */ 
1283 DBusMessage*
1284 dbus_message_new_method_return (DBusMessage *method_call)
1285 {
1286   DBusMessage *message;
1287   const char *sender;
1288
1289   _dbus_return_val_if_fail (method_call != NULL, NULL);
1290   
1291   sender = get_string_field (method_call,
1292                              DBUS_HEADER_FIELD_SENDER_SERVICE,
1293                              NULL);
1294   
1295   /* sender is allowed to be null here in peer-to-peer case */
1296
1297   message = dbus_message_new_empty_header ();
1298   if (message == NULL)
1299     return NULL;
1300   
1301   if (!dbus_message_create_header (message,
1302                                    DBUS_MESSAGE_TYPE_METHOD_RETURN,
1303                                    sender, NULL, NULL, NULL, NULL))
1304     {
1305       dbus_message_unref (message);
1306       return NULL;
1307     }
1308
1309   dbus_message_set_no_reply (message, TRUE);
1310
1311   if (!dbus_message_set_reply_serial (message,
1312                                       dbus_message_get_serial (method_call)))
1313     {
1314       dbus_message_unref (message);
1315       return NULL;
1316     }
1317
1318   return message;
1319 }
1320
1321 /**
1322  * Constructs a new message representing a signal emission. Returns
1323  * #NULL if memory can't be allocated for the message.
1324  * A signal is identified by its originating interface, and
1325  * the name of the signal.
1326  *
1327  * @param path the path to the object emitting the signal
1328  * @param interface the interface the signal is emitted from
1329  * @param name name of the signal
1330  * @returns a new DBusMessage, free with dbus_message_unref()
1331  * @see dbus_message_unref()
1332  */
1333 DBusMessage*
1334 dbus_message_new_signal (const char *path,
1335                          const char *interface,
1336                          const char *name)
1337 {
1338   DBusMessage *message;
1339
1340   _dbus_return_val_if_fail (path != NULL, NULL);
1341   _dbus_return_val_if_fail (interface != NULL, NULL);
1342   _dbus_return_val_if_fail (name != NULL, NULL);
1343   
1344   message = dbus_message_new_empty_header ();
1345   if (message == NULL)
1346     return NULL;
1347   
1348   if (!dbus_message_create_header (message,
1349                                    DBUS_MESSAGE_TYPE_SIGNAL,
1350                                    NULL, path, interface, name, NULL))
1351     {
1352       dbus_message_unref (message);
1353       return NULL;
1354     }
1355
1356   dbus_message_set_no_reply (message, TRUE);
1357   
1358   return message;
1359 }
1360
1361 /**
1362  * Creates a new message that is an error reply to a certain message.
1363  * Error replies are possible in response to method calls primarily.
1364  *
1365  * @param reply_to the original message
1366  * @param error_name the error name
1367  * @param error_message the error message string or #NULL for none
1368  * @returns a new error message
1369  */
1370 DBusMessage*
1371 dbus_message_new_error (DBusMessage *reply_to,
1372                         const char  *error_name,
1373                         const char  *error_message)
1374 {
1375   DBusMessage *message;
1376   const char *sender;
1377   DBusMessageIter iter;
1378
1379   _dbus_return_val_if_fail (reply_to != NULL, NULL);
1380   _dbus_return_val_if_fail (error_name != NULL, NULL);
1381   
1382   sender = get_string_field (reply_to,
1383                              DBUS_HEADER_FIELD_SENDER_SERVICE,
1384                              NULL);
1385
1386   /* sender may be NULL for non-message-bus case or
1387    * when the message bus is dealing with an unregistered
1388    * connection.
1389    */
1390   message = dbus_message_new_empty_header ();
1391   if (message == NULL)
1392     return NULL;
1393   
1394   if (!dbus_message_create_header (message,
1395                                    DBUS_MESSAGE_TYPE_ERROR,
1396                                    sender, NULL, NULL, NULL, error_name))
1397     {
1398       dbus_message_unref (message);
1399       return NULL;
1400     }
1401
1402   dbus_message_set_no_reply (message, TRUE);
1403   
1404   if (!dbus_message_set_reply_serial (message,
1405                                       dbus_message_get_serial (reply_to)))
1406     {
1407       dbus_message_unref (message);
1408       return NULL;
1409     }
1410
1411   if (error_message != NULL)
1412     {
1413       dbus_message_append_iter_init (message, &iter);
1414       if (!dbus_message_iter_append_string (&iter, error_message))
1415         {
1416           dbus_message_unref (message);
1417           return NULL;
1418         }
1419     }
1420   
1421   return message;
1422 }
1423
1424 /**
1425  * Creates a new message that is an exact replica of the message
1426  * specified, except that its refcount is set to 1.
1427  *
1428  * @param message the message.
1429  * @returns the new message.
1430  */
1431 DBusMessage *
1432 dbus_message_copy (const DBusMessage *message)
1433 {
1434   DBusMessage *retval;
1435   int i;
1436
1437   _dbus_return_val_if_fail (message != NULL, NULL);
1438   
1439   retval = dbus_new0 (DBusMessage, 1);
1440   if (retval == NULL)
1441     return NULL;
1442   
1443   retval->refcount.value = 1;
1444   retval->byte_order = message->byte_order;
1445   retval->client_serial = message->client_serial;
1446   retval->reply_serial = message->reply_serial;
1447   retval->header_padding = message->header_padding;
1448   retval->locked = FALSE;
1449   
1450   if (!_dbus_string_init_preallocated (&retval->header,
1451                                        _dbus_string_get_length (&message->header)))
1452     {
1453       dbus_free (retval);
1454       return NULL;
1455     }
1456   
1457   if (!_dbus_string_init_preallocated (&retval->body,
1458                                        _dbus_string_get_length (&message->body)))
1459     {
1460       _dbus_string_free (&retval->header);
1461       dbus_free (retval);
1462       return NULL;
1463     }
1464
1465   if (!_dbus_string_init_preallocated (&retval->signature,
1466                                        _dbus_string_get_length (&message->signature)))
1467     {
1468       _dbus_string_free (&retval->header);
1469       _dbus_string_free (&retval->body);
1470       dbus_free (retval);
1471       return NULL;
1472     }
1473   
1474   if (!_dbus_string_copy (&message->header, 0,
1475                           &retval->header, 0))
1476     goto failed_copy;
1477
1478   if (!_dbus_string_copy (&message->body, 0,
1479                           &retval->body, 0))
1480     goto failed_copy;
1481
1482   if (!_dbus_string_copy (&message->signature, 0,
1483                           &retval->signature, 0))
1484     goto failed_copy;
1485   
1486   for (i = 0; i <= DBUS_HEADER_FIELD_LAST; i++)
1487     {
1488       retval->header_fields[i] = message->header_fields[i];
1489     }
1490   
1491   return retval;
1492
1493  failed_copy:
1494   _dbus_string_free (&retval->header);
1495   _dbus_string_free (&retval->body);
1496   _dbus_string_free (&retval->signature);
1497   dbus_free (retval);
1498   
1499   return NULL;  
1500 }
1501
1502
1503 /**
1504  * Increments the reference count of a DBusMessage.
1505  *
1506  * @param message The message
1507  * @see dbus_message_unref
1508  */
1509 void
1510 dbus_message_ref (DBusMessage *message)
1511 {
1512   dbus_int32_t old_refcount;
1513
1514   _dbus_return_if_fail (message != NULL);
1515   
1516   old_refcount = _dbus_atomic_inc (&message->refcount);
1517   _dbus_assert (old_refcount >= 1);
1518 }
1519
1520 static void
1521 free_size_counter (void *element,
1522                    void *data)
1523 {
1524   DBusCounter *counter = element;
1525   DBusMessage *message = data;
1526   
1527   _dbus_counter_adjust (counter, - message->size_counter_delta);
1528
1529   _dbus_counter_unref (counter);
1530 }
1531
1532 /**
1533  * Decrements the reference count of a DBusMessage.
1534  *
1535  * @param message The message
1536  * @see dbus_message_ref
1537  */
1538 void
1539 dbus_message_unref (DBusMessage *message)
1540 {
1541  dbus_int32_t old_refcount;
1542
1543   _dbus_return_if_fail (message != NULL);
1544   
1545   old_refcount = _dbus_atomic_dec (&message->refcount);
1546   
1547   _dbus_assert (old_refcount >= 0);
1548
1549   if (old_refcount == 1)
1550     {
1551       /* This calls application callbacks! */
1552       _dbus_data_slot_list_free (&message->slot_list);
1553       
1554       _dbus_list_foreach (&message->size_counters,
1555                           free_size_counter, message);
1556       _dbus_list_clear (&message->size_counters);
1557       
1558       _dbus_string_free (&message->header);
1559       _dbus_string_free (&message->body);
1560       _dbus_string_free (&message->signature);
1561       
1562       dbus_free (message);
1563     }
1564 }
1565
1566 /**
1567  * Gets the type of a message. Types include
1568  * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN,
1569  * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types
1570  * are allowed and all code must silently ignore messages of unknown
1571  * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however.
1572  *
1573  *
1574  * @param message the message
1575  * @returns the type of the message
1576  */
1577 int
1578 dbus_message_get_type (DBusMessage *message)
1579 {
1580   int type;
1581
1582   type = _dbus_string_get_byte (&message->header, 1);
1583   _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID);
1584
1585   return type;
1586 }
1587
1588 /**
1589  * Sets the object path this message is being sent to (for
1590  * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being
1591  * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL).
1592  *
1593  * @param message the message
1594  * @param object_path the path
1595  * @returns #FALSE if not enough memory
1596  */
1597 dbus_bool_t
1598 dbus_message_set_path (DBusMessage   *message,
1599                        const char    *object_path)
1600 {
1601   _dbus_return_val_if_fail (message != NULL, FALSE);
1602   _dbus_return_val_if_fail (!message->locked, FALSE);
1603
1604   return set_string_field (message,
1605                            DBUS_HEADER_FIELD_PATH,
1606                            DBUS_TYPE_OBJECT_PATH,
1607                            object_path);
1608 }
1609
1610 /**
1611  * Gets the object path this message is being sent to
1612  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1613  * from (for DBUS_MESSAGE_TYPE_SIGNAL).
1614  *
1615  * @param message the message
1616  * @returns the path (should not be freed)
1617  */
1618 const char*
1619 dbus_message_get_path (DBusMessage   *message)
1620 {
1621   _dbus_return_val_if_fail (message != NULL, NULL);
1622   
1623   return get_string_field (message, DBUS_HEADER_FIELD_PATH, NULL);
1624 }
1625
1626 /**
1627  * Gets the object path this message is being sent to
1628  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1629  * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed
1630  * format (one array element per path component).
1631  * Free the returned array with dbus_free_string_array().
1632  *
1633  * An empty but non-NULL path array means the path "/".
1634  * So the path "/foo/bar" becomes { "foo", "bar", NULL }
1635  * and the path "/" becomes { NULL }.
1636  *
1637  * @param message the message
1638  * @param path place to store allocated array of path components; #NULL set here if no path field exists
1639  * @returns #FALSE if no memory to allocate the array
1640  */
1641 dbus_bool_t
1642 dbus_message_get_path_decomposed (DBusMessage   *message,
1643                                   char        ***path)
1644 {
1645   _dbus_return_val_if_fail (message != NULL, FALSE);
1646   _dbus_return_val_if_fail (path != NULL, FALSE);
1647
1648   return get_path_field_decomposed (message,
1649                                     DBUS_HEADER_FIELD_PATH,
1650                                     path);
1651 }
1652
1653 /**
1654  * Sets the interface this message is being sent to
1655  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or
1656  * the interface a signal is being emitted from
1657  * (for DBUS_MESSAGE_TYPE_SIGNAL).
1658  *
1659  * @param message the message
1660  * @param interface the interface
1661  * @returns #FALSE if not enough memory
1662  */
1663 dbus_bool_t
1664 dbus_message_set_interface (DBusMessage  *message,
1665                             const char   *interface)
1666 {
1667   _dbus_return_val_if_fail (message != NULL, FALSE);
1668   _dbus_return_val_if_fail (!message->locked, FALSE);
1669
1670   return set_string_field (message,
1671                            DBUS_HEADER_FIELD_INTERFACE,
1672                            DBUS_TYPE_STRING,
1673                            interface);
1674 }
1675
1676 /**
1677  * Gets the interface this message is being sent to
1678  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1679  * from (for DBUS_MESSAGE_TYPE_SIGNAL).
1680  * The interface name is fully-qualified (namespaced).
1681  *
1682  * @param message the message
1683  * @returns the message interface (should not be freed)
1684  */
1685 const char*
1686 dbus_message_get_interface (DBusMessage *message)
1687 {
1688   _dbus_return_val_if_fail (message != NULL, NULL);
1689   
1690   return get_string_field (message, DBUS_HEADER_FIELD_INTERFACE, NULL);
1691 }
1692
1693 /**
1694  * Sets the interface member being invoked
1695  * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
1696  * (DBUS_MESSAGE_TYPE_SIGNAL).
1697  * The interface name is fully-qualified (namespaced).
1698  *
1699  * @param message the message
1700  * @param member the member
1701  * @returns #FALSE if not enough memory
1702  */
1703 dbus_bool_t
1704 dbus_message_set_member (DBusMessage  *message,
1705                        const char   *member)
1706 {
1707   _dbus_return_val_if_fail (message != NULL, FALSE);
1708   _dbus_return_val_if_fail (!message->locked, FALSE);
1709
1710   return set_string_field (message,
1711                            DBUS_HEADER_FIELD_MEMBER,
1712                            DBUS_TYPE_STRING,
1713                            member);
1714 }
1715
1716 /**
1717  * Gets the interface member being invoked
1718  * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
1719  * (DBUS_MESSAGE_TYPE_SIGNAL).
1720  * 
1721  * @param message the message
1722  * @returns the member name (should not be freed)
1723  */
1724 const char*
1725 dbus_message_get_member (DBusMessage *message)
1726 {
1727   _dbus_return_val_if_fail (message != NULL, NULL);
1728   
1729   return get_string_field (message,
1730                            DBUS_HEADER_FIELD_MEMBER,
1731                            NULL);
1732 }
1733
1734 /**
1735  * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR).
1736  * The name is fully-qualified (namespaced).
1737  *
1738  * @param message the message
1739  * @param error_name the name
1740  * @returns #FALSE if not enough memory
1741  */
1742 dbus_bool_t
1743 dbus_message_set_error_name (DBusMessage  *message,
1744                              const char   *error_name)
1745 {
1746   _dbus_return_val_if_fail (message != NULL, FALSE);
1747   _dbus_return_val_if_fail (!message->locked, FALSE);
1748
1749   return set_string_field (message,
1750                            DBUS_HEADER_FIELD_ERROR_NAME,
1751                            DBUS_TYPE_STRING,
1752                            error_name);
1753 }
1754
1755 /**
1756  * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only).
1757  * 
1758  * @param message the message
1759  * @returns the error name (should not be freed)
1760  */
1761 const char*
1762 dbus_message_get_error_name (DBusMessage *message)
1763 {
1764   _dbus_return_val_if_fail (message != NULL, NULL);
1765   
1766   return get_string_field (message,
1767                            DBUS_HEADER_FIELD_ERROR_NAME,
1768                            NULL);
1769 }
1770
1771 /**
1772  * Sets the message's destination service.
1773  *
1774  * @param message the message
1775  * @param destination the destination service name
1776  * @returns #FALSE if not enough memory
1777  */
1778 dbus_bool_t
1779 dbus_message_set_destination (DBusMessage  *message,
1780                               const char   *destination)
1781 {
1782   _dbus_return_val_if_fail (message != NULL, FALSE);
1783   _dbus_return_val_if_fail (!message->locked, FALSE);
1784
1785   return set_string_field (message,
1786                            DBUS_HEADER_FIELD_SERVICE,
1787                            DBUS_TYPE_STRING,
1788                            destination);
1789 }
1790
1791 /**
1792  * Gets the destination service of a message.
1793  * 
1794  * @param message the message
1795  * @returns the message destination service (should not be freed)
1796  */
1797 const char*
1798 dbus_message_get_destination (DBusMessage *message)
1799 {
1800   _dbus_return_val_if_fail (message != NULL, NULL);
1801   
1802   return get_string_field (message,
1803                            DBUS_HEADER_FIELD_SERVICE,
1804                            NULL);
1805 }
1806
1807 /**
1808  * Appends fields to a message given a variable argument list. The
1809  * variable argument list should contain the type of the argument
1810  * followed by the value to add.  Array values are specified by an int
1811  * typecode followed by a pointer to the array followed by an int
1812  * giving the length of the array.  The argument list must be
1813  * terminated with #DBUS_TYPE_INVALID.
1814  *
1815  * This function doesn't support dicts or non-fundamental arrays.
1816  *
1817  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
1818  * only if #DBUS_HAVE_INT64 is defined.
1819  *
1820  * @param message the message
1821  * @param first_arg_type type of the first argument
1822  * @param ... value of first argument, list of additional type-value pairs
1823  * @returns #TRUE on success
1824  */
1825 dbus_bool_t
1826 dbus_message_append_args (DBusMessage *message,
1827                           int first_arg_type,
1828                           ...)
1829 {
1830   dbus_bool_t retval;
1831   va_list var_args;
1832
1833   _dbus_return_val_if_fail (message != NULL, FALSE);
1834   
1835   va_start (var_args, first_arg_type);
1836   retval = dbus_message_append_args_valist (message,
1837                                             first_arg_type,
1838                                             var_args);
1839   va_end (var_args);
1840
1841   return retval;
1842 }
1843
1844 /**
1845  * This function takes a va_list for use by language bindings.
1846  * It's otherwise the same as dbus_message_append_args().
1847  *
1848  * @todo: Shouldn't this function clean up the changes to the message
1849  *        on failures? (Yes)
1850   
1851  * @see dbus_message_append_args.  
1852  * @param message the message
1853  * @param first_arg_type type of first argument
1854  * @param var_args value of first argument, then list of type/value pairs
1855  * @returns #TRUE on success
1856  */
1857 dbus_bool_t
1858 dbus_message_append_args_valist (DBusMessage *message,
1859                                  int          first_arg_type,
1860                                  va_list      var_args)
1861 {
1862   int type, old_len;
1863   DBusMessageIter iter;
1864
1865   _dbus_return_val_if_fail (message != NULL, FALSE);
1866   
1867   old_len = _dbus_string_get_length (&message->body);
1868   
1869   type = first_arg_type;
1870
1871   dbus_message_append_iter_init (message, &iter);
1872   
1873   while (type != DBUS_TYPE_INVALID)
1874     {
1875       switch (type)
1876         {
1877         case DBUS_TYPE_NIL:
1878           if (!dbus_message_iter_append_nil (&iter))
1879             goto errorout;
1880           break;
1881         case DBUS_TYPE_BOOLEAN:
1882           if (!dbus_message_iter_append_boolean (&iter, va_arg (var_args, dbus_bool_t)))
1883             goto errorout;
1884           break;
1885         case DBUS_TYPE_INT32:
1886           if (!dbus_message_iter_append_int32 (&iter, va_arg (var_args, dbus_int32_t)))
1887             goto errorout;
1888           break;
1889         case DBUS_TYPE_UINT32:
1890           if (!dbus_message_iter_append_uint32 (&iter, va_arg (var_args, dbus_uint32_t)))
1891             goto errorout;          
1892           break;
1893 #ifdef DBUS_HAVE_INT64
1894         case DBUS_TYPE_INT64:
1895           if (!dbus_message_iter_append_int64 (&iter, va_arg (var_args, dbus_int64_t)))
1896             goto errorout;
1897           break;
1898         case DBUS_TYPE_UINT64:
1899           if (!dbus_message_iter_append_uint64 (&iter, va_arg (var_args, dbus_uint64_t)))
1900             goto errorout;          
1901           break;
1902 #endif /* DBUS_HAVE_INT64 */
1903         case DBUS_TYPE_DOUBLE:
1904           if (!dbus_message_iter_append_double (&iter, va_arg (var_args, double)))
1905             goto errorout;
1906           break;
1907         case DBUS_TYPE_STRING:
1908           if (!dbus_message_iter_append_string (&iter, va_arg (var_args, const char *)))
1909             goto errorout;
1910           break;
1911         case DBUS_TYPE_OBJECT_PATH:
1912
1913           break;
1914         case DBUS_TYPE_CUSTOM:
1915           {
1916             const char *name;
1917             unsigned char *data;
1918             int len;
1919  
1920             name = va_arg (var_args, const char *);
1921             data = va_arg (var_args, unsigned char *);
1922             len = va_arg (var_args, int);
1923
1924             if (!dbus_message_iter_append_custom (&iter, name, data, len))
1925               goto errorout;
1926             break;
1927           }
1928         case DBUS_TYPE_ARRAY:
1929           {
1930             void *data;
1931             int len, type;
1932  
1933             type = va_arg (var_args, int);
1934             data = va_arg (var_args, void *);
1935             len = va_arg (var_args, int);
1936
1937             switch (type)
1938               {
1939               case DBUS_TYPE_BYTE:
1940                 if (!dbus_message_iter_append_byte_array (&iter, (unsigned char *)data, len))
1941                   goto errorout;
1942                 break;
1943               case DBUS_TYPE_BOOLEAN:
1944                 if (!dbus_message_iter_append_boolean_array (&iter, (unsigned char *)data, len))
1945                   goto errorout;
1946                 break;
1947               case DBUS_TYPE_INT32:
1948                 if (!dbus_message_iter_append_int32_array (&iter, (dbus_int32_t *)data, len))
1949                   goto errorout;
1950                 break;
1951               case DBUS_TYPE_UINT32:
1952                 if (!dbus_message_iter_append_uint32_array (&iter, (dbus_uint32_t *)data, len))
1953                   goto errorout;
1954                 break;
1955 #ifdef DBUS_HAVE_INT64
1956               case DBUS_TYPE_INT64:
1957                 if (!dbus_message_iter_append_int64_array (&iter, (dbus_int64_t *)data, len))
1958                   goto errorout;
1959                 break;
1960               case DBUS_TYPE_UINT64:
1961                 if (!dbus_message_iter_append_uint64_array (&iter, (dbus_uint64_t *)data, len))
1962                   goto errorout;
1963                 break;
1964 #endif /* DBUS_HAVE_INT64 */
1965               case DBUS_TYPE_DOUBLE:
1966                 if (!dbus_message_iter_append_double_array (&iter, (double *)data, len))
1967                   goto errorout;
1968                 break;
1969               case DBUS_TYPE_STRING:
1970                 if (!dbus_message_iter_append_string_array (&iter, (const char **)data, len))
1971                   goto errorout;
1972                 break;
1973               case DBUS_TYPE_NIL:
1974               case DBUS_TYPE_ARRAY:
1975               case DBUS_TYPE_CUSTOM:
1976               case DBUS_TYPE_DICT:
1977                 _dbus_warn ("dbus_message_append_args_valist doesn't support recursive arrays\n");
1978                 goto errorout;
1979               default:
1980                 _dbus_warn ("Unknown field type %d\n", type);
1981                 goto errorout;
1982               }
1983           }
1984           break;
1985           
1986         case DBUS_TYPE_DICT:
1987           _dbus_warn ("dbus_message_append_args_valist doesn't support dicts\n");
1988           goto errorout;
1989         default:
1990           _dbus_warn ("Unknown field type %d\n", type);
1991           goto errorout;
1992         }
1993
1994       type = va_arg (var_args, int);
1995     }
1996
1997   return TRUE;
1998
1999  errorout:
2000   return FALSE;
2001 }
2002
2003
2004 /**
2005  * Gets arguments from a message given a variable argument list.
2006  * The variable argument list should contain the type of the
2007  * argumen followed by a pointer to where the value should be
2008  * stored. The list is terminated with #DBUS_TYPE_INVALID.
2009  *
2010  * @param message the message
2011  * @param error error to be filled in on failure
2012  * @param first_arg_type the first argument type
2013  * @param ... location for first argument value, then list of type-location pairs
2014  * @returns #FALSE if the error was set
2015  */
2016 dbus_bool_t
2017 dbus_message_get_args (DBusMessage     *message,
2018                        DBusError       *error,
2019                        int              first_arg_type,
2020                        ...)
2021 {
2022   dbus_bool_t retval;
2023   va_list var_args;
2024
2025   _dbus_return_val_if_fail (message != NULL, FALSE);
2026   _dbus_return_val_if_error_is_set (error, FALSE);
2027   
2028   va_start (var_args, first_arg_type);
2029   retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args);
2030   va_end (var_args);
2031
2032   return retval;
2033 }
2034
2035 /**
2036  * This function takes a va_list for use by language bindings
2037  *
2038  * @todo We need to free the argument data when an error occurs.
2039  *
2040  * @see dbus_message_get_args
2041  * @param message the message
2042  * @param error error to be filled in
2043  * @param first_arg_type type of the first argument
2044  * @param var_args return location for first argument, followed by list of type/location pairs
2045  * @returns #FALSE if error was set
2046  */
2047 dbus_bool_t
2048 dbus_message_get_args_valist (DBusMessage     *message,
2049                               DBusError       *error,
2050                               int              first_arg_type,
2051                               va_list          var_args)
2052 {
2053   DBusMessageIter iter;
2054
2055   _dbus_return_val_if_fail (message != NULL, FALSE);
2056   _dbus_return_val_if_error_is_set (error, FALSE);
2057   
2058   dbus_message_iter_init (message, &iter);
2059   return dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args);
2060 }
2061
2062 /**
2063  * Gets arguments from a message iterator given a variable argument list.
2064  * The variable argument list should contain the type of the
2065  * argumen followed by a pointer to where the value should be
2066  * stored. The list is terminated with 0.
2067  *
2068  * @param iter the message iterator 
2069  * @param error error to be filled in on failure
2070  * @param first_arg_type the first argument type
2071  * @param ... location for first argument value, then list of type-location pairs
2072  * @returns #FALSE if the error was set
2073  */
2074 dbus_bool_t
2075 dbus_message_iter_get_args (DBusMessageIter *iter,
2076                             DBusError       *error,
2077                             int              first_arg_type,
2078                             ...)
2079 {
2080   dbus_bool_t retval;
2081   va_list var_args;
2082
2083   _dbus_return_val_if_fail (iter != NULL, FALSE);
2084   _dbus_return_val_if_error_is_set (error, FALSE);
2085   
2086   va_start (var_args, first_arg_type);
2087   retval = dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args);
2088   va_end (var_args);
2089
2090   return retval;
2091 }
2092
2093 /**
2094  * This function takes a va_list for use by language bindings
2095  *
2096  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
2097  * only if #DBUS_HAVE_INT64 is defined.
2098  *
2099  * @todo this function (or some lower-level non-convenience function)
2100  * needs better error handling; should allow the application to
2101  * distinguish between out of memory, and bad data from the remote
2102  * app. It also needs to not leak a bunch of args when it gets
2103  * to the arg that's bad, as that would be a security hole
2104  * (allow one app to force another to leak memory)
2105  *
2106  * @todo We need to free the argument data when an error occurs.
2107  *
2108  * @see dbus_message_get_args
2109  * @param iter the message iter
2110  * @param error error to be filled in
2111  * @param first_arg_type type of the first argument
2112  * @param var_args return location for first argument, followed by list of type/location pairs
2113  * @returns #FALSE if error was set
2114  */
2115 dbus_bool_t
2116 dbus_message_iter_get_args_valist (DBusMessageIter *iter,
2117                                    DBusError       *error,
2118                                    int              first_arg_type,
2119                                    va_list          var_args)
2120 {
2121   int spec_type, msg_type, i;
2122   dbus_bool_t retval;
2123
2124   _dbus_return_val_if_fail (iter != NULL, FALSE);
2125   _dbus_return_val_if_error_is_set (error, FALSE);
2126
2127   retval = FALSE;
2128   
2129   spec_type = first_arg_type;
2130   i = 0;
2131   
2132   while (spec_type != 0)
2133     {
2134       msg_type = dbus_message_iter_get_arg_type (iter);      
2135       
2136       if (msg_type != spec_type)
2137         {
2138           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2139                           "Argument %d is specified to be of type \"%s\", but "
2140                           "is actually of type \"%s\"\n", i,
2141                           _dbus_type_to_string (spec_type),
2142                           _dbus_type_to_string (msg_type));
2143
2144           goto out;
2145         }
2146
2147       switch (spec_type)
2148         {
2149         case DBUS_TYPE_NIL:
2150           break;
2151         case DBUS_TYPE_BYTE:
2152           {
2153             unsigned char *ptr;
2154
2155             ptr = va_arg (var_args, unsigned char *);
2156
2157             *ptr = dbus_message_iter_get_byte (iter);
2158             break;
2159           }
2160         case DBUS_TYPE_BOOLEAN:
2161           {
2162             dbus_bool_t *ptr;
2163
2164             ptr = va_arg (var_args, dbus_bool_t *);
2165
2166             *ptr = dbus_message_iter_get_boolean (iter);
2167             break;
2168           }
2169         case DBUS_TYPE_INT32:
2170           {
2171             dbus_int32_t *ptr;
2172
2173             ptr = va_arg (var_args, dbus_int32_t *);
2174
2175             *ptr = dbus_message_iter_get_int32 (iter);
2176             break;
2177           }
2178         case DBUS_TYPE_UINT32:
2179           {
2180             dbus_uint32_t *ptr;
2181
2182             ptr = va_arg (var_args, dbus_uint32_t *);
2183
2184             *ptr = dbus_message_iter_get_uint32 (iter);
2185             break;
2186           }
2187 #ifdef DBUS_HAVE_INT64
2188         case DBUS_TYPE_INT64:
2189           {
2190             dbus_int64_t *ptr;
2191
2192             ptr = va_arg (var_args, dbus_int64_t *);
2193
2194             *ptr = dbus_message_iter_get_int64 (iter);
2195             break;
2196           }
2197         case DBUS_TYPE_UINT64:
2198           {
2199             dbus_uint64_t *ptr;
2200
2201             ptr = va_arg (var_args, dbus_uint64_t *);
2202
2203             *ptr = dbus_message_iter_get_uint64 (iter);
2204             break;
2205           }
2206 #endif /* DBUS_HAVE_INT64 */
2207           
2208         case DBUS_TYPE_DOUBLE:
2209           {
2210             double *ptr;
2211
2212             ptr = va_arg (var_args, double *);
2213
2214             *ptr = dbus_message_iter_get_double (iter);
2215             break;
2216           }
2217
2218         case DBUS_TYPE_STRING:
2219           {
2220             char **ptr;
2221
2222             ptr = va_arg (var_args, char **);
2223
2224             *ptr = dbus_message_iter_get_string (iter);
2225
2226             if (!*ptr)
2227               {
2228                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2229                 goto out;
2230               }
2231             
2232             break;
2233           }
2234
2235         case DBUS_TYPE_CUSTOM:
2236           {
2237             char **name;
2238             unsigned char **data;
2239             int *len;
2240  
2241             name = va_arg (var_args, char **);
2242             data = va_arg (var_args, unsigned char **);
2243             len = va_arg (var_args, int *);
2244
2245             if (!dbus_message_iter_get_custom (iter, name, data, len))
2246               {
2247                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2248                 goto out;
2249               }
2250           }
2251           break;
2252         case DBUS_TYPE_ARRAY:
2253           {
2254             void **data;
2255             int *len, type;
2256  
2257             type = va_arg (var_args, int);
2258             data = va_arg (var_args, void *);
2259             len = va_arg (var_args, int *);
2260
2261             _dbus_return_val_if_fail (data != NULL, FALSE);
2262             _dbus_return_val_if_fail (len != NULL, FALSE);
2263             
2264             if (dbus_message_iter_get_array_type (iter) != type)
2265               {
2266                 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2267                                 "Argument %d is specified to be of type \"array of %s\", but "
2268                                 "is actually of type \"array of %s\"\n", i,
2269                                 _dbus_type_to_string (type),
2270                                 _dbus_type_to_string (dbus_message_iter_get_array_type (iter)));
2271                 goto out;
2272               }
2273             
2274             switch (type)
2275               {
2276               case DBUS_TYPE_BYTE:
2277                 if (!dbus_message_iter_get_byte_array (iter, (unsigned char **)data, len))
2278                   {
2279                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2280                     goto out;
2281                   }
2282                 break;
2283               case DBUS_TYPE_BOOLEAN:
2284                 if (!dbus_message_iter_get_boolean_array (iter, (unsigned char **)data, len))
2285                   {
2286                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2287                     goto out;
2288                   }
2289                 break;
2290               case DBUS_TYPE_INT32:
2291                 if (!dbus_message_iter_get_int32_array (iter, (dbus_int32_t **)data, len))
2292                   {
2293                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2294                     goto out;
2295                   }
2296                 break;
2297               case DBUS_TYPE_UINT32:
2298                 if (!dbus_message_iter_get_uint32_array (iter, (dbus_uint32_t **)data, len))
2299                   {
2300                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2301                     goto out;
2302                   }
2303                 break;
2304 #ifdef DBUS_HAVE_INT64
2305               case DBUS_TYPE_INT64:
2306                 if (!dbus_message_iter_get_int64_array (iter, (dbus_int64_t **)data, len))
2307                   {
2308                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2309                     goto out;
2310                   }
2311                 break;
2312               case DBUS_TYPE_UINT64:
2313                 if (!dbus_message_iter_get_uint64_array (iter, (dbus_uint64_t **)data, len))
2314                   {
2315                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2316                     goto out;
2317                   }
2318                 break;
2319 #endif /* DBUS_HAVE_INT64 */
2320               case DBUS_TYPE_DOUBLE:
2321                 if (!dbus_message_iter_get_double_array (iter, (double **)data, len))
2322                   {
2323                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2324                     goto out;
2325                   }
2326                 break;
2327               case DBUS_TYPE_STRING:
2328                 if (!dbus_message_iter_get_string_array (iter, (char ***)data, len))
2329                   {
2330                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2331                     goto out;
2332                   }
2333                 break;
2334               case DBUS_TYPE_NIL:
2335               case DBUS_TYPE_ARRAY:
2336               case DBUS_TYPE_CUSTOM:
2337               case DBUS_TYPE_DICT:
2338                 _dbus_warn ("dbus_message_get_args_valist doesn't support recursive arrays\n");
2339                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2340                 goto out;
2341               default:
2342                 _dbus_warn ("Unknown field type %d\n", type);
2343                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2344                 goto out;
2345               }
2346           }
2347           break;
2348         case DBUS_TYPE_DICT:
2349           _dbus_warn ("dbus_message_get_args_valist doesn't support dicts\n");
2350           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2351           goto out;
2352         default:          
2353           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2354           _dbus_warn ("Unknown field type %d\n", spec_type);
2355           goto out;
2356         }
2357       
2358       spec_type = va_arg (var_args, int);
2359       if (spec_type != 0 && !dbus_message_iter_next (iter))
2360         {
2361           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2362                           "Message has only %d arguments, but more were expected", i);
2363           goto out;
2364         }
2365
2366       i++;
2367     }
2368   
2369   retval = TRUE;
2370   
2371  out:
2372   
2373   return retval;
2374 }
2375
2376
2377 /**
2378  * Initializes a DBusMessageIter representing the arguments of the
2379  * message passed in.
2380  *
2381  * @param message the message
2382  * @param iter pointer to an iterator to initialize
2383  */
2384 void
2385 dbus_message_iter_init (DBusMessage     *message,
2386                         DBusMessageIter *iter)
2387 {
2388   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2389
2390   _dbus_return_if_fail (message != NULL);
2391   _dbus_return_if_fail (iter != NULL);
2392   
2393   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
2394   
2395   real->message = message;
2396   real->parent_iter = NULL;
2397   real->changed_stamp = message->changed_stamp;
2398   
2399   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
2400   real->pos = 0;
2401   real->end = _dbus_string_get_length (&message->body);
2402   
2403   real->container_start = 0;
2404   real->container_length_pos = 0;
2405   real->wrote_dict_key = 0;
2406   real->array_type_pos = 0;
2407 }
2408
2409 #ifndef DBUS_DISABLE_CHECKS
2410 static dbus_bool_t
2411 dbus_message_iter_check (DBusMessageRealIter *iter)
2412 {
2413   if (iter == NULL)
2414     {
2415       _dbus_warn ("dbus iterator check failed: iterator is NULL\n");
2416       return FALSE;
2417     }
2418   
2419   if (iter->changed_stamp != iter->message->changed_stamp)
2420     {
2421       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message\n");
2422       return FALSE;
2423     }
2424   
2425   if (iter->pos < 0 || iter->pos > iter->end)
2426     {
2427       _dbus_warn ("dbus iterator check failed: invalid position\n");
2428       return FALSE;
2429     }
2430
2431   return TRUE;
2432 }
2433 #endif /* DBUS_DISABLE_CHECKS */
2434
2435 static int
2436 skip_array_type (DBusMessageRealIter *iter, int pos)
2437 {
2438   const char *data;
2439
2440   do
2441     {
2442       data = _dbus_string_get_const_data_len (&iter->message->body,
2443                                               pos++, 1);
2444     }
2445   while (*data == DBUS_TYPE_ARRAY);
2446   
2447   return pos;
2448 }
2449
2450 /* FIXME what are these _dbus_type_is_valid() checks for?
2451  * haven't we validated the message?
2452  */
2453 static int
2454 dbus_message_iter_get_data_start (DBusMessageRealIter *iter, int *type)
2455 {
2456   const char *data;
2457   int pos, len;
2458   
2459   switch (iter->type)
2460     {
2461     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2462       data = _dbus_string_get_const_data_len (&iter->message->body,
2463                                               iter->pos, 1);
2464       if (_dbus_type_is_valid (*data))
2465         *type = *data;
2466       else
2467         *type = DBUS_TYPE_INVALID;
2468       
2469       return skip_array_type (iter, iter->pos);
2470       
2471     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2472       data = _dbus_string_get_const_data_len (&iter->message->body,
2473                                               iter->array_type_pos, 1);
2474       if (_dbus_type_is_valid (*data))
2475         *type = *data;
2476       else
2477         *type = DBUS_TYPE_INVALID;
2478       
2479       return iter->pos;
2480       
2481     case DBUS_MESSAGE_ITER_TYPE_DICT:
2482       /* Get the length of the string */
2483       len = _dbus_demarshal_uint32 (&iter->message->body,
2484                                     iter->message->byte_order,
2485                                     iter->pos, &pos);
2486       pos = pos + len + 1;
2487
2488       data = _dbus_string_get_const_data_len (&iter->message->body,
2489                                               pos, 1);
2490       if (_dbus_type_is_valid (*data))
2491         *type = *data;
2492       else
2493         *type = DBUS_TYPE_INVALID;
2494
2495       return skip_array_type (iter, pos);
2496       
2497     default:
2498       _dbus_assert_not_reached ("Invalid iter type");
2499       break;
2500     }
2501   *type = DBUS_TYPE_INVALID;
2502   return iter->pos;
2503 }
2504
2505
2506 /**
2507  * Checks if an iterator has any more fields.
2508  *
2509  * @param iter the message iter
2510  * @returns #TRUE if there are more fields
2511  * following
2512  */
2513 dbus_bool_t
2514 dbus_message_iter_has_next (DBusMessageIter *iter)
2515 {
2516   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2517   int end_pos;
2518   int type, pos;
2519
2520   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2521
2522   if (real->pos >= real->end)
2523     return FALSE;
2524   
2525   pos = dbus_message_iter_get_data_start (real, &type);
2526   
2527   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
2528                                       real->message->byte_order,
2529                                       type, pos, &end_pos))
2530     return FALSE;
2531   
2532   if (end_pos >= real->end)
2533     return FALSE;
2534
2535   return TRUE;  
2536 }
2537
2538 /**
2539  * Moves the iterator to the next field.
2540  *
2541  * @param iter The message iter
2542  * @returns #TRUE if the iterator was moved to the next field
2543  */
2544 dbus_bool_t
2545 dbus_message_iter_next (DBusMessageIter *iter)
2546 {
2547   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2548   int end_pos;
2549   int type, pos;
2550
2551   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2552
2553   pos = dbus_message_iter_get_data_start (real, &type);
2554   
2555   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
2556                                       real->message->byte_order,
2557                                       type, pos, &end_pos))
2558     return FALSE;
2559
2560   if (end_pos >= real->end)
2561     return FALSE;
2562
2563   real->pos = end_pos;
2564
2565   return TRUE;
2566 }
2567
2568 /**
2569  * Returns the argument type of the argument that the
2570  * message iterator points at.
2571  *
2572  * @param iter the message iter
2573  * @returns the field type
2574  */
2575 int
2576 dbus_message_iter_get_arg_type (DBusMessageIter *iter)
2577 {
2578   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2579   int type, pos;
2580
2581   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
2582
2583   if (real->pos >= real->end)
2584     {
2585       _dbus_verbose ("  iterator at or beyond end of message\n");
2586       return DBUS_TYPE_INVALID;
2587     }
2588
2589   pos = dbus_message_iter_get_data_start (real, &type);
2590   
2591   return type;
2592 }
2593
2594 /* FIXME why do we validate the typecode in here, hasn't the message
2595  * already been verified?
2596  */
2597 static int
2598 iter_get_array_type (DBusMessageRealIter *iter, int *array_type_pos)
2599 {
2600   const char *data;
2601   int _array_type_pos;
2602   int len, pos;
2603   
2604   switch (iter->type)
2605     {
2606     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2607       _array_type_pos = iter->pos + 1;
2608       break;
2609     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2610       _array_type_pos = iter->array_type_pos + 1;
2611       break;
2612     case DBUS_MESSAGE_ITER_TYPE_DICT:
2613       /* Get the length of the string */
2614       len = _dbus_demarshal_uint32 (&iter->message->body,
2615                                     iter->message->byte_order,
2616                                     iter->pos, &pos);
2617       pos = pos + len + 1;
2618       data = _dbus_string_get_const_data_len (&iter->message->body,
2619                                               pos + 1, 1);
2620       _array_type_pos = pos + 1;
2621       break;
2622     default:
2623       _dbus_assert_not_reached ("wrong iter type");
2624       return DBUS_TYPE_INVALID;
2625     }
2626
2627   if (array_type_pos != NULL)
2628     *array_type_pos = _array_type_pos;
2629   
2630   data = _dbus_string_get_const_data_len (&iter->message->body,
2631                                           _array_type_pos, 1);
2632   if (_dbus_type_is_valid (*data))
2633     return  *data;
2634   
2635   return DBUS_TYPE_INVALID;
2636 }
2637
2638
2639 /**
2640  * Returns the element type of the array that the
2641  * message iterator points at. Note that you need
2642  * to check that the iterator points to an array
2643  * prior to using this function.
2644  *
2645  * @param iter the message iter
2646  * @returns the field type
2647  */
2648 int
2649 dbus_message_iter_get_array_type (DBusMessageIter *iter)
2650 {
2651   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2652   int type, pos;
2653
2654   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
2655
2656   if (real->pos >= real->end)
2657     return DBUS_TYPE_INVALID;
2658
2659   pos = dbus_message_iter_get_data_start (real, &type);
2660
2661   _dbus_assert (type == DBUS_TYPE_ARRAY);
2662
2663   return iter_get_array_type (real, NULL);
2664 }
2665
2666
2667 /**
2668  * Returns the string value that an iterator may point to.
2669  * Note that you need to check that the iterator points to
2670  * a string value before using this function.
2671  *
2672  * @see dbus_message_iter_get_arg_type
2673  * @param iter the message iter
2674  * @returns the string
2675  */
2676 char *
2677 dbus_message_iter_get_string (DBusMessageIter *iter)
2678 {
2679   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2680   int type, pos;
2681
2682   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2683
2684   pos = dbus_message_iter_get_data_start (real, &type);
2685   
2686   _dbus_assert (type == DBUS_TYPE_STRING);
2687
2688   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2689                                  pos, NULL);
2690 }
2691
2692 #if 0
2693 /**
2694  * @todo FIXME to finish this _dbus_demarshal_object_path() needs
2695  * to not explode the path.
2696  * 
2697  * Returns the object path value that an iterator may point to.
2698  * Note that you need to check that the iterator points to
2699  * an object path value before using this function.
2700  *
2701  * @see dbus_message_iter_get_arg_type
2702  * @param iter the message iter
2703  * @returns the path
2704  */
2705 char *
2706 dbus_message_iter_get_object_path (DBusMessageIter  *iter)
2707 {
2708   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2709   int type, pos;
2710
2711   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2712
2713   pos = dbus_message_iter_get_data_start (real, &type);
2714   
2715   _dbus_assert (type == DBUS_TYPE_OBJECT_PATH);
2716
2717   return _dbus_demarshal_object_path (&real->message->body, real->message->byte_order,
2718                                       pos, NULL);
2719 }
2720 #endif
2721
2722 /**
2723  * Returns the name and data from a custom type that an iterator may
2724  * point to. Note that you need to check that the iterator points to a
2725  * custom type before using this function.
2726  *
2727  * @see dbus_message_iter_get_arg_type
2728  * @param iter the message iter
2729  * @param name return location for the name of the custom type
2730  * @param value return location for data
2731  * @param len return location for length of data
2732  * @returns TRUE if get succeed
2733  * 
2734  */
2735 dbus_bool_t
2736 dbus_message_iter_get_custom (DBusMessageIter   *iter,
2737                               char             **name,
2738                               unsigned char    **value,
2739                               int               *len)
2740 {
2741   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2742   int type, pos;
2743   char *_name;
2744
2745   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2746
2747   pos = dbus_message_iter_get_data_start (real, &type);
2748   
2749   _dbus_assert (type == DBUS_TYPE_CUSTOM);
2750   
2751   _name = _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2752                                   pos, &pos);
2753
2754   if (_name == NULL)
2755     return FALSE;
2756   
2757   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
2758                                    pos, NULL, value, len))
2759     {
2760       dbus_free (_name);
2761       return FALSE;
2762     }
2763
2764   *name = _name;
2765   
2766   return TRUE;
2767 }
2768
2769 /**
2770  * Returns the byte value that an iterator may point to.
2771  * Note that you need to check that the iterator points to
2772  * a byte value before using this function.
2773  *
2774  * @see dbus_message_iter_get_arg_type
2775  * @param iter the message iter
2776  * @returns the byte value
2777  */
2778 unsigned char
2779 dbus_message_iter_get_byte (DBusMessageIter *iter)
2780 {
2781   unsigned char value;
2782   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2783   int type, pos;
2784
2785   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2786
2787   pos = dbus_message_iter_get_data_start (real, &type);
2788   
2789   _dbus_assert (type == DBUS_TYPE_BYTE);
2790
2791   value = _dbus_string_get_byte (&real->message->body, pos);
2792   
2793   return value;
2794 }
2795
2796
2797 /**
2798  * Returns the boolean value that an iterator may point to.
2799  * Note that you need to check that the iterator points to
2800  * a boolean value before using this function.
2801  *
2802  * @see dbus_message_iter_get_arg_type
2803  * @param iter the message iter
2804  * @returns the boolean value
2805  */
2806 dbus_bool_t
2807 dbus_message_iter_get_boolean (DBusMessageIter *iter)
2808 {
2809   unsigned char value;
2810   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2811   int type, pos;
2812
2813   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2814
2815   pos = dbus_message_iter_get_data_start (real, &type);
2816   
2817   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
2818
2819   value = _dbus_string_get_byte (&real->message->body, pos);
2820   
2821   return value;
2822 }
2823
2824 /**
2825  * Returns the 32 bit signed integer value that an iterator may point to.
2826  * Note that you need to check that the iterator points to
2827  * a 32-bit integer value before using this function.
2828  *
2829  * @see dbus_message_iter_get_arg_type
2830  * @param iter the message iter
2831  * @returns the integer
2832  */
2833 dbus_int32_t
2834 dbus_message_iter_get_int32 (DBusMessageIter *iter)
2835 {
2836   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2837   int type, pos;
2838
2839   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2840
2841   pos = dbus_message_iter_get_data_start (real, &type);
2842   
2843   _dbus_assert (type == DBUS_TYPE_INT32);
2844   
2845   return _dbus_demarshal_int32 (&real->message->body, real->message->byte_order,
2846                                 pos, NULL);
2847 }
2848
2849 /**
2850  * Returns the 32 bit unsigned integer value that an iterator may point to.
2851  * Note that you need to check that the iterator points to
2852  * a 32-bit unsigned integer value before using this function.
2853  *
2854  * @see dbus_message_iter_get_arg_type
2855  * @param iter the message iter
2856  * @returns the integer
2857  */
2858 dbus_uint32_t
2859 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
2860 {
2861   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2862   int type, pos;
2863
2864   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2865
2866   pos = dbus_message_iter_get_data_start (real, &type);
2867   
2868   _dbus_assert (type == DBUS_TYPE_UINT32);
2869   
2870   return _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2871                                  pos, NULL);
2872 }
2873
2874 #ifdef DBUS_HAVE_INT64
2875
2876 /**
2877  * Returns the 64 bit signed integer value that an iterator may point
2878  * to.  Note that you need to check that the iterator points to a
2879  * 64-bit integer value before using this function.
2880  *
2881  * This function only exists if #DBUS_HAVE_INT64 is defined.
2882  *
2883  * @see dbus_message_iter_get_arg_type
2884  * @param iter the message iter
2885  * @returns the integer
2886  */
2887 dbus_int64_t
2888 dbus_message_iter_get_int64 (DBusMessageIter *iter)
2889 {
2890   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2891   int type, pos;
2892
2893   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2894
2895   pos = dbus_message_iter_get_data_start (real, &type);
2896   
2897   _dbus_assert (type == DBUS_TYPE_INT64);
2898   
2899   return _dbus_demarshal_int64 (&real->message->body, real->message->byte_order,
2900                                 pos, NULL);
2901 }
2902
2903 /**
2904  * Returns the 64 bit unsigned integer value that an iterator may point to.
2905  * Note that you need to check that the iterator points to
2906  * a 64-bit unsigned integer value before using this function.
2907  * 
2908  * This function only exists if #DBUS_HAVE_INT64 is defined.
2909  * 
2910  * @see dbus_message_iter_get_arg_type
2911  * @param iter the message iter
2912  * @returns the integer
2913  */
2914 dbus_uint64_t
2915 dbus_message_iter_get_uint64 (DBusMessageIter *iter)
2916 {
2917   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2918   int type, pos;
2919
2920   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2921
2922   pos = dbus_message_iter_get_data_start (real, &type);
2923   
2924   _dbus_assert (type == DBUS_TYPE_UINT64);
2925   
2926   return _dbus_demarshal_uint64 (&real->message->body, real->message->byte_order,
2927                                  pos, NULL);
2928 }
2929
2930 #endif /* DBUS_HAVE_INT64 */
2931
2932 /**
2933  * Returns the double value that an iterator may point to.
2934  * Note that you need to check that the iterator points to
2935  * a string value before using this function.
2936  *
2937  * @see dbus_message_iter_get_arg_type
2938  * @param iter the message iter
2939  * @returns the double
2940  */
2941 double
2942 dbus_message_iter_get_double (DBusMessageIter *iter)
2943 {
2944   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2945   int type, pos;
2946
2947   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0.0);
2948
2949   pos = dbus_message_iter_get_data_start (real, &type);
2950   
2951   _dbus_assert (type == DBUS_TYPE_DOUBLE);
2952   
2953   return _dbus_demarshal_double (&real->message->body, real->message->byte_order,
2954                                  pos, NULL);
2955 }
2956
2957 /**
2958  * Initializes an iterator for the array that the iterator
2959  * may point to. Note that you need to check that the iterator
2960  * points to an array prior to using this function.
2961  *
2962  * The array element type is returned in array_type, and the array
2963  * iterator can only be used to get that type of data.
2964  *
2965  * @param iter the iterator
2966  * @param array_iter pointer to an iterator to initialize
2967  * @param array_type gets set to the type of the array elements
2968  */
2969 void
2970 dbus_message_iter_init_array_iterator (DBusMessageIter *iter,
2971                                        DBusMessageIter *array_iter,
2972                                        int             *array_type)
2973 {
2974   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2975   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
2976   int type, pos, len_pos, len, array_type_pos;
2977   int _array_type;
2978
2979   _dbus_return_if_fail (dbus_message_iter_check (real));
2980
2981   pos = dbus_message_iter_get_data_start (real, &type);
2982   
2983   _dbus_assert (type == DBUS_TYPE_ARRAY);
2984
2985   _array_type = iter_get_array_type (real, &array_type_pos);
2986   
2987   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
2988   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2989                                 pos, &pos);
2990   
2991   array_real->parent_iter = real;
2992   array_real->message = real->message;
2993   array_real->changed_stamp = real->message->changed_stamp;
2994   
2995   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
2996   array_real->pos = pos;
2997   array_real->end = pos + len;
2998   
2999   array_real->container_start = pos;
3000   array_real->container_length_pos = len_pos;
3001   array_real->wrote_dict_key = 0;
3002   array_real->array_type_pos = array_type_pos;
3003   array_real->array_type_done = TRUE;
3004   
3005   if (array_type != NULL)
3006     *array_type = _array_type;
3007 }
3008
3009
3010 /**
3011  * Initializes an iterator for the dict that the iterator
3012  * may point to. Note that you need to check that the iterator
3013  * points to a dict prior to using this function.
3014  *
3015  * @param iter the iterator
3016  * @param dict_iter pointer to an iterator to initialize
3017  */
3018 void
3019 dbus_message_iter_init_dict_iterator (DBusMessageIter *iter,
3020                                       DBusMessageIter *dict_iter)
3021 {
3022   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3023   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
3024   int type, pos, len_pos, len;
3025
3026   _dbus_return_if_fail (dbus_message_iter_check (real));
3027
3028   pos = dbus_message_iter_get_data_start (real, &type);
3029   
3030   _dbus_assert (type == DBUS_TYPE_DICT);
3031
3032   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
3033   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
3034                                 pos, &pos);
3035   
3036   dict_real->parent_iter = real;
3037   dict_real->message = real->message;
3038   dict_real->changed_stamp = real->message->changed_stamp;
3039   
3040   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
3041   dict_real->pos = pos;
3042   dict_real->end = pos + len;
3043   
3044   dict_real->container_start = pos;
3045   dict_real->container_length_pos = len_pos;
3046   dict_real->wrote_dict_key = 0;
3047 }
3048
3049 /**
3050  * Returns the byte array that the iterator may point to.
3051  * Note that you need to check that the iterator points
3052  * to a byte array prior to using this function.
3053  *
3054  * @param iter the iterator
3055  * @param value return location for array values
3056  * @param len return location for length of byte array
3057  * @returns #TRUE on success
3058  */
3059 dbus_bool_t
3060 dbus_message_iter_get_byte_array (DBusMessageIter  *iter,
3061                                   unsigned char   **value,
3062                                   int              *len)
3063 {
3064   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3065   int type, pos;
3066
3067   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3068
3069   pos = dbus_message_iter_get_data_start (real, &type);
3070   
3071   _dbus_assert (type == DBUS_TYPE_ARRAY);
3072
3073   type = iter_get_array_type (real, NULL);
3074
3075   _dbus_assert (type == DBUS_TYPE_BYTE);
3076
3077   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
3078                                    pos, NULL, value, len))
3079     return FALSE;
3080   else
3081     return TRUE;
3082 }
3083
3084 /**
3085  * Returns the boolean array that the iterator may point to. Note that
3086  * you need to check that the iterator points to an array of the
3087  * correct type prior to using this function.
3088  *
3089  * @param iter the iterator
3090  * @param value return location for the array
3091  * @param len return location for the array length
3092  * @returns #TRUE on success
3093  */
3094 dbus_bool_t
3095 dbus_message_iter_get_boolean_array (DBusMessageIter   *iter,
3096                                      unsigned char    **value,
3097                                      int               *len)
3098 {
3099   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3100   int type, pos;
3101
3102   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3103
3104   pos = dbus_message_iter_get_data_start (real, &type);
3105   
3106   _dbus_assert (type == DBUS_TYPE_ARRAY);
3107
3108   type = iter_get_array_type (real, NULL);
3109
3110   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
3111
3112   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
3113                                    pos, NULL, value, len))
3114     return FALSE;
3115   else
3116     return TRUE;
3117 }
3118
3119 /**
3120  * Returns the 32 bit signed integer array that the iterator may point
3121  * to. Note that you need to check that the iterator points to an
3122  * array of the correct type prior to using this function.
3123  *
3124  * @param iter the iterator
3125  * @param value return location for the array
3126  * @param len return location for the array length
3127  * @returns #TRUE on success
3128  */
3129 dbus_bool_t
3130 dbus_message_iter_get_int32_array  (DBusMessageIter *iter,
3131                                     dbus_int32_t   **value,
3132                                     int             *len)
3133 {
3134   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3135   int type, pos;
3136
3137   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3138
3139   pos = dbus_message_iter_get_data_start (real, &type);
3140   
3141   _dbus_assert (type == DBUS_TYPE_ARRAY);
3142
3143   type = iter_get_array_type (real, NULL);
3144   
3145   _dbus_assert (type == DBUS_TYPE_INT32);
3146
3147   if (!_dbus_demarshal_int32_array (&real->message->body, real->message->byte_order,
3148                                     pos, NULL, value, len))
3149     return FALSE;
3150   else
3151     return TRUE;
3152 }
3153
3154 /**
3155  * Returns the 32 bit unsigned integer array that the iterator may point
3156  * to. Note that you need to check that the iterator points to an
3157  * array of the correct type prior to using this function.
3158  *
3159  * @param iter the iterator
3160  * @param value return location for the array
3161  * @param len return location for the array length
3162  * @returns #TRUE on success
3163  */
3164 dbus_bool_t
3165 dbus_message_iter_get_uint32_array  (DBusMessageIter *iter,
3166                                      dbus_uint32_t  **value,
3167                                      int             *len)
3168 {
3169   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3170   int type, pos;
3171
3172   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3173
3174   pos = dbus_message_iter_get_data_start (real, &type);
3175   
3176   _dbus_assert (type == DBUS_TYPE_ARRAY);
3177
3178   type = iter_get_array_type (real, NULL);
3179   _dbus_assert (type == DBUS_TYPE_UINT32);
3180
3181   if (!_dbus_demarshal_uint32_array (&real->message->body, real->message->byte_order,
3182                                     pos, NULL, value, len))
3183     return FALSE;
3184   else
3185     return TRUE;
3186 }
3187
3188 #ifdef DBUS_HAVE_INT64
3189
3190 /**
3191  * Returns the 64 bit signed integer array that the iterator may point
3192  * to. Note that you need to check that the iterator points to an
3193  * array of the correct type prior to using this function.
3194  * 
3195  * This function only exists if #DBUS_HAVE_INT64 is defined.
3196  *
3197  * @param iter the iterator
3198  * @param value return location for the array
3199  * @param len return location for the array length
3200  * @returns #TRUE on success
3201  */
3202 dbus_bool_t
3203 dbus_message_iter_get_int64_array  (DBusMessageIter *iter,
3204                                     dbus_int64_t   **value,
3205                                     int             *len)
3206 {
3207   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3208   int type, pos;
3209
3210   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3211
3212   pos = dbus_message_iter_get_data_start (real, &type);
3213   
3214   _dbus_assert (type == DBUS_TYPE_ARRAY);
3215
3216   type = iter_get_array_type (real, NULL);
3217   
3218   _dbus_assert (type == DBUS_TYPE_INT64);
3219
3220   if (!_dbus_demarshal_int64_array (&real->message->body, real->message->byte_order,
3221                                     pos, NULL, value, len))
3222     return FALSE;
3223   else
3224     return TRUE;
3225 }
3226
3227 /**
3228  * Returns the 64 bit unsigned integer array that the iterator may point
3229  * to. Note that you need to check that the iterator points to an
3230  * array of the correct type prior to using this function.
3231  *
3232  * This function only exists if #DBUS_HAVE_INT64 is defined.
3233  *
3234  * @param iter the iterator
3235  * @param value return location for the array
3236  * @param len return location for the array length
3237  * @returns #TRUE on success
3238  */
3239 dbus_bool_t
3240 dbus_message_iter_get_uint64_array  (DBusMessageIter *iter,
3241                                      dbus_uint64_t  **value,
3242                                      int             *len)
3243 {
3244   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3245   int type, pos;
3246
3247   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3248
3249   pos = dbus_message_iter_get_data_start (real, &type);
3250   
3251   _dbus_assert (type == DBUS_TYPE_ARRAY);
3252
3253   type = iter_get_array_type (real, NULL);
3254   _dbus_assert (type == DBUS_TYPE_UINT64);
3255
3256   if (!_dbus_demarshal_uint64_array (&real->message->body, real->message->byte_order,
3257                                     pos, NULL, value, len))
3258     return FALSE;
3259   else
3260     return TRUE;
3261 }
3262
3263 #endif /* DBUS_HAVE_INT64 */
3264
3265 /**
3266  * Returns the double array that the iterator may point to. Note that
3267  * you need to check that the iterator points to an array of the
3268  * correct type prior to using this function.
3269  *
3270  * @param iter the iterator
3271  * @param value return location for the array
3272  * @param len return location for the array length
3273  * @returns #TRUE on success
3274  */
3275 dbus_bool_t
3276 dbus_message_iter_get_double_array  (DBusMessageIter *iter,
3277                                      double         **value,
3278                                      int             *len)
3279 {
3280   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3281   int type, pos;
3282
3283   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3284
3285   pos = dbus_message_iter_get_data_start (real, &type);
3286   
3287   _dbus_assert (type == DBUS_TYPE_ARRAY);
3288
3289   type = iter_get_array_type (real, NULL);
3290   _dbus_assert (type == DBUS_TYPE_DOUBLE);
3291
3292   if (!_dbus_demarshal_double_array (&real->message->body, real->message->byte_order,
3293                                      pos, NULL, value, len))
3294     return FALSE;
3295   else
3296     return TRUE;
3297 }
3298
3299 /**
3300  * Returns the string array that the iterator may point to.
3301  * Note that you need to check that the iterator points
3302  * to a string array prior to using this function.
3303  *
3304  * The returned value is a #NULL-terminated array of strings.
3305  * Each string is a separate malloc block, and the array
3306  * itself is a malloc block. You can free this type of
3307  * string array with dbus_free_string_array().
3308  *
3309  * @param iter the iterator
3310  * @param value return location for string values
3311  * @param len return location for length of byte array
3312  * @returns #TRUE on success
3313  */
3314 dbus_bool_t
3315 dbus_message_iter_get_string_array (DBusMessageIter *iter,
3316                                     char          ***value,
3317                                     int             *len)
3318 {
3319   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3320   int type, pos;
3321
3322   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3323
3324   pos = dbus_message_iter_get_data_start (real, &type);
3325   
3326   _dbus_assert (type == DBUS_TYPE_ARRAY);
3327
3328   type = iter_get_array_type (real, NULL);
3329   _dbus_assert (type == DBUS_TYPE_STRING);
3330
3331   if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order,
3332                                      pos, NULL, value, len))
3333     return FALSE;
3334   else
3335     return TRUE;
3336 }
3337
3338 #if 0
3339 /**
3340  * @todo FIXME to implement this _dbus_demarshal_object_path_array()
3341  * needs implementing
3342  * 
3343  * Returns the object path array that the iterator may point to.
3344  * Note that you need to check that the iterator points
3345  * to an object path array prior to using this function.
3346  *
3347  * The returned value is a #NULL-terminated array of strings.
3348  * Each string is a separate malloc block, and the array
3349  * itself is a malloc block. You can free this type of
3350  * array with dbus_free_string_array().
3351  *
3352  * @param iter the iterator
3353  * @param value return location for string values
3354  * @param len return location for length of byte array
3355  * @returns #TRUE on success
3356  */
3357 dbus_bool_t
3358 dbus_message_iter_get_object_path_array (DBusMessageIter *iter,
3359                                          char          ***value,
3360                                          int             *len)
3361 {
3362   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3363   int type, pos;
3364
3365   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3366
3367   pos = dbus_message_iter_get_data_start (real, &type);
3368   
3369   _dbus_assert (type == DBUS_TYPE_ARRAY);
3370
3371   type = iter_get_array_type (real, NULL);
3372   _dbus_assert (type == DBUS_TYPE_OBJECT_PATH);
3373
3374   if (!_dbus_demarshal_object_path_array (&real->message->body, real->message->byte_order,
3375                                           pos, NULL, value, len))
3376     return FALSE;
3377   else
3378     return TRUE;
3379 }
3380 #endif
3381
3382 /**
3383  * Returns the key name fot the dict entry that an iterator
3384  * may point to. Note that you need to check that the iterator
3385  * points to a dict entry before using this function.
3386  *
3387  * @see dbus_message_iter_init_dict_iterator
3388  * @param iter the message iter
3389  * @returns the key name
3390  */
3391 char *
3392 dbus_message_iter_get_dict_key (DBusMessageIter   *iter)
3393 {
3394   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3395
3396   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
3397
3398   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
3399
3400   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
3401                                  real->pos, NULL);
3402 }
3403
3404 /**
3405  * Initializes a DBusMessageIter pointing to the end of the
3406  * message. This iterator can be used to append data to the
3407  * message.
3408  *
3409  * @param message the message
3410  * @param iter pointer to an iterator to initialize
3411  */
3412 void
3413 dbus_message_append_iter_init (DBusMessage     *message,
3414                                DBusMessageIter *iter)
3415 {
3416   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3417
3418   _dbus_return_if_fail (message != NULL);
3419   _dbus_return_if_fail (iter != NULL);
3420   
3421   real->message = message;
3422   real->parent_iter = NULL;
3423   real->changed_stamp = message->changed_stamp;
3424   
3425   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
3426   real->end = _dbus_string_get_length (&real->message->body);
3427   real->pos = real->end;
3428   
3429   real->container_length_pos = 0;
3430   real->wrote_dict_key = 0;
3431 }
3432
3433 #ifndef DBUS_DISABLE_CHECKS
3434 static dbus_bool_t
3435 dbus_message_iter_append_check (DBusMessageRealIter *iter)
3436 {
3437   if (iter == NULL)
3438     {
3439       _dbus_warn ("dbus iterator check failed: NULL iterator\n");
3440       return FALSE;
3441     }
3442   
3443   if (iter->message->locked)
3444     {
3445       _dbus_warn ("dbus iterator check failed: message is locked (has already been sent)\n");
3446       return FALSE;
3447     }
3448       
3449   if (iter->changed_stamp != iter->message->changed_stamp)
3450     {
3451       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message");
3452       return FALSE;
3453     }
3454   
3455   if (iter->pos != iter->end)
3456     {
3457       _dbus_warn ("dbus iterator check failed: can only append at end of message");
3458       return FALSE;
3459     }
3460   
3461   if (iter->pos != _dbus_string_get_length (&iter->message->body))
3462     {
3463       _dbus_warn ("dbus iterator check failed: append pos not at end of message string");
3464       return FALSE;
3465     }
3466
3467   return TRUE;
3468 }
3469 #endif /* DBUS_DISABLE_CHECKS */
3470
3471 static dbus_bool_t
3472 dbus_message_iter_append_type (DBusMessageRealIter *iter,
3473                                int                  type)
3474 {
3475   const char *data;
3476   switch (iter->type)
3477     {
3478     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
3479       if (!_dbus_string_append_byte (&iter->message->signature, type))
3480         return FALSE;
3481       
3482       if (!_dbus_string_append_byte (&iter->message->body, type))
3483         {
3484           _dbus_string_shorten (&iter->message->signature, 1);
3485           return FALSE;
3486         }
3487       break;
3488       
3489     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
3490       data = _dbus_string_get_const_data_len (&iter->message->body,
3491                                               iter->array_type_pos, 1);
3492       if (type != *data)
3493         {
3494           _dbus_warn ("Appended element of wrong type for array\n");
3495           return FALSE;
3496         }
3497       break;
3498       
3499     case DBUS_MESSAGE_ITER_TYPE_DICT:
3500       if (!iter->wrote_dict_key)
3501         {
3502           _dbus_warn ("Appending dict data before key name\n");
3503           return FALSE;
3504         }
3505       
3506       if (!_dbus_string_append_byte (&iter->message->body, type))
3507         return FALSE;
3508       
3509       break;
3510       
3511     default:
3512       _dbus_assert_not_reached ("Invalid iter type");
3513       break;
3514     }
3515   
3516   return TRUE;
3517 }
3518
3519 static void
3520 dbus_message_iter_update_after_change (DBusMessageRealIter *iter)
3521 {
3522   iter->changed_stamp = iter->message->changed_stamp;
3523   
3524   /* Set new end of iter */
3525   iter->end = _dbus_string_get_length (&iter->message->body);
3526   iter->pos = iter->end;
3527
3528   /* Set container length */
3529   if (iter->type == DBUS_MESSAGE_ITER_TYPE_DICT ||
3530       (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY && iter->array_type_done))
3531     _dbus_marshal_set_uint32 (&iter->message->body,
3532                               iter->message->byte_order,
3533                               iter->container_length_pos,
3534                               iter->end - iter->container_start);
3535   
3536   if (iter->parent_iter)
3537     dbus_message_iter_update_after_change (iter->parent_iter);
3538 }
3539
3540 static void
3541 dbus_message_iter_append_done (DBusMessageRealIter *iter)
3542 {
3543   iter->message->changed_stamp++;
3544   dbus_message_iter_update_after_change (iter);
3545   iter->wrote_dict_key = FALSE;
3546 }
3547
3548 /**
3549  * Appends a nil value to the message
3550  *
3551  * @param iter an iterator pointing to the end of the message
3552  * @returns #TRUE on success
3553  */
3554 dbus_bool_t
3555 dbus_message_iter_append_nil (DBusMessageIter *iter)
3556 {
3557   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3558
3559   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3560
3561   if (!dbus_message_iter_append_type (real, DBUS_TYPE_NIL))
3562     return FALSE;
3563   
3564   dbus_message_iter_append_done (real);
3565   
3566   return TRUE;
3567 }
3568
3569 /**
3570  * Appends a boolean value to the message
3571  *
3572  * @param iter an iterator pointing to the end of the message
3573  * @param value the boolean value
3574  * @returns #TRUE on success
3575  */
3576 dbus_bool_t
3577 dbus_message_iter_append_boolean (DBusMessageIter *iter,
3578                                   dbus_bool_t     value)
3579 {
3580   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3581
3582   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3583
3584   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BOOLEAN))
3585     return FALSE;
3586   
3587   if (!_dbus_string_append_byte (&real->message->body, (value != FALSE)))
3588     {
3589       _dbus_string_set_length (&real->message->body, real->pos);
3590       return FALSE;
3591     }
3592
3593   dbus_message_iter_append_done (real);
3594   
3595   return TRUE;
3596 }
3597
3598 /**
3599  * Appends a byte to the message
3600  *
3601  * @param iter an iterator pointing to the end of the message
3602  * @param value the byte value
3603  * @returns #TRUE on success
3604  */
3605 dbus_bool_t
3606 dbus_message_iter_append_byte (DBusMessageIter *iter,
3607                                unsigned char    value)
3608 {
3609   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3610
3611   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3612
3613   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BYTE))
3614     return FALSE;
3615   
3616   if (!_dbus_string_append_byte (&real->message->body, value))
3617     {
3618       _dbus_string_set_length (&real->message->body, real->pos);
3619       return FALSE;
3620     }
3621
3622   dbus_message_iter_append_done (real);
3623   
3624   return TRUE;
3625 }
3626
3627
3628 /**
3629  * Appends a 32 bit signed integer to the message.
3630  *
3631  * @param iter an iterator pointing to the end of the message
3632  * @param value the integer value
3633  * @returns #TRUE on success
3634  */
3635 dbus_bool_t
3636 dbus_message_iter_append_int32   (DBusMessageIter *iter,
3637                                   dbus_int32_t  value)
3638 {
3639   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3640
3641   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3642
3643   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT32))
3644     return FALSE;
3645   
3646   if (!_dbus_marshal_int32 (&real->message->body, real->message->byte_order, value))
3647     {
3648       _dbus_string_set_length (&real->message->body, real->pos);
3649       return FALSE;
3650     }
3651
3652   dbus_message_iter_append_done (real);
3653   
3654   return TRUE;
3655 }
3656
3657 /**
3658  * Appends a 32 bit unsigned integer to the message.
3659  *
3660  * @param iter an iterator pointing to the end of the message
3661  * @param value the integer value
3662  * @returns #TRUE on success
3663  */
3664 dbus_bool_t
3665 dbus_message_iter_append_uint32 (DBusMessageIter *iter,
3666                                  dbus_uint32_t    value)
3667 {
3668   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3669
3670   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3671
3672   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT32))
3673     return FALSE;
3674   
3675   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, value))
3676     {
3677       _dbus_string_set_length (&real->message->body, real->pos);
3678       return FALSE;
3679     }
3680
3681   dbus_message_iter_append_done (real);
3682   
3683   return TRUE;
3684 }
3685
3686 #ifdef DBUS_HAVE_INT64
3687
3688 /**
3689  * Appends a 64 bit signed integer to the message.
3690  *
3691  * This function only exists if #DBUS_HAVE_INT64 is defined.
3692  *
3693  * @param iter an iterator pointing to the end of the message
3694  * @param value the integer value
3695  * @returns #TRUE on success
3696  */
3697 dbus_bool_t
3698 dbus_message_iter_append_int64   (DBusMessageIter *iter,
3699                                   dbus_int64_t  value)
3700 {
3701   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3702
3703   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3704
3705   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT64))
3706     return FALSE;
3707   
3708   if (!_dbus_marshal_int64 (&real->message->body, real->message->byte_order, value))
3709     {
3710       _dbus_string_set_length (&real->message->body, real->pos);
3711       return FALSE;
3712     }
3713
3714   dbus_message_iter_append_done (real);
3715   
3716   return TRUE;
3717 }
3718
3719 /**
3720  * Appends a 64 bit unsigned integer to the message.
3721  *
3722  * This function only exists if #DBUS_HAVE_INT64 is defined.
3723  *
3724  * @param iter an iterator pointing to the end of the message
3725  * @param value the integer value
3726  * @returns #TRUE on success
3727  */
3728 dbus_bool_t
3729 dbus_message_iter_append_uint64 (DBusMessageIter *iter,
3730                                  dbus_uint64_t    value)
3731 {
3732   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3733
3734   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3735
3736   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT64))
3737     return FALSE;
3738   
3739   if (!_dbus_marshal_uint64 (&real->message->body, real->message->byte_order, value))
3740     {
3741       _dbus_string_set_length (&real->message->body, real->pos);
3742       return FALSE;
3743     }
3744
3745   dbus_message_iter_append_done (real);
3746   
3747   return TRUE;
3748 }
3749
3750 #endif /* DBUS_HAVE_INT64 */
3751
3752 /**
3753  * Appends a double value to the message.
3754  *
3755  * @param iter an iterator pointing to the end of the message
3756  * @param value the double value
3757  * @returns #TRUE on success
3758  */
3759 dbus_bool_t
3760 dbus_message_iter_append_double (DBusMessageIter *iter,
3761                                  double           value)
3762 {
3763   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3764
3765   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3766
3767   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DOUBLE))
3768     return FALSE;
3769   
3770   if (!_dbus_marshal_double (&real->message->body, real->message->byte_order, value))
3771     {
3772       _dbus_string_set_length (&real->message->body, real->pos);
3773       return FALSE;
3774     }
3775
3776   dbus_message_iter_append_done (real);
3777   
3778   return TRUE;
3779 }
3780
3781 /**
3782  * Appends a UTF-8 string to the message.
3783  *
3784  * @todo add return_val_if_fail(UTF-8 is valid)
3785  *
3786  * @param iter an iterator pointing to the end of the message
3787  * @param value the string
3788  * @returns #TRUE on success
3789  */
3790 dbus_bool_t
3791 dbus_message_iter_append_string (DBusMessageIter *iter,
3792                                  const char      *value)
3793 {
3794   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3795
3796   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3797   
3798   if (!dbus_message_iter_append_type (real, DBUS_TYPE_STRING))
3799     return FALSE;
3800   
3801   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3802     {
3803       _dbus_string_set_length (&real->message->body, real->pos);
3804       return FALSE;
3805     }
3806
3807   dbus_message_iter_append_done (real);
3808   
3809   return TRUE;
3810 }
3811
3812 /**
3813  * Appends a custom type data chunk to the message. A custom
3814  * type is simply an arbitrary UTF-8 string used as a type
3815  * tag, plus an array of arbitrary bytes to be interpreted
3816  * according to the type tag.
3817  *
3818  * @param iter an iterator pointing to the end of the message
3819  * @param name the name of the type
3820  * @param data the binary data used to store the value
3821  * @param len the length of the binary data in bytes
3822  * @returns #TRUE on success
3823  */
3824 dbus_bool_t
3825 dbus_message_iter_append_custom (DBusMessageIter      *iter,
3826                                  const char           *name,
3827                                  const unsigned char  *data,
3828                                  int                   len)
3829 {
3830   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3831
3832   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3833
3834   if (!dbus_message_iter_append_type (real, DBUS_TYPE_CUSTOM))
3835     return FALSE;
3836   
3837    if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, name))
3838     {
3839       _dbus_string_set_length (&real->message->body, real->pos);
3840       return FALSE;
3841     }
3842    
3843   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, data, len))
3844     {
3845       _dbus_string_set_length (&real->message->body, real->pos);
3846       return FALSE;
3847     }
3848
3849   dbus_message_iter_append_done (real);
3850   
3851   return TRUE;
3852 }
3853
3854
3855 /**
3856  * Appends a dict key name to the message. The iterator used
3857  * must point to a dict.
3858  *
3859  * @param iter an iterator pointing to the end of the message
3860  * @param value the string
3861  * @returns #TRUE on success
3862  */
3863 dbus_bool_t
3864 dbus_message_iter_append_dict_key (DBusMessageIter *iter,
3865                                    const char      *value)
3866 {
3867   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3868
3869   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3870   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
3871   
3872   if (real->wrote_dict_key)
3873     {
3874       _dbus_warn ("Appendinging multiple dict key names\n");
3875       return FALSE;
3876     }
3877   
3878   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3879     {
3880       return FALSE;
3881     }
3882
3883   dbus_message_iter_append_done (real);
3884   real->wrote_dict_key = TRUE;
3885   
3886   return TRUE;
3887 }
3888
3889 static dbus_bool_t
3890 array_iter_type_mark_done (DBusMessageRealIter *iter)
3891 {
3892   int len_pos;
3893   
3894   if (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY)
3895     array_iter_type_mark_done (iter->parent_iter);
3896   else
3897     return TRUE;
3898
3899   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&iter->message->body),
3900                                sizeof (dbus_uint32_t));
3901
3902   /* Empty length for now, backfill later */
3903   if (!_dbus_marshal_uint32 (&iter->message->body, iter->message->byte_order, 0))
3904     {
3905       _dbus_string_set_length (&iter->message->body, iter->pos);
3906       return FALSE;
3907     }
3908
3909   iter->container_start = _dbus_string_get_length (&iter->message->body);
3910   iter->container_length_pos = len_pos;
3911   iter->array_type_done = TRUE;
3912
3913   return TRUE;
3914 }
3915
3916 static dbus_bool_t
3917 append_array_type (DBusMessageRealIter *real,
3918                    int                  element_type,
3919                    dbus_bool_t         *array_type_done,
3920                    int                 *array_type_pos)
3921 {
3922   int existing_element_type;
3923   
3924   if (!dbus_message_iter_append_type (real, DBUS_TYPE_ARRAY))
3925     return FALSE;
3926   
3927   if (real->type == DBUS_MESSAGE_ITER_TYPE_ARRAY &&
3928       real->array_type_done)
3929     {
3930       existing_element_type = iter_get_array_type (real, array_type_pos);
3931       if (existing_element_type != element_type)
3932         {
3933           _dbus_warn ("Appending array of %s, when expecting array of %s\n",
3934                       _dbus_type_to_string (element_type),
3935                       _dbus_type_to_string (existing_element_type));
3936           _dbus_string_set_length (&real->message->body, real->pos);
3937           return FALSE;
3938         }
3939       if (array_type_done != NULL)
3940           *array_type_done = TRUE;
3941     }
3942   else
3943     {
3944       if (array_type_pos != NULL)
3945         *array_type_pos = _dbus_string_get_length (&real->message->body);
3946
3947
3948       if (!_dbus_string_append_byte (&real->message->signature, element_type))
3949         {
3950           _dbus_string_set_length (&real->message->body, real->pos);
3951           return FALSE;
3952         }
3953       
3954       /* Append element type */
3955       if (!_dbus_string_append_byte (&real->message->body, element_type))
3956         {
3957           _dbus_string_shorten (&real->message->signature, 1);
3958           _dbus_string_set_length (&real->message->body, real->pos);
3959           return FALSE;
3960         }
3961
3962       if (array_type_done != NULL)
3963         *array_type_done = element_type != DBUS_TYPE_ARRAY;
3964       
3965       if (element_type != DBUS_TYPE_ARRAY &&
3966           !array_iter_type_mark_done (real))
3967         {
3968           _dbus_string_shorten (&real->message->signature, 1);
3969           return FALSE;
3970         }        
3971     }
3972
3973   return TRUE;
3974 }
3975
3976 /**
3977  * Appends an array to the message and initializes an iterator that
3978  * can be used to append to the array.
3979  *
3980  * @param iter an iterator pointing to the end of the message
3981  * @param array_iter pointer to an iter that will be initialized
3982  * @param element_type the type of the array elements
3983  * @returns #TRUE on success
3984  */
3985 dbus_bool_t
3986 dbus_message_iter_append_array (DBusMessageIter      *iter,
3987                                 DBusMessageIter      *array_iter,
3988                                 int                   element_type)
3989 {
3990   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3991   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
3992   int len_pos;
3993   int array_type_pos;
3994   dbus_bool_t array_type_done;
3995
3996   if (element_type == DBUS_TYPE_NIL)
3997     {
3998       _dbus_warn ("Can't create NIL arrays\n");
3999       return FALSE;
4000     }
4001   
4002   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4003
4004   if (!append_array_type (real, element_type, &array_type_done, &array_type_pos))
4005     return FALSE;
4006
4007   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
4008
4009   if (array_type_done)
4010     {
4011       /* Empty length for now, backfill later */
4012       if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
4013         {
4014           _dbus_string_set_length (&real->message->body, real->pos);
4015           return FALSE;
4016         }
4017     }
4018   
4019   array_real->parent_iter = real;
4020   array_real->message = real->message;
4021   array_real->changed_stamp = real->message->changed_stamp;
4022   
4023   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
4024   array_real->pos = _dbus_string_get_length (&real->message->body);
4025   array_real->end = array_real->end;
4026   
4027   array_real->container_start = array_real->pos;
4028   array_real->container_length_pos = len_pos;
4029   array_real->wrote_dict_key = 0;
4030   array_real->array_type_done = array_type_done;
4031   array_real->array_type_pos = array_type_pos;
4032
4033   dbus_message_iter_append_done (array_real);
4034   
4035   return TRUE;
4036 }
4037
4038 /**
4039  * Appends a dict to the message and initializes an iterator that
4040  * can be used to append to the dict.
4041  *
4042  * @param iter an iterator pointing to the end of the message
4043  * @param dict_iter pointer to an iter that will be initialized
4044  * @returns #TRUE on success
4045  */
4046 dbus_bool_t
4047 dbus_message_iter_append_dict (DBusMessageIter      *iter,
4048                                DBusMessageIter      *dict_iter)
4049 {
4050   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4051   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
4052   int len_pos;
4053
4054   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4055   
4056   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DICT))
4057     return FALSE;  
4058   
4059   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
4060
4061   /* Empty length for now, backfill later */
4062   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
4063     {
4064       _dbus_string_set_length (&real->message->body, real->pos);
4065       return FALSE;
4066     }
4067   
4068   dict_real->parent_iter = real;
4069   dict_real->message = real->message;
4070   dict_real->changed_stamp = real->message->changed_stamp;
4071   
4072   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
4073   dict_real->pos = _dbus_string_get_length (&real->message->body);
4074   dict_real->end = dict_real->end;
4075   
4076   dict_real->container_start = dict_real->pos;
4077   dict_real->container_length_pos = len_pos;
4078   dict_real->wrote_dict_key = 0;
4079
4080   dbus_message_iter_append_done (dict_real);
4081   
4082   return TRUE;
4083 }
4084
4085
4086 /**
4087  * Appends a boolean array to the message.
4088  *
4089  * @param iter an iterator pointing to the end of the message
4090  * @param value the array
4091  * @param len the length of the array
4092  * @returns #TRUE on success
4093  */
4094 dbus_bool_t
4095 dbus_message_iter_append_boolean_array (DBusMessageIter     *iter,
4096                                         unsigned const char *value,
4097                                         int                  len)
4098 {
4099   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4100
4101   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4102
4103   if (!append_array_type (real, DBUS_TYPE_BOOLEAN, NULL, NULL))
4104     return FALSE;
4105   
4106   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
4107     {
4108       _dbus_string_set_length (&real->message->body, real->pos);
4109       return FALSE;
4110     }
4111
4112   dbus_message_iter_append_done (real);
4113   
4114   return TRUE;
4115 }
4116
4117 /**
4118  * Appends a 32 bit signed integer array to the message.
4119  *
4120  * @param iter an iterator pointing to the end of the message
4121  * @param value the array
4122  * @param len the length of the array
4123  * @returns #TRUE on success
4124  */
4125 dbus_bool_t
4126 dbus_message_iter_append_int32_array (DBusMessageIter    *iter,
4127                                       const dbus_int32_t *value,
4128                                       int                 len)
4129 {
4130   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4131
4132   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4133
4134   if (!append_array_type (real, DBUS_TYPE_INT32, NULL, NULL))
4135     return FALSE;
4136   
4137   if (!_dbus_marshal_int32_array (&real->message->body, real->message->byte_order, value, len))
4138     {
4139       _dbus_string_set_length (&real->message->body, real->pos);
4140       return FALSE;
4141     }
4142
4143   dbus_message_iter_append_done (real);
4144   
4145   return TRUE;
4146 }
4147
4148 /**
4149  * Appends a 32 bit unsigned integer array to the message.
4150  *
4151  * @param iter an iterator pointing to the end of the message
4152  * @param value the array
4153  * @param len the length of the array
4154  * @returns #TRUE on success
4155  */
4156 dbus_bool_t
4157 dbus_message_iter_append_uint32_array (DBusMessageIter     *iter,
4158                                        const dbus_uint32_t *value,
4159                                        int                  len)
4160 {
4161   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4162
4163   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4164
4165   if (!append_array_type (real, DBUS_TYPE_UINT32, NULL, NULL))
4166     return FALSE;
4167   
4168   if (!_dbus_marshal_uint32_array (&real->message->body, real->message->byte_order, value, len))
4169     {
4170       _dbus_string_set_length (&real->message->body, real->pos);
4171       return FALSE;
4172     }
4173
4174   dbus_message_iter_append_done (real);
4175   
4176   return TRUE;
4177 }
4178
4179 #ifdef DBUS_HAVE_INT64
4180
4181 /**
4182  * Appends a 64 bit signed integer array to the message.
4183  *
4184  * This function only exists if #DBUS_HAVE_INT64 is defined.
4185  *
4186  * @param iter an iterator pointing to the end of the message
4187  * @param value the array
4188  * @param len the length of the array
4189  * @returns #TRUE on success
4190  */
4191 dbus_bool_t
4192 dbus_message_iter_append_int64_array (DBusMessageIter    *iter,
4193                                       const dbus_int64_t *value,
4194                                       int                 len)
4195 {
4196   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4197
4198   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4199
4200   if (!append_array_type (real, DBUS_TYPE_INT64, NULL, NULL))
4201     return FALSE;
4202   
4203   if (!_dbus_marshal_int64_array (&real->message->body, real->message->byte_order, value, len))
4204     {
4205       _dbus_string_set_length (&real->message->body, real->pos);
4206       return FALSE;
4207     }
4208
4209   dbus_message_iter_append_done (real);
4210   
4211   return TRUE;
4212 }
4213
4214 /**
4215  * Appends a 64 bit unsigned integer array to the message.
4216  *
4217  * This function only exists if #DBUS_HAVE_INT64 is defined.
4218  *
4219  * @param iter an iterator pointing to the end of the message
4220  * @param value the array
4221  * @param len the length of the array
4222  * @returns #TRUE on success
4223  */
4224 dbus_bool_t
4225 dbus_message_iter_append_uint64_array (DBusMessageIter     *iter,
4226                                        const dbus_uint64_t *value,
4227                                        int                  len)
4228 {
4229   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4230
4231   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4232
4233   if (!append_array_type (real, DBUS_TYPE_UINT64, NULL, NULL))
4234     return FALSE;
4235   
4236   if (!_dbus_marshal_uint64_array (&real->message->body, real->message->byte_order, value, len))
4237     {
4238       _dbus_string_set_length (&real->message->body, real->pos);
4239       return FALSE;
4240     }
4241
4242   dbus_message_iter_append_done (real);
4243   
4244   return TRUE;
4245 }
4246 #endif /* DBUS_HAVE_INT64 */
4247
4248 /**
4249  * Appends a double array to the message.
4250  *
4251  * @param iter an iterator pointing to the end of the message
4252  * @param value the array
4253  * @param len the length of the array
4254  * @returns #TRUE on success
4255  */
4256 dbus_bool_t
4257 dbus_message_iter_append_double_array (DBusMessageIter *iter,
4258                                        const double    *value,
4259                                        int              len)
4260 {
4261   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4262
4263   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4264
4265   if (!append_array_type (real, DBUS_TYPE_DOUBLE, NULL, NULL))
4266     return FALSE;
4267   
4268   if (!_dbus_marshal_double_array (&real->message->body, real->message->byte_order, value, len))
4269     {
4270       _dbus_string_set_length (&real->message->body, real->pos);
4271       return FALSE;
4272     }
4273
4274   dbus_message_iter_append_done (real);
4275   
4276   return TRUE;
4277 }
4278
4279 /**
4280  * Appends a byte array to the message.
4281  *
4282  * @param iter an iterator pointing to the end of the message
4283  * @param value the array
4284  * @param len the length of the array
4285  * @returns #TRUE on success
4286  */
4287 dbus_bool_t
4288 dbus_message_iter_append_byte_array (DBusMessageIter     *iter,
4289                                      unsigned const char *value,
4290                                      int                  len)
4291 {
4292   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4293
4294   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4295
4296   if (!append_array_type (real, DBUS_TYPE_BYTE, NULL, NULL))
4297     return FALSE;
4298   
4299   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
4300     {
4301       _dbus_string_set_length (&real->message->body, real->pos);
4302       return FALSE;
4303     }
4304
4305   dbus_message_iter_append_done (real);
4306   
4307   return TRUE;
4308 }
4309
4310 /**
4311  * Appends a string array to the message.
4312  *
4313  * @param iter an iterator pointing to the end of the message
4314  * @param value the array
4315  * @param len the length of the array
4316  * @returns #TRUE on success
4317  */
4318 dbus_bool_t
4319 dbus_message_iter_append_string_array (DBusMessageIter *iter,
4320                                        const char     **value,
4321                                        int              len)
4322 {
4323   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4324
4325   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4326
4327   if (!append_array_type (real, DBUS_TYPE_STRING, NULL, NULL))
4328     return FALSE;
4329   
4330   if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len))
4331     {
4332       _dbus_string_set_length (&real->message->body, real->pos);
4333       return FALSE;
4334     }
4335
4336   dbus_message_iter_append_done (real);
4337   
4338   return TRUE;
4339 }
4340
4341 /**
4342  * Sets the message sender.
4343  *
4344  * @param message the message
4345  * @param sender the sender
4346  * @returns #FALSE if not enough memory
4347  */
4348 dbus_bool_t
4349 dbus_message_set_sender (DBusMessage  *message,
4350                          const char   *sender)
4351 {
4352   _dbus_return_val_if_fail (message != NULL, FALSE);
4353   _dbus_return_val_if_fail (!message->locked, FALSE);
4354
4355   return set_string_field (message,
4356                            DBUS_HEADER_FIELD_SENDER_SERVICE,
4357                            DBUS_TYPE_STRING,
4358                            sender);
4359 }
4360
4361 /**
4362  * Sets a flag indicating that the message does not want a reply; if
4363  * this flag is set, the other end of the connection may (but is not
4364  * required to) optimize by not sending method return or error
4365  * replies. If this flag is set, there is no way to know whether the
4366  * message successfully arrived at the remote end.
4367  *
4368  * @param message the message
4369  * @param no_reply #TRUE if no reply is desired
4370  */
4371 void
4372 dbus_message_set_no_reply (DBusMessage *message,
4373                            dbus_bool_t  no_reply)
4374 {
4375   char *header;
4376
4377   _dbus_return_if_fail (message != NULL);
4378   _dbus_return_if_fail (!message->locked);
4379   
4380   header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1);
4381   
4382   if (no_reply)
4383     *header |= DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;
4384   else
4385     *header &= ~DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;    
4386 }
4387
4388 /**
4389  * Returns #TRUE if the message does not expect
4390  * a reply.
4391  *
4392  * @param message the message
4393  * @returns #TRUE if the message sender isn't waiting for a reply
4394  */
4395 dbus_bool_t
4396 dbus_message_get_no_reply (DBusMessage *message)
4397 {
4398   const char *header;
4399
4400   _dbus_return_val_if_fail (message != NULL, FALSE);
4401   
4402   header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1);
4403
4404   return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0;
4405 }
4406
4407 /**
4408  * Gets the service which originated this message,
4409  * or #NULL if unknown or inapplicable.
4410  *
4411  * @param message the message
4412  * @returns the service name or #NULL
4413  */
4414 const char*
4415 dbus_message_get_sender (DBusMessage *message)
4416 {
4417   _dbus_return_val_if_fail (message != NULL, NULL);
4418   
4419   return get_string_field (message, 
4420                            DBUS_HEADER_FIELD_SENDER_SERVICE,
4421                            NULL);
4422 }
4423
4424 /**
4425  * Gets the type signature of the message, i.e. the arguments in the
4426  * message payload. The signature includes only "in" arguments for
4427  * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for
4428  * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from
4429  * what you might expect (it does not include the signature of the
4430  * entire C++-style method).
4431  *
4432  * The signature is a string made up of type codes such
4433  * as #DBUS_TYPE_STRING. The string is terminated with nul
4434  * (nul is also the value of #DBUS_TYPE_INVALID).
4435  * 
4436  * @param message the message
4437  * @returns the type signature
4438  */
4439 const char*
4440 dbus_message_get_signature (DBusMessage *message)
4441 {
4442   _dbus_return_val_if_fail (message != NULL, NULL);
4443   
4444   return _dbus_string_get_const_data (&message->signature);
4445 }
4446
4447 static dbus_bool_t
4448 _dbus_message_has_type_interface_member (DBusMessage *message,
4449                                          int          type,
4450                                          const char  *interface,
4451                                          const char  *method)
4452 {
4453   const char *n;
4454
4455   _dbus_assert (message != NULL);
4456   _dbus_assert (interface != NULL);
4457   _dbus_assert (method != NULL);
4458
4459   if (dbus_message_get_type (message) != type)
4460     return FALSE;
4461
4462   /* Optimize by checking the short method name first
4463    * instead of the longer interface name
4464    */  
4465
4466   n = dbus_message_get_member (message);
4467
4468   if (n && strcmp (n, method) == 0)
4469     {
4470       n = dbus_message_get_interface (message);
4471       
4472       if (n && strcmp (n, interface) == 0)
4473         return TRUE;
4474     }
4475
4476   return FALSE;
4477 }
4478
4479 /**
4480  * Checks whether the message is a method call with the given
4481  * interface and member fields.  If the message is not
4482  * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or member field,
4483  * returns #FALSE.
4484  *
4485  * @param message the message
4486  * @param interface the name to check (must not be #NULL)
4487  * @param method the name to check (must not be #NULL)
4488  * 
4489  * @returns #TRUE if the message is the specified method call
4490  */
4491 dbus_bool_t
4492 dbus_message_is_method_call (DBusMessage *message,
4493                              const char  *interface,
4494                              const char  *method)
4495 {
4496   _dbus_return_val_if_fail (message != NULL, FALSE);
4497   _dbus_return_val_if_fail (interface != NULL, FALSE);
4498   _dbus_return_val_if_fail (method != NULL, FALSE);
4499
4500   return _dbus_message_has_type_interface_member (message,
4501                                                   DBUS_MESSAGE_TYPE_METHOD_CALL,
4502                                                   interface, method);
4503 }
4504
4505 /**
4506  * Checks whether the message is a signal with the given
4507  * interface and member fields.  If the message is not
4508  * #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field,
4509  * returns #FALSE.
4510  *
4511  * @param message the message
4512  * @param interface the name to check (must not be #NULL)
4513  * @param signal_name the name to check (must not be #NULL)
4514  * 
4515  * @returns #TRUE if the message is the specified signal
4516  */
4517 dbus_bool_t
4518 dbus_message_is_signal (DBusMessage *message,
4519                         const char  *interface,
4520                         const char  *signal_name)
4521 {
4522   _dbus_return_val_if_fail (message != NULL, FALSE);
4523   _dbus_return_val_if_fail (interface != NULL, FALSE);
4524   _dbus_return_val_if_fail (signal_name != NULL, FALSE);
4525
4526   return _dbus_message_has_type_interface_member (message,
4527                                                   DBUS_MESSAGE_TYPE_SIGNAL,
4528                                                   interface, signal_name);
4529 }
4530
4531 /**
4532  * Checks whether the message is an error reply with the given error
4533  * name.  If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a
4534  * different name, returns #FALSE.
4535  *
4536  * @param message the message
4537  * @param error_name the name to check (must not be #NULL)
4538  * 
4539  * @returns #TRUE if the message is the specified error
4540  */
4541 dbus_bool_t
4542 dbus_message_is_error (DBusMessage *message,
4543                         const char  *error_name)
4544 {
4545   const char *n;
4546   
4547   _dbus_return_val_if_fail (message != NULL, FALSE);
4548   _dbus_return_val_if_fail (error_name != NULL, FALSE);
4549
4550   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
4551     return FALSE;
4552
4553   n = dbus_message_get_error_name (message);
4554
4555   if (n && strcmp (n, error_name) == 0)
4556     return TRUE;
4557   else
4558     return FALSE;
4559 }
4560
4561 /**
4562  * Checks whether the message was sent to the given service.  If the
4563  * message has no service specified or has a different name, returns
4564  * #FALSE.
4565  *
4566  * @param message the message
4567  * @param service the service to check (must not be #NULL)
4568  * 
4569  * @returns #TRUE if the message has the given destination service
4570  */
4571 dbus_bool_t
4572 dbus_message_has_destination (DBusMessage  *message,
4573                               const char   *service)
4574 {
4575   const char *s;
4576
4577   _dbus_return_val_if_fail (message != NULL, FALSE);
4578   _dbus_return_val_if_fail (service != NULL, FALSE);
4579   
4580   s = dbus_message_get_destination (message);
4581
4582   if (s && strcmp (s, service) == 0)
4583     return TRUE;
4584   else
4585     return FALSE;
4586 }
4587
4588 /**
4589  * Checks whether the message has the given service as its sender.  If
4590  * the message has no sender specified or has a different sender,
4591  * returns #FALSE. Note that if a peer application owns multiple
4592  * services, its messages will have only one of those services as the
4593  * sender (usually the base service). So you can't use this
4594  * function to prove the sender didn't own service Foo, you can
4595  * only use it to prove that it did.
4596  *
4597  * @param message the message
4598  * @param service the service to check (must not be #NULL)
4599  * 
4600  * @returns #TRUE if the message has the given origin service
4601  */
4602 dbus_bool_t
4603 dbus_message_has_sender (DBusMessage  *message,
4604                          const char   *service)
4605 {
4606   const char *s;
4607
4608   _dbus_return_val_if_fail (message != NULL, FALSE);
4609   _dbus_return_val_if_fail (service != NULL, FALSE);
4610   
4611   s = dbus_message_get_sender (message);
4612
4613   if (s && strcmp (s, service) == 0)
4614     return TRUE;
4615   else
4616     return FALSE;
4617 }
4618
4619 /**
4620  * Checks whether the message has the given signature;
4621  * see dbus_message_get_signature() for more details on
4622  * what the signature looks like.
4623  *
4624  * @param message the message
4625  * @param signature typecode array
4626  * @returns #TRUE if message has the given signature
4627 */
4628 dbus_bool_t
4629 dbus_message_has_signature (DBusMessage   *message,
4630                             const char    *signature)
4631 {
4632   _dbus_return_val_if_fail (message != NULL, FALSE);
4633   _dbus_return_val_if_fail (signature != NULL, FALSE);
4634
4635   return _dbus_string_equal_c_str (&message->signature, signature);
4636 }
4637
4638 /**
4639  * Sets a #DBusError based on the contents of the given
4640  * message. The error is only set if the message
4641  * is an error message, as in DBUS_MESSAGE_TYPE_ERROR.
4642  * The name of the error is set to the name of the message,
4643  * and the error message is set to the first argument
4644  * if the argument exists and is a string.
4645  *
4646  * The return value indicates whether the error was set (the error is
4647  * set if and only if the message is an error message).
4648  * So you can check for an error reply and convert it to DBusError
4649  * in one go.
4650  *
4651  * @param error the error to set
4652  * @param message the message to set it from
4653  * @returns #TRUE if dbus_message_get_is_error() returns #TRUE for the message
4654  */
4655 dbus_bool_t
4656 dbus_set_error_from_message (DBusError   *error,
4657                              DBusMessage *message)
4658 {
4659   char *str;
4660
4661   _dbus_return_val_if_fail (message != NULL, FALSE);
4662   _dbus_return_val_if_error_is_set (error, FALSE);
4663   
4664   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
4665     return FALSE;
4666
4667   str = NULL;
4668   dbus_message_get_args (message, NULL,
4669                          DBUS_TYPE_STRING, &str,
4670                          DBUS_TYPE_INVALID);
4671
4672   dbus_set_error (error, dbus_message_get_error_name (message),
4673                   str ? "%s" : NULL, str);
4674
4675   dbus_free (str);
4676   
4677   return TRUE;
4678 }
4679
4680 /** @} */
4681
4682 /**
4683  * @addtogroup DBusMessageInternals
4684  *
4685  * @{
4686  */
4687 /**
4688  * @typedef DBusMessageLoader
4689  *
4690  * The DBusMessageLoader object encapsulates the process of converting
4691  * a byte stream into a series of DBusMessage. It buffers the incoming
4692  * bytes as efficiently as possible, and generates a queue of
4693  * messages. DBusMessageLoader is typically used as part of a
4694  * DBusTransport implementation. The DBusTransport then hands off
4695  * the loaded messages to a DBusConnection, making the messages
4696  * visible to the application.
4697  *
4698  * @todo write tests for break-loader that a) randomly delete header
4699  * fields and b) set string fields to zero-length and other funky
4700  * values.
4701  * 
4702  */
4703
4704 /* we definitely use signed ints for sizes, so don't exceed
4705  * _DBUS_INT_MAX; and add 16 for paranoia, since a message
4706  * over 128M is pretty nuts anyhow.
4707  */
4708
4709 /**
4710  * The maximum sane message size.
4711  */
4712 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
4713
4714 /**
4715  * Implementation details of DBusMessageLoader.
4716  * All members are private.
4717  */
4718 struct DBusMessageLoader
4719 {
4720   int refcount;        /**< Reference count. */
4721
4722   DBusString data;     /**< Buffered data */
4723   
4724   DBusList *messages;  /**< Complete messages. */
4725
4726   long max_message_size; /**< Maximum size of a message */
4727   
4728   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
4729
4730   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
4731 };
4732
4733 /**
4734  * The initial buffer size of the message loader.
4735  * 
4736  * @todo this should be based on min header size plus some average
4737  * body size, or something. Or rather, the min header size only, if we
4738  * want to try to read only the header, store that in a DBusMessage,
4739  * then read only the body and store that, etc., depends on
4740  * how we optimize _dbus_message_loader_get_buffer() and what
4741  * the exact message format is.
4742  */
4743 #define INITIAL_LOADER_DATA_LEN 32
4744
4745 /**
4746  * Creates a new message loader. Returns #NULL if memory can't
4747  * be allocated.
4748  *
4749  * @returns new loader, or #NULL.
4750  */
4751 DBusMessageLoader*
4752 _dbus_message_loader_new (void)
4753 {
4754   DBusMessageLoader *loader;
4755
4756   loader = dbus_new0 (DBusMessageLoader, 1);
4757   if (loader == NULL)
4758     return NULL;
4759   
4760   loader->refcount = 1;
4761
4762   /* Try to cap message size at something that won't *totally* hose
4763    * the system if we have a couple of them.
4764    */
4765   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
4766   
4767   if (!_dbus_string_init (&loader->data))
4768     {
4769       dbus_free (loader);
4770       return NULL;
4771     }
4772
4773   /* preallocate the buffer for speed, ignore failure */
4774   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
4775   _dbus_string_set_length (&loader->data, 0);
4776   
4777   return loader;
4778 }
4779
4780 /**
4781  * Increments the reference count of the loader.
4782  *
4783  * @param loader the loader.
4784  */
4785 void
4786 _dbus_message_loader_ref (DBusMessageLoader *loader)
4787 {
4788   loader->refcount += 1;
4789 }
4790
4791 /**
4792  * Decrements the reference count of the loader and finalizes the
4793  * loader when the count reaches zero.
4794  *
4795  * @param loader the loader.
4796  */
4797 void
4798 _dbus_message_loader_unref (DBusMessageLoader *loader)
4799 {
4800   loader->refcount -= 1;
4801   if (loader->refcount == 0)
4802     {
4803       _dbus_list_foreach (&loader->messages,
4804                           (DBusForeachFunction) dbus_message_unref,
4805                           NULL);
4806       _dbus_list_clear (&loader->messages);
4807       _dbus_string_free (&loader->data);
4808       dbus_free (loader);
4809     }
4810 }
4811
4812 /**
4813  * Gets the buffer to use for reading data from the network.  Network
4814  * data is read directly into an allocated buffer, which is then used
4815  * in the DBusMessage, to avoid as many extra memcpy's as possible.
4816  * The buffer must always be returned immediately using
4817  * _dbus_message_loader_return_buffer(), even if no bytes are
4818  * successfully read.
4819  *
4820  * @todo this function can be a lot more clever. For example
4821  * it can probably always return a buffer size to read exactly
4822  * the body of the next message, thus avoiding any memory wastage
4823  * or reallocs.
4824  *
4825  * @todo we need to enforce a max length on strings in header fields.
4826  * 
4827  * @param loader the message loader.
4828  * @param buffer the buffer
4829  */
4830 void
4831 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
4832                                  DBusString        **buffer)
4833 {
4834   _dbus_assert (!loader->buffer_outstanding);
4835
4836   *buffer = &loader->data;
4837   
4838   loader->buffer_outstanding = TRUE;
4839 }
4840
4841 /**
4842  * The smallest header size that can occur. 
4843  * (It won't be valid)
4844  */
4845 #define DBUS_MINIMUM_HEADER_SIZE 16
4846
4847 static dbus_bool_t
4848 decode_string_field (const DBusString   *data,
4849                      int                 field,
4850                      HeaderField        *header_field,
4851                      DBusString         *field_data,
4852                      int                 pos,
4853                      int                 type)
4854 {
4855   int string_data_pos;
4856
4857   _dbus_assert (header_field != NULL);
4858   _dbus_assert (field_data != NULL);
4859   
4860   if (header_field->name_offset >= 0)
4861     {
4862       _dbus_verbose ("%s field provided twice\n",
4863                      _dbus_header_field_to_string (field));
4864       return FALSE;
4865     }
4866
4867   if (type != DBUS_TYPE_STRING)
4868     {
4869       _dbus_verbose ("%s field has wrong type %s\n",
4870                      _dbus_header_field_to_string (field),
4871                      _dbus_type_to_string (type));
4872       return FALSE;
4873     }
4874
4875   /* skip padding after typecode, skip string length;
4876    * we assume that the string arg has already been validated
4877    * for sanity and UTF-8
4878    */
4879   string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
4880   _dbus_assert (string_data_pos < _dbus_string_get_length (data));
4881   
4882   _dbus_string_init_const (field_data,
4883                            _dbus_string_get_const_data (data) + string_data_pos);
4884
4885   header_field->name_offset  = pos;
4886   header_field->value_offset = _DBUS_ALIGN_VALUE (pos, 4);
4887   
4888 #if 0
4889   _dbus_verbose ("Found field %s at offset %d\n",
4890                  _dbus_header_field_to_string (field),
4891                  header_field->value_offset);
4892 #endif
4893
4894   return TRUE;
4895 }
4896
4897 /* FIXME because the service/interface/member/error names are already
4898  * validated to be in the particular ASCII subset, UTF-8 validating
4899  * them could be skipped as a probably-interesting optimization.
4900  * The UTF-8 validation definitely shows up in profiles.
4901  */
4902 static dbus_bool_t
4903 decode_header_data (const DBusString   *data,
4904                     int                 header_len,
4905                     int                 byte_order,
4906                     int                 message_type,
4907                     HeaderField         fields[DBUS_HEADER_FIELD_LAST + 1],
4908                     int                *message_padding)
4909 {
4910   DBusString field_data;
4911   int pos, new_pos;
4912   int i;
4913   int field;
4914   int type;
4915   
4916   if (header_len < 16)
4917     {
4918       _dbus_verbose ("Header length %d is too short\n", header_len);
4919       return FALSE;
4920     }
4921   
4922   i = 0;
4923   while (i <= DBUS_HEADER_FIELD_LAST)
4924     {
4925       fields[i].name_offset  = -1;
4926       fields[i].value_offset = -1;
4927       ++i;
4928     }
4929   
4930   pos = 16;
4931   while (pos < header_len)
4932     {
4933       field = _dbus_string_get_byte (data, pos);
4934       if (field == DBUS_HEADER_FIELD_INVALID)
4935         break; /* Must be padding */
4936       pos++;
4937
4938       if (!_dbus_marshal_validate_type (data, pos, &type, &pos))
4939         {
4940           _dbus_verbose ("Failed to validate type of named header field pos = %d\n",
4941                          pos);
4942           return FALSE;
4943         }
4944       
4945       if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos))
4946         {
4947           _dbus_verbose ("Failed to validate argument to named header field pos = %d\n",
4948                          pos);
4949           return FALSE;
4950         }
4951
4952       if (new_pos > header_len)
4953         {
4954           _dbus_verbose ("Named header field tries to extend beyond header length\n");
4955           return FALSE;
4956         }
4957       
4958       switch (field)
4959         {
4960         case DBUS_HEADER_FIELD_SERVICE:
4961           if (!decode_string_field (data, field, &fields[field],
4962                                     &field_data, pos, type))
4963             return FALSE;
4964
4965           if (!_dbus_string_validate_service (&field_data, 0,
4966                                               _dbus_string_get_length (&field_data)))
4967             {
4968               _dbus_verbose ("service field has invalid content \"%s\"\n",
4969                              _dbus_string_get_const_data (&field_data));
4970               return FALSE;
4971             }
4972           break;
4973
4974         case DBUS_HEADER_FIELD_INTERFACE:
4975           if (!decode_string_field (data, field, &fields[field],
4976                                     &field_data, pos, type))
4977             return FALSE;
4978
4979           if (!_dbus_string_validate_interface (&field_data, 0,
4980                                                 _dbus_string_get_length (&field_data)))
4981             {
4982               _dbus_verbose ("interface field has invalid content \"%s\"\n",
4983                              _dbus_string_get_const_data (&field_data));
4984               return FALSE;
4985             }
4986       
4987           if (_dbus_string_equal_c_str (&field_data,
4988                                         DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL))
4989             {
4990               _dbus_verbose ("Message is on the local interface\n");
4991               return FALSE;
4992             }
4993           break;
4994
4995         case DBUS_HEADER_FIELD_MEMBER:
4996           if (!decode_string_field (data, field, &fields[field],
4997                                     &field_data, pos, type))
4998             return FALSE;
4999           
5000           if (!_dbus_string_validate_member (&field_data, 0,
5001                                              _dbus_string_get_length (&field_data)))
5002             {
5003               _dbus_verbose ("member field has invalid content \"%s\"\n",
5004                              _dbus_string_get_const_data (&field_data));
5005               return FALSE;
5006             }
5007           break;
5008
5009         case DBUS_HEADER_FIELD_ERROR_NAME:
5010           if (!decode_string_field (data, field, &fields[field],
5011                                     &field_data, pos, type))
5012             return FALSE;
5013           
5014           if (!_dbus_string_validate_error_name (&field_data, 0,
5015                                                  _dbus_string_get_length (&field_data)))
5016             {
5017               _dbus_verbose ("error-name field has invalid content \"%s\"\n",
5018                              _dbus_string_get_const_data (&field_data));
5019               return FALSE;
5020             }
5021           break;
5022           
5023         case DBUS_HEADER_FIELD_SENDER_SERVICE:
5024           if (!decode_string_field (data, field, &fields[field],
5025                                     &field_data, pos, type))
5026             return FALSE;
5027           
5028           if (!_dbus_string_validate_service (&field_data, 0,
5029                                               _dbus_string_get_length (&field_data)))
5030             {
5031               _dbus_verbose ("sender-service field has invalid content \"%s\"\n",
5032                              _dbus_string_get_const_data (&field_data));
5033               return FALSE;
5034             }
5035           break;
5036
5037         case DBUS_HEADER_FIELD_PATH:
5038
5039           /* Path was already validated as part of standard
5040            * type validation, since there's an OBJECT_PATH
5041            * type.
5042            */
5043           
5044           if (fields[field].name_offset >= 0)
5045             {
5046               _dbus_verbose ("path field provided twice\n");
5047               return FALSE;
5048             }
5049           if (type != DBUS_TYPE_OBJECT_PATH)
5050             {
5051               _dbus_verbose ("path field has wrong type\n");
5052               return FALSE;
5053             }
5054
5055           fields[field].name_offset  = pos;
5056           fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
5057
5058           /* No forging signals from the local path */
5059           {
5060             const char *s;
5061             s = _dbus_string_get_const_data_len (data,
5062                                                  fields[field].value_offset,
5063                                                  _dbus_string_get_length (data) -
5064                                                  fields[field].value_offset);
5065             if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0)
5066               {
5067                 _dbus_verbose ("Message is on the local path\n");
5068                 return FALSE;
5069               }
5070           }
5071           
5072           _dbus_verbose ("Found path at offset %d\n",
5073                          fields[field].value_offset);
5074           break;
5075           
5076         case DBUS_HEADER_FIELD_REPLY_SERIAL:
5077           if (fields[field].name_offset >= 0)
5078             {
5079               _dbus_verbose ("reply field provided twice\n");
5080               return FALSE;
5081             }
5082
5083           if (type != DBUS_TYPE_UINT32)
5084             {
5085               _dbus_verbose ("reply field has wrong type\n");
5086               return FALSE;
5087             }
5088           
5089           fields[field].name_offset  = pos;
5090           fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
5091
5092           _dbus_verbose ("Found reply serial %u at offset %d\n",
5093                          _dbus_demarshal_uint32 (data,
5094                                                  byte_order,
5095                                                  fields[field].value_offset,
5096                                                  NULL),
5097                          fields[field].value_offset);
5098           break;
5099
5100         default:
5101           _dbus_verbose ("Ignoring an unknown header field: %d at offset %d\n",
5102                          field, pos);
5103         }
5104       
5105       pos = new_pos;
5106     }
5107
5108   if (pos < header_len)
5109     {
5110       /* Alignment padding, verify that it's nul */
5111       if ((header_len - pos) >= 8)
5112         {
5113           _dbus_verbose ("too much header alignment padding\n");
5114           return FALSE;
5115         }
5116
5117       if (!_dbus_string_validate_nul (data,
5118                                       pos, (header_len - pos)))
5119         {
5120           _dbus_verbose ("header alignment padding is not nul\n");
5121           return FALSE;
5122         }
5123     }
5124
5125   /* Depending on message type, enforce presence of certain fields. */
5126   switch (message_type)
5127     {
5128     case DBUS_MESSAGE_TYPE_SIGNAL:
5129     case DBUS_MESSAGE_TYPE_METHOD_CALL:
5130       if (fields[DBUS_HEADER_FIELD_PATH].value_offset < 0)
5131         {
5132           _dbus_verbose ("No path field provided\n");
5133           return FALSE;
5134         }
5135       /* FIXME make this optional, only for method calls */
5136       if (fields[DBUS_HEADER_FIELD_INTERFACE].value_offset < 0)
5137         {
5138           _dbus_verbose ("No interface field provided\n");
5139           return FALSE;
5140         }
5141       if (fields[DBUS_HEADER_FIELD_MEMBER].value_offset < 0)
5142         {
5143           _dbus_verbose ("No member field provided\n");
5144           return FALSE;
5145         }
5146       break;
5147     case DBUS_MESSAGE_TYPE_ERROR:
5148       if (fields[DBUS_HEADER_FIELD_ERROR_NAME].value_offset < 0)
5149         {
5150           _dbus_verbose ("No error-name field provided\n");
5151           return FALSE;
5152         }
5153       if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0)
5154         {
5155           _dbus_verbose ("No reply serial field provided in error\n");
5156           return FALSE;
5157         }
5158       break;
5159     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
5160       if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0)
5161         {
5162           _dbus_verbose ("No reply serial field provided in method return\n");
5163           return FALSE;
5164         }
5165       break;
5166     default:
5167       /* An unknown type, spec requires us to ignore it */
5168       break;
5169     }
5170   
5171   if (message_padding)
5172     *message_padding = header_len - pos;  
5173   
5174   return TRUE;
5175 }
5176
5177 /**
5178  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
5179  * indicating to the loader how many bytes of the buffer were filled
5180  * in. This function must always be called, even if no bytes were
5181  * successfully read.
5182  *
5183  * @param loader the loader.
5184  * @param buffer the buffer.
5185  * @param bytes_read number of bytes that were read into the buffer.
5186  */
5187 void
5188 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
5189                                     DBusString         *buffer,
5190                                     int                 bytes_read)
5191 {
5192   _dbus_assert (loader->buffer_outstanding);
5193   _dbus_assert (buffer == &loader->data);
5194
5195   loader->buffer_outstanding = FALSE;
5196 }
5197
5198 static dbus_bool_t
5199 load_one_message (DBusMessageLoader *loader,
5200                   int                byte_order,
5201                   int                message_type,
5202                   int                header_len,
5203                   int                body_len)
5204 {
5205   DBusMessage *message;
5206   HeaderField fields[DBUS_HEADER_FIELD_LAST + 1];
5207   int i;
5208   int next_arg;
5209   dbus_bool_t oom;
5210   int header_padding;
5211   
5212   message = NULL;
5213   oom = FALSE;
5214   
5215 #if 0
5216   _dbus_verbose_bytes_of_string (&loader->data, 0, header_len /* + body_len */);
5217 #endif    
5218
5219   if (!decode_header_data (&loader->data,
5220                            header_len, byte_order,
5221                            message_type,
5222                            fields, &header_padding))
5223     {
5224       _dbus_verbose ("Header was invalid\n");
5225       loader->corrupted = TRUE;
5226       goto failed;
5227     }
5228           
5229   next_arg = header_len;
5230   while (next_arg < (header_len + body_len))
5231     {
5232       int type;
5233       int prev = next_arg;
5234
5235       if (!_dbus_marshal_validate_type (&loader->data, next_arg,
5236                                         &type, &next_arg))
5237         {
5238           _dbus_verbose ("invalid typecode at offset %d\n", prev);
5239           loader->corrupted = TRUE;
5240           goto failed;
5241         }
5242       
5243       if (!_dbus_marshal_validate_arg (&loader->data,
5244                                        byte_order,
5245                                        0,
5246                                        type, -1,
5247                                        next_arg,
5248                                        &next_arg))
5249         {
5250           _dbus_verbose ("invalid type data at %d, next_arg\n", next_arg);
5251           loader->corrupted = TRUE;
5252           goto failed;
5253         }
5254
5255       _dbus_assert (next_arg > prev);
5256     }
5257           
5258   if (next_arg > (header_len + body_len))
5259     {
5260       _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
5261                      next_arg, header_len, body_len,
5262                      header_len + body_len);
5263       loader->corrupted = TRUE;
5264       goto failed;
5265     }
5266
5267   message = dbus_message_new_empty_header ();
5268   if (message == NULL)
5269     {
5270       _dbus_verbose ("Failed to allocate empty message\n");
5271       oom = TRUE;
5272       goto failed;
5273     }
5274
5275   message->byte_order = byte_order;
5276   message->header_padding = header_padding;
5277           
5278   /* Copy in the offsets we found */
5279   i = 0;
5280   while (i <= DBUS_HEADER_FIELD_LAST)
5281     {
5282       message->header_fields[i] = fields[i];
5283       ++i;
5284     }
5285           
5286   if (!_dbus_list_append (&loader->messages, message))
5287     {
5288       _dbus_verbose ("Failed to append new message to loader queue\n");
5289       oom = TRUE;
5290       goto failed;
5291     }
5292
5293   _dbus_assert (_dbus_string_get_length (&message->header) == 0);
5294   _dbus_assert (_dbus_string_get_length (&message->body) == 0);
5295
5296   _dbus_assert (_dbus_string_get_length (&loader->data) >=
5297                 (header_len + body_len));
5298           
5299   if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
5300     {
5301       _dbus_verbose ("Failed to move header into new message\n");
5302       oom = TRUE;
5303       goto failed;
5304     }
5305           
5306   if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
5307     {
5308       _dbus_verbose ("Failed to move body into new message\n");
5309       
5310       oom = TRUE;
5311       goto failed;
5312     }
5313
5314   _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
5315   _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
5316
5317   /* Fill in caches (we checked the types of these fields
5318    * earlier)
5319    */
5320   message->reply_serial = get_uint_field (message,
5321                                           DBUS_HEADER_FIELD_REPLY_SERIAL);
5322   
5323   message->client_serial = _dbus_demarshal_uint32 (&message->header,
5324                                                    message->byte_order,
5325                                                    CLIENT_SERIAL_OFFSET,
5326                                                    NULL);
5327   if (message->client_serial == 0 ||
5328       (message->header_fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset >= 0 && message->reply_serial == 0))
5329     {
5330       _dbus_verbose ("client_serial = %d reply_serial = %d, one of these no good\n",
5331                      message->client_serial,
5332                      message->reply_serial);
5333       
5334       loader->corrupted = TRUE;
5335       goto failed;
5336     }
5337           
5338   /* Fill in signature (FIXME should do this during validation,
5339    * but I didn't want to spend time on it since we want to change
5340    * the wire format to contain the signature anyway)
5341    */
5342   {
5343     DBusMessageIter iter;
5344
5345     dbus_message_iter_init (message, &iter);
5346
5347     do
5348       {
5349         int t;
5350
5351         t = dbus_message_iter_get_arg_type (&iter);
5352         if (t == DBUS_TYPE_INVALID)
5353           break;
5354
5355         if (!_dbus_string_append_byte (&message->signature,
5356                                        t))
5357           {
5358             _dbus_verbose ("failed to append type byte to signature\n");
5359             oom = TRUE;
5360             goto failed;
5361           }
5362
5363         if (t == DBUS_TYPE_ARRAY)
5364           {
5365             DBusMessageIter child_iter;
5366             int array_type = t;
5367
5368             child_iter = iter;
5369                     
5370             while (array_type == DBUS_TYPE_ARRAY)
5371               {
5372                 DBusMessageIter parent_iter = child_iter;
5373                 dbus_message_iter_init_array_iterator (&parent_iter,
5374                                                        &child_iter,
5375                                                        &array_type);
5376                                             
5377                 if (!_dbus_string_append_byte (&message->signature,
5378                                                array_type))
5379                   {
5380                     _dbus_verbose ("failed to append array type byte to signature\n");
5381
5382                     oom = TRUE;
5383                     goto failed;
5384                   }
5385               }
5386           }
5387       }
5388     while (dbus_message_iter_next (&iter));
5389   }
5390           
5391   _dbus_verbose ("Loaded message %p\n", message);
5392
5393   _dbus_assert (!oom);
5394   _dbus_assert (!loader->corrupted);
5395
5396   return TRUE;
5397
5398  failed:
5399   
5400   /* Clean up */
5401   
5402   if (message != NULL)
5403     {
5404       /* Put the data back so we can try again later if it was an OOM issue */
5405       if (_dbus_string_get_length (&message->body) > 0)
5406         {
5407           dbus_bool_t result;
5408           
5409           result = _dbus_string_copy_len (&message->body, 0, body_len,
5410                                           &loader->data, 0);
5411           
5412           _dbus_assert (result); /* because DBusString never reallocs smaller */
5413         }
5414       
5415       if (_dbus_string_get_length (&message->header) > 0)
5416         {
5417           dbus_bool_t result;
5418           
5419           result = _dbus_string_copy_len (&message->header, 0, header_len,
5420                                           &loader->data, 0);
5421           
5422           _dbus_assert (result); /* because DBusString never reallocs smaller */
5423         }
5424
5425       /* does nothing if the message isn't in the list */
5426       _dbus_list_remove_last (&loader->messages, message);
5427
5428       dbus_message_unref (message);
5429     }
5430
5431   
5432   return !oom;
5433 }
5434
5435 /**
5436  * Converts buffered data into messages.
5437  *
5438  * @todo we need to check that the proper named header fields exist
5439  * for each message type.
5440  * 
5441  * @todo If a message has unknown type, we should probably eat it
5442  * right here rather than passing it out to applications.  However
5443  * it's not an error to see messages of unknown type.
5444  * 
5445  * @param loader the loader.
5446  * @returns #TRUE if we had enough memory to finish.
5447  */
5448 dbus_bool_t
5449 _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
5450 {
5451   while (!loader->corrupted && _dbus_string_get_length (&loader->data) >= 16)
5452     {
5453       const char *header_data;
5454       int byte_order, message_type, header_len, body_len;
5455       dbus_uint32_t header_len_unsigned, body_len_unsigned;
5456       
5457       header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16);
5458
5459       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
5460
5461       if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION)
5462         {
5463           _dbus_verbose ("Message has protocol version %d ours is %d\n",
5464                          (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION);
5465           loader->corrupted = TRUE;
5466           return TRUE;
5467         }
5468       
5469       byte_order = header_data[BYTE_ORDER_OFFSET];
5470
5471       if (byte_order != DBUS_LITTLE_ENDIAN &&
5472           byte_order != DBUS_BIG_ENDIAN)
5473         {
5474           _dbus_verbose ("Message with bad byte order '%c' received\n",
5475                          byte_order);
5476           loader->corrupted = TRUE;
5477           return TRUE;
5478         }
5479
5480       /* Unknown types are ignored, but INVALID is
5481        * disallowed
5482        */
5483       message_type = header_data[TYPE_OFFSET];
5484       if (message_type == DBUS_MESSAGE_TYPE_INVALID)
5485         {
5486           _dbus_verbose ("Message with bad type '%d' received\n",
5487                          message_type);
5488           loader->corrupted = TRUE;
5489           return TRUE;
5490         }      
5491       
5492       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
5493       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
5494
5495       if (header_len_unsigned < 16)
5496         {
5497           _dbus_verbose ("Message had broken too-small header length %u\n",
5498                          header_len_unsigned);
5499           loader->corrupted = TRUE;
5500           return TRUE;
5501         }
5502
5503       if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE ||
5504           body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE)
5505         {
5506           _dbus_verbose ("Header or body length too large (%u %u)\n",
5507                          header_len_unsigned,
5508                          body_len_unsigned);
5509           loader->corrupted = TRUE;
5510           return TRUE;
5511         }
5512
5513       /* Now that we know the values are in signed range, get
5514        * rid of stupid unsigned, just causes bugs
5515        */
5516       header_len = header_len_unsigned;
5517       body_len = body_len_unsigned;
5518
5519       if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned)
5520         {
5521           
5522           _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
5523                          header_len);
5524           loader->corrupted = TRUE;
5525           return TRUE;
5526         }
5527       
5528       if (header_len + body_len > loader->max_message_size)
5529         {
5530           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %ld\n",
5531                          header_len, body_len, loader->max_message_size);
5532           loader->corrupted = TRUE;
5533           return TRUE;
5534         }
5535
5536       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
5537         {
5538           if (!load_one_message (loader, byte_order, message_type,
5539                                  header_len, body_len))
5540             return FALSE;
5541         }
5542       else
5543         return TRUE;
5544     }
5545
5546   return TRUE;
5547 }
5548
5549 /**
5550  * Peeks at first loaded message, returns #NULL if no messages have
5551  * been queued.
5552  *
5553  * @param loader the loader.
5554  * @returns the next message, or #NULL if none.
5555  */
5556 DBusMessage*
5557 _dbus_message_loader_peek_message (DBusMessageLoader *loader)
5558 {
5559   if (loader->messages)
5560     return loader->messages->data;
5561   else
5562     return NULL;
5563 }
5564
5565 /**
5566  * Pops a loaded message (passing ownership of the message
5567  * to the caller). Returns #NULL if no messages have been
5568  * queued.
5569  *
5570  * @param loader the loader.
5571  * @returns the next message, or #NULL if none.
5572  */
5573 DBusMessage*
5574 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
5575 {
5576   return _dbus_list_pop_first (&loader->messages);
5577 }
5578
5579 /**
5580  * Pops a loaded message inside a list link (passing ownership of the
5581  * message and link to the caller). Returns #NULL if no messages have
5582  * been loaded.
5583  *
5584  * @param loader the loader.
5585  * @returns the next message link, or #NULL if none.
5586  */
5587 DBusList*
5588 _dbus_message_loader_pop_message_link (DBusMessageLoader *loader)
5589 {
5590   return _dbus_list_pop_first_link (&loader->messages);
5591 }
5592
5593 /**
5594  * Returns a popped message link, used to undo a pop.
5595  *
5596  * @param loader the loader
5597  * @param link the link with a message in it
5598  */
5599 void
5600 _dbus_message_loader_putback_message_link (DBusMessageLoader  *loader,
5601                                            DBusList           *link)
5602 {
5603   _dbus_list_prepend_link (&loader->messages, link);
5604 }
5605
5606 /**
5607  * Checks whether the loader is confused due to bad data.
5608  * If messages are received that are invalid, the
5609  * loader gets confused and gives up permanently.
5610  * This state is called "corrupted."
5611  *
5612  * @param loader the loader
5613  * @returns #TRUE if the loader is hosed.
5614  */
5615 dbus_bool_t
5616 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
5617 {
5618   return loader->corrupted;
5619 }
5620
5621 /**
5622  * Sets the maximum size message we allow.
5623  *
5624  * @param loader the loader
5625  * @param size the max message size in bytes
5626  */
5627 void
5628 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
5629                                            long                size)
5630 {
5631   if (size > MAX_SANE_MESSAGE_SIZE)
5632     {
5633       _dbus_verbose ("clamping requested max message size %ld to %d\n",
5634                      size, MAX_SANE_MESSAGE_SIZE);
5635       size = MAX_SANE_MESSAGE_SIZE;
5636     }
5637   loader->max_message_size = size;
5638 }
5639
5640 /**
5641  * Gets the maximum allowed message size in bytes.
5642  *
5643  * @param loader the loader
5644  * @returns max size in bytes
5645  */
5646 long
5647 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
5648 {
5649   return loader->max_message_size;
5650 }
5651
5652 static DBusDataSlotAllocator slot_allocator;
5653 _DBUS_DEFINE_GLOBAL_LOCK (message_slots);
5654
5655 /**
5656  * Allocates an integer ID to be used for storing application-specific
5657  * data on any DBusMessage. The allocated ID may then be used
5658  * with dbus_message_set_data() and dbus_message_get_data().
5659  * The passed-in slot must be initialized to -1, and is filled in
5660  * with the slot ID. If the passed-in slot is not -1, it's assumed
5661  * to be already allocated, and its refcount is incremented.
5662  * 
5663  * The allocated slot is global, i.e. all DBusMessage objects will
5664  * have a slot with the given integer ID reserved.
5665  *
5666  * @param slot_p address of a global variable storing the slot
5667  * @returns #FALSE on failure (no memory)
5668  */
5669 dbus_bool_t
5670 dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
5671 {
5672   return _dbus_data_slot_allocator_alloc (&slot_allocator,
5673                                           _DBUS_LOCK_NAME (message_slots),
5674                                           slot_p);
5675 }
5676
5677 /**
5678  * Deallocates a global ID for message data slots.
5679  * dbus_message_get_data() and dbus_message_set_data() may no
5680  * longer be used with this slot.  Existing data stored on existing
5681  * DBusMessage objects will be freed when the message is
5682  * finalized, but may not be retrieved (and may only be replaced if
5683  * someone else reallocates the slot).  When the refcount on the
5684  * passed-in slot reaches 0, it is set to -1.
5685  *
5686  * @param slot_p address storing the slot to deallocate
5687  */
5688 void
5689 dbus_message_free_data_slot (dbus_int32_t *slot_p)
5690 {
5691   _dbus_return_if_fail (*slot_p >= 0);
5692   
5693   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
5694 }
5695
5696 /**
5697  * Stores a pointer on a DBusMessage, along
5698  * with an optional function to be used for freeing
5699  * the data when the data is set again, or when
5700  * the message is finalized. The slot number
5701  * must have been allocated with dbus_message_allocate_data_slot().
5702  *
5703  * @param message the message
5704  * @param slot the slot number
5705  * @param data the data to store
5706  * @param free_data_func finalizer function for the data
5707  * @returns #TRUE if there was enough memory to store the data
5708  */
5709 dbus_bool_t
5710 dbus_message_set_data (DBusMessage     *message,
5711                        dbus_int32_t     slot,
5712                        void            *data,
5713                        DBusFreeFunction free_data_func)
5714 {
5715   DBusFreeFunction old_free_func;
5716   void *old_data;
5717   dbus_bool_t retval;
5718
5719   _dbus_return_val_if_fail (message != NULL, FALSE);
5720   _dbus_return_val_if_fail (slot >= 0, FALSE);
5721
5722   retval = _dbus_data_slot_list_set (&slot_allocator,
5723                                      &message->slot_list,
5724                                      slot, data, free_data_func,
5725                                      &old_free_func, &old_data);
5726
5727   if (retval)
5728     {
5729       /* Do the actual free outside the message lock */
5730       if (old_free_func)
5731         (* old_free_func) (old_data);
5732     }
5733
5734   return retval;
5735 }
5736
5737 /**
5738  * Retrieves data previously set with dbus_message_set_data().
5739  * The slot must still be allocated (must not have been freed).
5740  *
5741  * @param message the message
5742  * @param slot the slot to get data from
5743  * @returns the data, or #NULL if not found
5744  */
5745 void*
5746 dbus_message_get_data (DBusMessage   *message,
5747                        dbus_int32_t   slot)
5748 {
5749   void *res;
5750
5751   _dbus_return_val_if_fail (message != NULL, NULL);
5752   
5753   res = _dbus_data_slot_list_get (&slot_allocator,
5754                                   &message->slot_list,
5755                                   slot);
5756
5757   return res;
5758 }
5759
5760 /**
5761  * Utility function to convert a machine-readable (not translated)
5762  * string into a D-BUS message type.
5763  *
5764  * @code
5765  *   "method_call"    -> DBUS_MESSAGE_TYPE_METHOD_CALL
5766  *   "method_return"  -> DBUS_MESSAGE_TYPE_METHOD_RETURN
5767  *   "signal"         -> DBUS_MESSAGE_TYPE_SIGNAL
5768  *   "error"          -> DBUS_MESSAGE_TYPE_ERROR
5769  *   anything else    -> DBUS_MESSAGE_TYPE_INVALID
5770  * @endcode
5771  * 
5772  */
5773 int
5774 dbus_message_type_from_string (const char *type_str)
5775 {
5776   if (strcmp (type_str, "method_call") == 0)
5777     return DBUS_MESSAGE_TYPE_METHOD_CALL;
5778   if (strcmp (type_str, "method_return") == 0)
5779     return DBUS_MESSAGE_TYPE_METHOD_RETURN;
5780   else if (strcmp (type_str, "signal") == 0)
5781     return DBUS_MESSAGE_TYPE_SIGNAL;
5782   else if (strcmp (type_str, "error") == 0)
5783     return DBUS_MESSAGE_TYPE_ERROR;
5784   else
5785     return DBUS_MESSAGE_TYPE_INVALID;
5786 }
5787
5788 /** @} */
5789 #ifdef DBUS_BUILD_TESTS
5790 #include "dbus-test.h"
5791 #include <stdio.h>
5792 #include <stdlib.h>
5793
5794 static void
5795 message_iter_test (DBusMessage *message)
5796 {
5797   DBusMessageIter iter, dict, array, array2;
5798   char *str;
5799   unsigned char *data;
5800   dbus_int32_t *our_int_array;
5801   int len;
5802   
5803   dbus_message_iter_init (message, &iter);
5804
5805   /* String tests */
5806   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
5807     _dbus_assert_not_reached ("Argument type isn't string");
5808
5809   str = dbus_message_iter_get_string (&iter);
5810   if (strcmp (str, "Test string") != 0)
5811     _dbus_assert_not_reached ("Strings differ");
5812   dbus_free (str);
5813
5814   if (!dbus_message_iter_next (&iter))
5815     _dbus_assert_not_reached ("Reached end of arguments");
5816
5817   /* Signed integer tests */
5818   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32)
5819     _dbus_assert_not_reached ("Argument type isn't int32");
5820
5821   if (dbus_message_iter_get_int32 (&iter) != -0x12345678)
5822     _dbus_assert_not_reached ("Signed integers differ");
5823
5824   if (!dbus_message_iter_next (&iter))
5825     _dbus_assert_not_reached ("Reached end of fields");
5826   
5827   /* Unsigned integer tests */
5828   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
5829     _dbus_assert_not_reached ("Argument type isn't int32");
5830
5831   if (dbus_message_iter_get_uint32 (&iter) != 0xedd1e)
5832     _dbus_assert_not_reached ("Unsigned integers differ");
5833
5834   if (!dbus_message_iter_next (&iter))
5835     _dbus_assert_not_reached ("Reached end of arguments");
5836
5837   /* Double tests */
5838   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DOUBLE)
5839     _dbus_assert_not_reached ("Argument type isn't double");
5840
5841   if (dbus_message_iter_get_double (&iter) != 3.14159)
5842     _dbus_assert_not_reached ("Doubles differ");
5843
5844   if (!dbus_message_iter_next (&iter))
5845     _dbus_assert_not_reached ("Reached end of arguments");
5846
5847   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
5848     _dbus_assert_not_reached ("Argument type not an array");
5849
5850   if (dbus_message_iter_get_array_type (&iter) != DBUS_TYPE_DOUBLE)
5851     _dbus_assert_not_reached ("Array type not double");
5852
5853   
5854   dbus_message_iter_init_array_iterator (&iter, &array, NULL);
5855
5856   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
5857     _dbus_assert_not_reached ("Argument type isn't double");
5858
5859   if (dbus_message_iter_get_double (&array) != 1.5)
5860     _dbus_assert_not_reached ("Unsigned integers differ");
5861
5862   if (!dbus_message_iter_next (&array))
5863     _dbus_assert_not_reached ("Reached end of arguments");
5864
5865   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
5866     _dbus_assert_not_reached ("Argument type isn't double");
5867
5868   if (dbus_message_iter_get_double (&array) != 2.5)
5869     _dbus_assert_not_reached ("Unsigned integers differ");
5870
5871   if (dbus_message_iter_next (&array))
5872     _dbus_assert_not_reached ("Didn't reach end of arguments");
5873   
5874   if (!dbus_message_iter_next (&iter))
5875     _dbus_assert_not_reached ("Reached end of arguments");
5876   
5877
5878   /* dict */
5879
5880   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
5881     _dbus_assert_not_reached ("not dict type");
5882      
5883   dbus_message_iter_init_dict_iterator (&iter, &dict);
5884
5885   str = dbus_message_iter_get_dict_key (&dict);
5886   if (str == NULL || strcmp (str, "test") != 0)
5887     _dbus_assert_not_reached ("wrong dict key");
5888   dbus_free (str);
5889
5890   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
5891     _dbus_assert_not_reached ("wrong dict entry type");
5892
5893   if (dbus_message_iter_get_uint32 (&dict) != 0xDEADBEEF)
5894     _dbus_assert_not_reached ("wrong dict entry value");
5895
5896   if (!dbus_message_iter_next (&dict))
5897     _dbus_assert_not_reached ("reached end of dict");
5898   
5899   /* array of array of int32 (in dict) */
5900
5901   str = dbus_message_iter_get_dict_key (&dict);
5902   if (str == NULL || strcmp (str, "array") != 0)
5903     _dbus_assert_not_reached ("wrong dict key");
5904   dbus_free (str);
5905   
5906   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_ARRAY)
5907     _dbus_assert_not_reached ("Argument type not an array");
5908
5909   if (dbus_message_iter_get_array_type (&dict) != DBUS_TYPE_ARRAY)
5910     _dbus_assert_not_reached ("Array type not array");
5911
5912   dbus_message_iter_init_array_iterator (&dict, &array, NULL);
5913
5914   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_ARRAY)
5915     _dbus_assert_not_reached ("Argument type isn't array");
5916   
5917   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
5918     _dbus_assert_not_reached ("Array type not int32");
5919   
5920   dbus_message_iter_init_array_iterator (&array, &array2, NULL);
5921
5922   if (dbus_message_iter_get_arg_type (&array2) != DBUS_TYPE_INT32)
5923     _dbus_assert_not_reached ("Argument type isn't int32");
5924
5925   if (dbus_message_iter_get_int32 (&array2) != 0x12345678)
5926     _dbus_assert_not_reached ("Signed integers differ");
5927
5928   if (!dbus_message_iter_next (&array2))
5929     _dbus_assert_not_reached ("Reached end of arguments");
5930
5931   if (dbus_message_iter_get_int32 (&array2) != 0x23456781)
5932     _dbus_assert_not_reached ("Signed integers differ");
5933
5934   if (dbus_message_iter_next (&array2))
5935     _dbus_assert_not_reached ("Didn't reached end of arguments");
5936
5937   if (!dbus_message_iter_next (&array))
5938     _dbus_assert_not_reached ("Reached end of arguments");
5939
5940   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
5941     _dbus_assert_not_reached ("Array type not int32");
5942
5943   if (!dbus_message_iter_get_int32_array (&array,
5944                                           &our_int_array,
5945                                           &len))
5946     _dbus_assert_not_reached ("couldn't get int32 array");
5947
5948   _dbus_assert (len == 3);
5949   _dbus_assert (our_int_array[0] == 0x34567812 &&
5950                 our_int_array[1] == 0x45678123 &&
5951                 our_int_array[2] == 0x56781234);
5952   dbus_free (our_int_array);
5953   
5954   if (dbus_message_iter_next (&array))
5955     _dbus_assert_not_reached ("Didn't reach end of array");
5956
5957   if (dbus_message_iter_next (&dict))
5958     _dbus_assert_not_reached ("Didn't reach end of dict");
5959   
5960   if (!dbus_message_iter_next (&iter))
5961     _dbus_assert_not_reached ("Reached end of arguments");
5962   
5963   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_BYTE)
5964     {
5965       _dbus_warn ("type was: %d\n", dbus_message_iter_get_arg_type (&iter));
5966       _dbus_assert_not_reached ("wrong type after dict (should be byte)");
5967     }
5968   
5969   if (dbus_message_iter_get_byte (&iter) != 0xF0)
5970     _dbus_assert_not_reached ("wrong value after dict");
5971
5972
5973   if (!dbus_message_iter_next (&iter))
5974     _dbus_assert_not_reached ("Reached end of arguments");
5975   
5976   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NIL)
5977     _dbus_assert_not_reached ("not a nil type");
5978   
5979   if (!dbus_message_iter_next (&iter))
5980     _dbus_assert_not_reached ("Reached end of arguments");
5981   
5982   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_CUSTOM)
5983     _dbus_assert_not_reached ("wrong type after dict");
5984
5985   if (!dbus_message_iter_get_custom (&iter, &str, &data, &len))
5986     _dbus_assert_not_reached ("failed to get custom type");
5987
5988   _dbus_assert (strcmp (str, "MyTypeName")==0);
5989   _dbus_assert (len == 5);
5990   _dbus_assert (strcmp (data, "data")==0);
5991   dbus_free (str);
5992   dbus_free (data);
5993   
5994   if (dbus_message_iter_next (&iter))
5995     _dbus_assert_not_reached ("Didn't reach end of arguments");
5996 }
5997
5998
5999 static dbus_bool_t
6000 check_message_handling_type (DBusMessageIter *iter,
6001                              int type)
6002 {
6003   DBusMessageIter child_iter;
6004   
6005   switch (type)
6006     {
6007     case DBUS_TYPE_NIL:
6008       break;
6009     case DBUS_TYPE_BYTE:
6010       dbus_message_iter_get_byte (iter);
6011       break;
6012     case DBUS_TYPE_BOOLEAN:
6013       dbus_message_iter_get_boolean (iter);
6014       break;
6015     case DBUS_TYPE_INT32:
6016       dbus_message_iter_get_int32 (iter);
6017       break;
6018     case DBUS_TYPE_UINT32:
6019       dbus_message_iter_get_uint32 (iter);
6020       break;
6021     case DBUS_TYPE_INT64:
6022 #ifdef DBUS_HAVE_INT64
6023       dbus_message_iter_get_int64 (iter);
6024 #endif
6025       break;
6026     case DBUS_TYPE_UINT64:
6027 #ifdef DBUS_HAVE_INT64
6028       dbus_message_iter_get_uint64 (iter);
6029 #endif
6030       break;
6031     case DBUS_TYPE_DOUBLE:
6032       dbus_message_iter_get_double (iter);
6033       break;
6034     case DBUS_TYPE_STRING:
6035       {
6036         char *str;
6037         str = dbus_message_iter_get_string (iter);
6038         if (str == NULL)
6039           {
6040             _dbus_warn ("NULL string in message\n");
6041             return FALSE;
6042           }
6043         dbus_free (str);
6044       }
6045       break;
6046     case DBUS_TYPE_CUSTOM:
6047       {
6048         char *name;
6049         unsigned char *data;
6050         int len;
6051         
6052         if (!dbus_message_iter_get_custom (iter, &name, &data, &len))
6053           {
6054             _dbus_warn ("error reading name from custom type\n");
6055             return FALSE;
6056           }
6057         dbus_free (data);
6058         dbus_free (name);
6059       }
6060       break;
6061     case DBUS_TYPE_ARRAY:
6062       {
6063         int array_type;
6064
6065         dbus_message_iter_init_array_iterator (iter, &child_iter, &array_type);
6066
6067         while (dbus_message_iter_has_next (&child_iter))
6068           {
6069             if (!check_message_handling_type (&child_iter, array_type))
6070               {
6071                 _dbus_warn ("error in array element\n");
6072                 return FALSE;
6073               }
6074             
6075             if (!dbus_message_iter_next (&child_iter))
6076               break;
6077           }
6078       }
6079       break;
6080     case DBUS_TYPE_DICT:
6081       {
6082         int entry_type;
6083         char *key;
6084         
6085         dbus_message_iter_init_dict_iterator (iter, &child_iter);
6086
6087         while ((entry_type = dbus_message_iter_get_arg_type (&child_iter)) != DBUS_TYPE_INVALID)
6088           {
6089             key = dbus_message_iter_get_dict_key (&child_iter);
6090             if (key == NULL)
6091               {
6092                 _dbus_warn ("error reading dict key\n");
6093                 return FALSE;
6094               }
6095             dbus_free (key);
6096             
6097             if (!check_message_handling_type (&child_iter, entry_type))
6098               {
6099                 _dbus_warn ("error in dict value\n");
6100                 return FALSE;
6101               }
6102             
6103             if (!dbus_message_iter_next (&child_iter))
6104               break;
6105           }
6106       }
6107       break;
6108       
6109     default:
6110       _dbus_warn ("unknown type %d\n", type);
6111       return FALSE;
6112       break;
6113     }
6114   return TRUE;
6115 }
6116   
6117   
6118 static dbus_bool_t
6119 check_message_handling (DBusMessage *message)
6120 {
6121   DBusMessageIter iter;
6122   int type;
6123   dbus_bool_t retval;
6124   dbus_uint32_t client_serial;
6125   
6126   retval = FALSE;
6127   
6128   client_serial = dbus_message_get_serial (message);
6129
6130   /* can't use set_serial due to the assertions at the start of it */
6131   _dbus_marshal_set_uint32 (&message->header,
6132                             message->byte_order,
6133                             CLIENT_SERIAL_OFFSET,
6134                             client_serial);
6135   
6136   if (client_serial != dbus_message_get_serial (message))
6137     {
6138       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
6139       goto failed;
6140     }
6141   
6142   /* If we implement message_set_arg (message, n, value)
6143    * then we would want to test it here
6144    */
6145
6146   dbus_message_iter_init (message, &iter);
6147   while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
6148     {
6149       if (!check_message_handling_type (&iter, type))
6150         goto failed;
6151
6152       if (!dbus_message_iter_next (&iter))
6153         break;
6154     }
6155   
6156   retval = TRUE;
6157   
6158  failed:
6159   return retval;
6160 }
6161
6162 static dbus_bool_t
6163 check_have_valid_message (DBusMessageLoader *loader)
6164 {
6165   DBusMessage *message;
6166   dbus_bool_t retval;
6167
6168   message = NULL;
6169   retval = FALSE;
6170
6171   if (!_dbus_message_loader_queue_messages (loader))
6172     _dbus_assert_not_reached ("no memory to queue messages");
6173   
6174   if (_dbus_message_loader_get_is_corrupted (loader))
6175     {
6176       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
6177       goto failed;
6178     }
6179   
6180   message = _dbus_message_loader_pop_message (loader);
6181   if (message == NULL)
6182     {
6183       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
6184       goto failed;
6185     }
6186   
6187   if (_dbus_string_get_length (&loader->data) > 0)
6188     {
6189       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
6190       goto failed;
6191     }
6192
6193   /* Verify that we're able to properly deal with the message.
6194    * For example, this would detect improper handling of messages
6195    * in nonstandard byte order.
6196    */
6197   if (!check_message_handling (message))
6198     goto failed;  
6199   
6200   retval = TRUE;
6201
6202  failed:
6203   if (message)
6204     dbus_message_unref (message);
6205
6206   return retval;
6207 }
6208
6209 static dbus_bool_t
6210 check_invalid_message (DBusMessageLoader *loader)
6211 {
6212   dbus_bool_t retval;
6213
6214   retval = FALSE;
6215
6216   if (!_dbus_message_loader_queue_messages (loader))
6217     _dbus_assert_not_reached ("no memory to queue messages");
6218   
6219   if (!_dbus_message_loader_get_is_corrupted (loader))
6220     {
6221       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
6222       goto failed;
6223     }
6224
6225   retval = TRUE;
6226
6227  failed:
6228   return retval;
6229 }
6230
6231 static dbus_bool_t
6232 check_incomplete_message (DBusMessageLoader *loader)
6233 {
6234   DBusMessage *message;
6235   dbus_bool_t retval;
6236
6237   message = NULL;
6238   retval = FALSE;
6239
6240   if (!_dbus_message_loader_queue_messages (loader))
6241     _dbus_assert_not_reached ("no memory to queue messages");
6242   
6243   if (_dbus_message_loader_get_is_corrupted (loader))
6244     {
6245       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
6246       goto failed;
6247     }
6248   
6249   message = _dbus_message_loader_pop_message (loader);
6250   if (message != NULL)
6251     {
6252       _dbus_warn ("loaded message that was expected to be incomplete\n");
6253       goto failed;
6254     }
6255
6256   retval = TRUE;
6257
6258  failed:
6259   if (message)
6260     dbus_message_unref (message);
6261   return retval;
6262 }
6263
6264 static dbus_bool_t
6265 check_loader_results (DBusMessageLoader      *loader,
6266                       DBusMessageValidity     validity)
6267 {
6268   if (!_dbus_message_loader_queue_messages (loader))
6269     _dbus_assert_not_reached ("no memory to queue messages");
6270   
6271   switch (validity)
6272     {
6273     case _DBUS_MESSAGE_VALID:
6274       return check_have_valid_message (loader);
6275     case _DBUS_MESSAGE_INVALID:
6276       return check_invalid_message (loader);
6277     case _DBUS_MESSAGE_INCOMPLETE:
6278       return check_incomplete_message (loader);
6279     case _DBUS_MESSAGE_UNKNOWN:
6280       return TRUE;
6281     }
6282
6283   _dbus_assert_not_reached ("bad DBusMessageValidity");
6284   return FALSE;
6285 }
6286
6287
6288 /**
6289  * Loads the message in the given message file.
6290  *
6291  * @param filename filename to load
6292  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
6293  * @param data string to load message into
6294  * @returns #TRUE if the message was loaded
6295  */
6296 dbus_bool_t
6297 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
6298                                             dbus_bool_t          is_raw,
6299                                             DBusString          *data)
6300 {
6301   dbus_bool_t retval;
6302
6303   retval = FALSE;  
6304
6305   if (is_raw)
6306     {
6307       DBusError error;
6308
6309       _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename));
6310       dbus_error_init (&error);
6311       if (!_dbus_file_get_contents (data, filename, &error))
6312         {
6313           _dbus_warn ("Could not load message file %s: %s\n",
6314                       _dbus_string_get_const_data (filename),
6315                       error.message);
6316           dbus_error_free (&error);
6317           goto failed;
6318         }
6319     }
6320   else
6321     {
6322       if (!_dbus_message_data_load (data, filename))
6323         {
6324           _dbus_warn ("Could not load message file %s\n",
6325                       _dbus_string_get_const_data (filename));
6326           goto failed;
6327         }
6328     }
6329
6330   retval = TRUE;
6331   
6332  failed:
6333
6334   return retval;
6335 }
6336
6337 /**
6338  * Tries loading the message in the given message file
6339  * and verifies that DBusMessageLoader can handle it.
6340  *
6341  * @param filename filename to load
6342  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
6343  * @param expected_validity what the message has to be like to return #TRUE
6344  * @returns #TRUE if the message has the expected validity
6345  */
6346 dbus_bool_t
6347 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
6348                                            dbus_bool_t          is_raw,
6349                                            DBusMessageValidity  expected_validity)
6350 {
6351   DBusString data;
6352   dbus_bool_t retval;
6353
6354   retval = FALSE;
6355   
6356   if (!_dbus_string_init (&data))
6357     _dbus_assert_not_reached ("could not allocate string\n");
6358
6359   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
6360                                                    &data))
6361     goto failed;
6362
6363   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
6364
6365  failed:
6366
6367   if (!retval)
6368     {
6369       if (_dbus_string_get_length (&data) > 0)
6370         _dbus_verbose_bytes_of_string (&data, 0,
6371                                        _dbus_string_get_length (&data));
6372       
6373       _dbus_warn ("Failed message loader test on %s\n",
6374                   _dbus_string_get_const_data (filename));
6375     }
6376   
6377   _dbus_string_free (&data);
6378
6379   return retval;
6380 }
6381
6382 /**
6383  * Tries loading the given message data.
6384  *
6385  *
6386  * @param data the message data
6387  * @param expected_validity what the message has to be like to return #TRUE
6388  * @returns #TRUE if the message has the expected validity
6389  */
6390 dbus_bool_t
6391 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
6392                                            DBusMessageValidity  expected_validity)
6393 {
6394   DBusMessageLoader *loader;
6395   dbus_bool_t retval;
6396   int len;
6397   int i;
6398
6399   loader = NULL;
6400   retval = FALSE;
6401
6402   /* Write the data one byte at a time */
6403   
6404   loader = _dbus_message_loader_new ();
6405
6406   /* check some trivial loader functions */
6407   _dbus_message_loader_ref (loader);
6408   _dbus_message_loader_unref (loader);
6409   _dbus_message_loader_get_max_message_size (loader);
6410   
6411   len = _dbus_string_get_length (data);
6412   for (i = 0; i < len; i++)
6413     {
6414       DBusString *buffer;
6415
6416       _dbus_message_loader_get_buffer (loader, &buffer);
6417       _dbus_string_append_byte (buffer,
6418                                 _dbus_string_get_byte (data, i));
6419       _dbus_message_loader_return_buffer (loader, buffer, 1);
6420     }
6421   
6422   if (!check_loader_results (loader, expected_validity))
6423     goto failed;
6424
6425   _dbus_message_loader_unref (loader);
6426   loader = NULL;
6427
6428   /* Write the data all at once */
6429   
6430   loader = _dbus_message_loader_new ();
6431
6432   {
6433     DBusString *buffer;
6434     
6435     _dbus_message_loader_get_buffer (loader, &buffer);
6436     _dbus_string_copy (data, 0, buffer,
6437                        _dbus_string_get_length (buffer));
6438     _dbus_message_loader_return_buffer (loader, buffer, 1);
6439   }
6440   
6441   if (!check_loader_results (loader, expected_validity))
6442     goto failed;
6443
6444   _dbus_message_loader_unref (loader);
6445   loader = NULL;  
6446
6447   /* Write the data 2 bytes at a time */
6448   
6449   loader = _dbus_message_loader_new ();
6450
6451   len = _dbus_string_get_length (data);
6452   for (i = 0; i < len; i += 2)
6453     {
6454       DBusString *buffer;
6455
6456       _dbus_message_loader_get_buffer (loader, &buffer);
6457       _dbus_string_append_byte (buffer,
6458                                 _dbus_string_get_byte (data, i));
6459       if ((i+1) < len)
6460         _dbus_string_append_byte (buffer,
6461                                   _dbus_string_get_byte (data, i+1));
6462       _dbus_message_loader_return_buffer (loader, buffer, 1);
6463     }
6464   
6465   if (!check_loader_results (loader, expected_validity))
6466     goto failed;
6467
6468   _dbus_message_loader_unref (loader);
6469   loader = NULL;
6470   
6471   retval = TRUE;
6472   
6473  failed:
6474   
6475   if (loader)
6476     _dbus_message_loader_unref (loader);
6477   
6478   return retval;
6479 }
6480
6481 static dbus_bool_t
6482 process_test_subdir (const DBusString          *test_base_dir,
6483                      const char                *subdir,
6484                      DBusMessageValidity        validity,
6485                      DBusForeachMessageFileFunc function,
6486                      void                      *user_data)
6487 {
6488   DBusString test_directory;
6489   DBusString filename;
6490   DBusDirIter *dir;
6491   dbus_bool_t retval;
6492   DBusError error;
6493
6494   retval = FALSE;
6495   dir = NULL;
6496   
6497   if (!_dbus_string_init (&test_directory))
6498     _dbus_assert_not_reached ("didn't allocate test_directory\n");
6499
6500   _dbus_string_init_const (&filename, subdir);
6501   
6502   if (!_dbus_string_copy (test_base_dir, 0,
6503                           &test_directory, 0))
6504     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
6505   
6506   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
6507     _dbus_assert_not_reached ("couldn't allocate full path");
6508
6509   _dbus_string_free (&filename);
6510   if (!_dbus_string_init (&filename))
6511     _dbus_assert_not_reached ("didn't allocate filename string\n");
6512
6513   dbus_error_init (&error);
6514   dir = _dbus_directory_open (&test_directory, &error);
6515   if (dir == NULL)
6516     {
6517       _dbus_warn ("Could not open %s: %s\n",
6518                   _dbus_string_get_const_data (&test_directory),
6519                   error.message);
6520       dbus_error_free (&error);
6521       goto failed;
6522     }
6523
6524   printf ("Testing %s:\n", subdir);
6525   
6526  next:
6527   while (_dbus_directory_get_next_file (dir, &filename, &error))
6528     {
6529       DBusString full_path;
6530       dbus_bool_t is_raw;
6531       
6532       if (!_dbus_string_init (&full_path))
6533         _dbus_assert_not_reached ("couldn't init string");
6534
6535       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
6536         _dbus_assert_not_reached ("couldn't copy dir to full_path");
6537
6538       if (!_dbus_concat_dir_and_file (&full_path, &filename))
6539         _dbus_assert_not_reached ("couldn't concat file to dir");
6540
6541       if (_dbus_string_ends_with_c_str (&filename, ".message"))
6542         is_raw = FALSE;
6543       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
6544         is_raw = TRUE;
6545       else
6546         {
6547           _dbus_verbose ("Skipping non-.message file %s\n",
6548                          _dbus_string_get_const_data (&filename));
6549           _dbus_string_free (&full_path);
6550           goto next;
6551         }
6552
6553       printf ("    %s\n",
6554               _dbus_string_get_const_data (&filename));
6555       
6556       _dbus_verbose (" expecting %s for %s\n",
6557                      validity == _DBUS_MESSAGE_VALID ? "valid" :
6558                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
6559                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")),
6560                      _dbus_string_get_const_data (&filename));
6561       
6562       if (! (*function) (&full_path, is_raw, validity, user_data))
6563         {
6564           _dbus_string_free (&full_path);
6565           goto failed;
6566         }
6567       else
6568         _dbus_string_free (&full_path);
6569     }
6570
6571   if (dbus_error_is_set (&error))
6572     {
6573       _dbus_warn ("Could not get next file in %s: %s\n",
6574                   _dbus_string_get_const_data (&test_directory),
6575                   error.message);
6576       dbus_error_free (&error);
6577       goto failed;
6578     }
6579     
6580   retval = TRUE;
6581   
6582  failed:
6583
6584   if (dir)
6585     _dbus_directory_close (dir);
6586   _dbus_string_free (&test_directory);
6587   _dbus_string_free (&filename);
6588
6589   return retval;
6590 }
6591                      
6592 /**
6593  * Runs the given function on every message file in the test suite.
6594  * The function should return #FALSE on test failure or fatal error.
6595  *
6596  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
6597  * @param func the function to run
6598  * @param user_data data for function
6599  * @returns #FALSE if there's a failure
6600  */
6601 dbus_bool_t
6602 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
6603                                                DBusForeachMessageFileFunc func,
6604                                                void                      *user_data)
6605 {
6606   DBusString test_directory;
6607   dbus_bool_t retval;
6608
6609   retval = FALSE;
6610   
6611   _dbus_string_init_const (&test_directory, test_data_dir);
6612
6613   if (!process_test_subdir (&test_directory, "valid-messages",
6614                             _DBUS_MESSAGE_VALID, func, user_data))
6615     goto failed;
6616
6617   if (!process_test_subdir (&test_directory, "invalid-messages",
6618                             _DBUS_MESSAGE_INVALID, func, user_data))
6619     goto failed;
6620   
6621   if (!process_test_subdir (&test_directory, "incomplete-messages",
6622                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
6623     goto failed;
6624
6625   retval = TRUE;
6626   
6627  failed:
6628
6629   _dbus_string_free (&test_directory);
6630   
6631   return retval;
6632 }
6633
6634 static void
6635 verify_test_message (DBusMessage *message)
6636 {
6637   DBusMessageIter iter, dict;
6638   DBusError error;
6639   dbus_int32_t our_int;
6640   char *our_str;
6641   double our_double;
6642   dbus_bool_t our_bool;
6643   dbus_uint32_t our_uint32;
6644   dbus_int32_t *our_uint32_array;
6645   int our_uint32_array_len;
6646   dbus_int32_t *our_int32_array;
6647   int our_int32_array_len;
6648   char **our_string_array;
6649   int our_string_array_len;
6650 #ifdef DBUS_HAVE_INT64
6651   dbus_int64_t our_int64;
6652   dbus_uint64_t our_uint64;
6653   dbus_int64_t *our_uint64_array;
6654   int our_uint64_array_len;
6655   dbus_int64_t *our_int64_array;
6656   int our_int64_array_len;
6657 #endif
6658   double *our_double_array;
6659   int our_double_array_len;
6660   unsigned char *our_byte_array;
6661   int our_byte_array_len;
6662   unsigned char *our_boolean_array;
6663   int our_boolean_array_len;
6664   
6665   dbus_message_iter_init (message, &iter);
6666
6667   dbus_error_init (&error);
6668   if (!dbus_message_iter_get_args (&iter, &error,
6669                                    DBUS_TYPE_INT32, &our_int,
6670 #ifdef DBUS_HAVE_INT64
6671                                    DBUS_TYPE_INT64, &our_int64,
6672                                    DBUS_TYPE_UINT64, &our_uint64,
6673 #endif
6674                                    DBUS_TYPE_STRING, &our_str,
6675                                    DBUS_TYPE_DOUBLE, &our_double,
6676                                    DBUS_TYPE_BOOLEAN, &our_bool,
6677                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
6678                                    &our_uint32_array, &our_uint32_array_len,
6679                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
6680                                    &our_int32_array, &our_int32_array_len,
6681 #ifdef DBUS_HAVE_INT64
6682                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64,
6683                                    &our_uint64_array, &our_uint64_array_len,
6684                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT64,
6685                                    &our_int64_array, &our_int64_array_len,
6686 #endif
6687                                    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
6688                                    &our_string_array, &our_string_array_len,
6689                                    DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE,
6690                                    &our_double_array, &our_double_array_len,
6691                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
6692                                    &our_byte_array, &our_byte_array_len,
6693                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN,
6694                                    &our_boolean_array, &our_boolean_array_len,
6695                                    0))
6696     {
6697       _dbus_warn ("error: %s - %s\n", error.name,
6698                   (error.message != NULL) ? error.message : "no message");
6699       _dbus_assert_not_reached ("Could not get arguments");
6700     }
6701
6702   if (our_int != -0x12345678)
6703     _dbus_assert_not_reached ("integers differ!");
6704
6705 #ifdef DBUS_HAVE_INT64
6706   if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd))
6707     _dbus_assert_not_reached ("64-bit integers differ!");
6708   if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd))
6709     _dbus_assert_not_reached ("64-bit unsigned integers differ!");
6710 #endif
6711   
6712   if (our_double != 3.14159)
6713     _dbus_assert_not_reached ("doubles differ!");
6714
6715   if (strcmp (our_str, "Test string") != 0)
6716     _dbus_assert_not_reached ("strings differ!");
6717   dbus_free (our_str);
6718
6719   if (!our_bool)
6720     _dbus_assert_not_reached ("booleans differ");
6721
6722   if (our_uint32_array_len != 4 ||
6723       our_uint32_array[0] != 0x12345678 ||
6724       our_uint32_array[1] != 0x23456781 ||
6725       our_uint32_array[2] != 0x34567812 ||
6726       our_uint32_array[3] != 0x45678123)
6727     _dbus_assert_not_reached ("uint array differs");
6728   dbus_free (our_uint32_array);
6729
6730   if (our_int32_array_len != 4 ||
6731       our_int32_array[0] != 0x12345678 ||
6732       our_int32_array[1] != -0x23456781 ||
6733       our_int32_array[2] != 0x34567812 ||
6734       our_int32_array[3] != -0x45678123)
6735     _dbus_assert_not_reached ("int array differs");
6736   dbus_free (our_int32_array);
6737
6738 #ifdef DBUS_HAVE_INT64
6739   if (our_uint64_array_len != 4 ||
6740       our_uint64_array[0] != 0x12345678 ||
6741       our_uint64_array[1] != 0x23456781 ||
6742       our_uint64_array[2] != 0x34567812 ||
6743       our_uint64_array[3] != 0x45678123)
6744     _dbus_assert_not_reached ("uint64 array differs");
6745   dbus_free (our_uint64_array);
6746   
6747   if (our_int64_array_len != 4 ||
6748       our_int64_array[0] != 0x12345678 ||
6749       our_int64_array[1] != -0x23456781 ||
6750       our_int64_array[2] != 0x34567812 ||
6751       our_int64_array[3] != -0x45678123)
6752     _dbus_assert_not_reached ("int64 array differs");
6753   dbus_free (our_int64_array);
6754 #endif /* DBUS_HAVE_INT64 */
6755   
6756   if (our_string_array_len != 4)
6757     _dbus_assert_not_reached ("string array has wrong length");
6758
6759   if (strcmp (our_string_array[0], "Foo") != 0 ||
6760       strcmp (our_string_array[1], "bar") != 0 ||
6761       strcmp (our_string_array[2], "") != 0 ||
6762       strcmp (our_string_array[3], "woo woo woo woo") != 0)
6763     _dbus_assert_not_reached ("string array differs");
6764
6765   dbus_free_string_array (our_string_array);
6766
6767   if (our_double_array_len != 3)
6768     _dbus_assert_not_reached ("double array had wrong length");
6769
6770   /* On all IEEE machines (i.e. everything sane) exact equality
6771    * should be preserved over the wire
6772    */
6773   if (our_double_array[0] != 0.1234 ||
6774       our_double_array[1] != 9876.54321 ||
6775       our_double_array[2] != -300.0)
6776     _dbus_assert_not_reached ("double array had wrong values");
6777
6778   dbus_free (our_double_array);
6779
6780   if (our_byte_array_len != 4)
6781     _dbus_assert_not_reached ("byte array had wrong length");
6782
6783   if (our_byte_array[0] != 'a' ||
6784       our_byte_array[1] != 'b' ||
6785       our_byte_array[2] != 'c' ||
6786       our_byte_array[3] != 234)
6787     _dbus_assert_not_reached ("byte array had wrong values");
6788
6789   dbus_free (our_byte_array);
6790
6791   if (our_boolean_array_len != 5)
6792     _dbus_assert_not_reached ("bool array had wrong length");
6793
6794   if (our_boolean_array[0] != TRUE ||
6795       our_boolean_array[1] != FALSE ||
6796       our_boolean_array[2] != TRUE ||
6797       our_boolean_array[3] != TRUE ||
6798       our_boolean_array[4] != FALSE)
6799     _dbus_assert_not_reached ("bool array had wrong values");
6800
6801   dbus_free (our_boolean_array);
6802   
6803   if (!dbus_message_iter_next (&iter))
6804     _dbus_assert_not_reached ("Reached end of arguments");
6805
6806   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
6807     _dbus_assert_not_reached ("not dict type");
6808      
6809   dbus_message_iter_init_dict_iterator (&iter, &dict);
6810
6811   our_str = dbus_message_iter_get_dict_key (&dict);
6812   if (our_str == NULL || strcmp (our_str, "test") != 0)
6813     _dbus_assert_not_reached ("wrong dict key");
6814   dbus_free (our_str);
6815
6816   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
6817     {
6818       _dbus_verbose ("dict entry type: %d\n", dbus_message_iter_get_arg_type (&dict));
6819       _dbus_assert_not_reached ("wrong dict entry type");
6820     }
6821
6822   if ((our_uint32 = dbus_message_iter_get_uint32 (&dict)) != 0xDEADBEEF)
6823     {
6824       _dbus_verbose ("dict entry val: %x\n", our_uint32);
6825       _dbus_assert_not_reached ("wrong dict entry value");
6826     }
6827
6828   if (dbus_message_iter_next (&dict))
6829     _dbus_assert_not_reached ("Didn't reach end of dict");
6830   
6831   if (!dbus_message_iter_next (&iter))
6832     _dbus_assert_not_reached ("Reached end of arguments");
6833   
6834   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
6835     _dbus_assert_not_reached ("wrong type after dict");
6836   
6837   if (dbus_message_iter_get_uint32 (&iter) != 0xCAFEBABE)
6838     _dbus_assert_not_reached ("wrong value after dict");
6839
6840   if (dbus_message_iter_next (&iter))
6841     _dbus_assert_not_reached ("Didn't reach end of arguments");
6842 }
6843
6844 /**
6845  * @ingroup DBusMessageInternals
6846  * Unit test for DBusMessage.
6847  *
6848  * @returns #TRUE on success.
6849  */
6850 dbus_bool_t
6851 _dbus_message_test (const char *test_data_dir)
6852 {
6853   DBusMessage *message;
6854   DBusMessageLoader *loader;
6855   DBusMessageIter iter, child_iter, child_iter2, child_iter3;
6856   int i;
6857   const char *data;
6858   DBusMessage *copy;
6859   const char *name1;
6860   const char *name2;
6861   const dbus_uint32_t our_uint32_array[] =
6862     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
6863   const dbus_uint32_t our_int32_array[] =
6864     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
6865 #ifdef DBUS_HAVE_INT64
6866   const dbus_uint64_t our_uint64_array[] =
6867     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
6868   const dbus_uint64_t our_int64_array[] =
6869     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
6870 #endif
6871   const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" };
6872   const double our_double_array[] = { 0.1234, 9876.54321, -300.0 };
6873   const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 };
6874   const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE };
6875   char sig[64];
6876   const char *s;
6877   char *t;
6878   DBusError error;
6879   
6880   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
6881
6882   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
6883                                           "/org/freedesktop/TestPath",
6884                                           "Foo.TestInterface",
6885                                           "TestMethod");
6886   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
6887   _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",
6888                                              "TestMethod"));
6889   _dbus_assert (strcmp (dbus_message_get_path (message),
6890                         "/org/freedesktop/TestPath") == 0);
6891   _dbus_message_set_serial (message, 1234);
6892   /* string length including nul byte not a multiple of 4 */
6893   if (!dbus_message_set_sender (message, "org.foo.bar1"))
6894     _dbus_assert_not_reached ("out of memory");
6895   _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1"));
6896   dbus_message_set_reply_serial (message, 5678);
6897   if (!dbus_message_set_sender (message, NULL))
6898     _dbus_assert_not_reached ("out of memory");
6899   _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1"));
6900   _dbus_assert (dbus_message_get_serial (message) == 1234);
6901   _dbus_assert (dbus_message_get_reply_serial (message) == 5678);
6902   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
6903
6904   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
6905   dbus_message_set_no_reply (message, TRUE);
6906   _dbus_assert (dbus_message_get_no_reply (message) == TRUE);
6907   dbus_message_set_no_reply (message, FALSE);
6908   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
6909
6910   /* Set/get some header fields */
6911   
6912   if (!dbus_message_set_path (message, "/foo"))
6913     _dbus_assert_not_reached ("out of memory");
6914   _dbus_assert (strcmp (dbus_message_get_path (message),
6915                         "/foo") == 0);
6916
6917   if (!dbus_message_set_interface (message, "org.Foo"))
6918     _dbus_assert_not_reached ("out of memory");
6919   _dbus_assert (strcmp (dbus_message_get_interface (message),
6920                         "org.Foo") == 0);
6921   
6922   if (!dbus_message_set_member (message, "Bar"))
6923     _dbus_assert_not_reached ("out of memory");
6924   _dbus_assert (strcmp (dbus_message_get_member (message),
6925                         "Bar") == 0);
6926
6927   /* Set/get them with longer values */
6928   if (!dbus_message_set_path (message, "/foo/bar"))
6929     _dbus_assert_not_reached ("out of memory");
6930   _dbus_assert (strcmp (dbus_message_get_path (message),
6931                         "/foo/bar") == 0);
6932
6933   if (!dbus_message_set_interface (message, "org.Foo.Bar"))
6934     _dbus_assert_not_reached ("out of memory");
6935   _dbus_assert (strcmp (dbus_message_get_interface (message),
6936                         "org.Foo.Bar") == 0);
6937   
6938   if (!dbus_message_set_member (message, "BarFoo"))
6939     _dbus_assert_not_reached ("out of memory");
6940   _dbus_assert (strcmp (dbus_message_get_member (message),
6941                         "BarFoo") == 0);
6942
6943   /* Realloc shorter again */
6944   
6945   if (!dbus_message_set_path (message, "/foo"))
6946     _dbus_assert_not_reached ("out of memory");
6947   _dbus_assert (strcmp (dbus_message_get_path (message),
6948                         "/foo") == 0);
6949
6950   if (!dbus_message_set_interface (message, "org.Foo"))
6951     _dbus_assert_not_reached ("out of memory");
6952   _dbus_assert (strcmp (dbus_message_get_interface (message),
6953                         "org.Foo") == 0);
6954   
6955   if (!dbus_message_set_member (message, "Bar"))
6956     _dbus_assert_not_reached ("out of memory");
6957   _dbus_assert (strcmp (dbus_message_get_member (message),
6958                         "Bar") == 0);
6959   
6960   dbus_message_unref (message);
6961   
6962   /* Test the vararg functions */
6963   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
6964                                           "/org/freedesktop/TestPath",
6965                                           "Foo.TestInterface",
6966                                           "TestMethod");
6967   _dbus_message_set_serial (message, 1);
6968   dbus_message_append_args (message,
6969                             DBUS_TYPE_INT32, -0x12345678,
6970 #ifdef DBUS_HAVE_INT64
6971                             DBUS_TYPE_INT64, DBUS_INT64_CONSTANT (-0x123456789abcd),
6972                             DBUS_TYPE_UINT64, DBUS_UINT64_CONSTANT (0x123456789abcd),
6973 #endif
6974                             DBUS_TYPE_STRING, "Test string",
6975                             DBUS_TYPE_DOUBLE, 3.14159,
6976                             DBUS_TYPE_BOOLEAN, TRUE,
6977                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, our_uint32_array,
6978                             _DBUS_N_ELEMENTS (our_uint32_array),
6979                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, our_int32_array,
6980                             _DBUS_N_ELEMENTS (our_int32_array),
6981 #ifdef DBUS_HAVE_INT64
6982                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, our_uint64_array,
6983                             _DBUS_N_ELEMENTS (our_uint64_array),
6984                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array,
6985                             _DBUS_N_ELEMENTS (our_int64_array),
6986 #endif
6987                             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array,
6988                             _DBUS_N_ELEMENTS (our_string_array),
6989                             DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array,
6990                             _DBUS_N_ELEMENTS (our_double_array),
6991                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, our_byte_array,
6992                             _DBUS_N_ELEMENTS (our_byte_array),
6993                             DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, our_boolean_array,
6994                             _DBUS_N_ELEMENTS (our_boolean_array),
6995                             0);
6996   
6997   dbus_message_append_iter_init (message, &iter);
6998   dbus_message_iter_append_dict (&iter, &child_iter);
6999   dbus_message_iter_append_dict_key (&child_iter, "test");
7000   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
7001   dbus_message_iter_append_uint32 (&iter, 0xCAFEBABE);
7002
7003   i = 0;
7004   sig[i++] = DBUS_TYPE_INT32;
7005 #ifdef DBUS_HAVE_INT64
7006   sig[i++] = DBUS_TYPE_INT64;
7007   sig[i++] = DBUS_TYPE_UINT64;
7008 #endif
7009   sig[i++] = DBUS_TYPE_STRING;
7010   sig[i++] = DBUS_TYPE_DOUBLE;
7011   sig[i++] = DBUS_TYPE_BOOLEAN;
7012   sig[i++] = DBUS_TYPE_ARRAY;
7013   sig[i++] = DBUS_TYPE_UINT32;
7014   sig[i++] = DBUS_TYPE_ARRAY;
7015   sig[i++] = DBUS_TYPE_INT32;
7016 #ifdef DBUS_HAVE_INT64
7017   sig[i++] = DBUS_TYPE_ARRAY;
7018   sig[i++] = DBUS_TYPE_UINT64;
7019   sig[i++] = DBUS_TYPE_ARRAY;
7020   sig[i++] = DBUS_TYPE_INT64;
7021 #endif
7022   sig[i++] = DBUS_TYPE_ARRAY;
7023   sig[i++] = DBUS_TYPE_STRING;
7024   sig[i++] = DBUS_TYPE_ARRAY;
7025   sig[i++] = DBUS_TYPE_DOUBLE;
7026   sig[i++] = DBUS_TYPE_ARRAY;
7027   sig[i++] = DBUS_TYPE_BYTE;
7028   sig[i++] = DBUS_TYPE_ARRAY;
7029   sig[i++] = DBUS_TYPE_BOOLEAN;
7030   sig[i++] = DBUS_TYPE_DICT;
7031   sig[i++] = DBUS_TYPE_UINT32;
7032   sig[i++] = DBUS_TYPE_INVALID;
7033
7034   _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig));
7035   
7036   _dbus_verbose_bytes_of_string (&message->header, 0,
7037                                  _dbus_string_get_length (&message->header));
7038   _dbus_verbose_bytes_of_string (&message->body, 0,
7039                                  _dbus_string_get_length (&message->body));
7040   
7041   _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n",
7042                  sig, dbus_message_get_signature (message));
7043   
7044   s = dbus_message_get_signature (message);
7045   
7046   _dbus_assert (dbus_message_has_signature (message, sig));
7047   _dbus_assert (strcmp (s, sig) == 0);
7048   
7049   verify_test_message (message);
7050
7051   copy = dbus_message_copy (message);
7052   
7053   _dbus_assert (message->client_serial == copy->client_serial);
7054   _dbus_assert (message->reply_serial == copy->reply_serial);
7055   _dbus_assert (message->header_padding == copy->header_padding);
7056   
7057   _dbus_assert (_dbus_string_get_length (&message->header) ==
7058                 _dbus_string_get_length (&copy->header));
7059
7060   _dbus_assert (_dbus_string_get_length (&message->body) ==
7061                 _dbus_string_get_length (&copy->body));
7062
7063   _dbus_assert (_dbus_string_get_length (&message->signature) ==
7064                 _dbus_string_get_length (&copy->signature));
7065   
7066   verify_test_message (copy);
7067
7068   name1 = dbus_message_get_interface (message);
7069   name2 = dbus_message_get_interface (copy);
7070
7071   _dbus_assert (strcmp (name1, name2) == 0);
7072
7073   name1 = dbus_message_get_member (message);
7074   name2 = dbus_message_get_member (copy);
7075
7076   _dbus_assert (strcmp (name1, name2) == 0);
7077   
7078   dbus_message_unref (message);  
7079   dbus_message_unref (copy);
7080
7081   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
7082                                           "/org/freedesktop/TestPath",
7083                                           "Foo.TestInterface",
7084                                           "TestMethod");
7085
7086   _dbus_message_set_serial (message, 1);
7087   dbus_message_set_reply_serial (message, 0x12345678);
7088
7089   dbus_message_append_iter_init (message, &iter);
7090   dbus_message_iter_append_string (&iter, "Test string");
7091   dbus_message_iter_append_int32 (&iter, -0x12345678);
7092   dbus_message_iter_append_uint32 (&iter, 0xedd1e);
7093   dbus_message_iter_append_double (&iter, 3.14159);
7094
7095   dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE);
7096   dbus_message_iter_append_double (&child_iter, 1.5);
7097   dbus_message_iter_append_double (&child_iter, 2.5);
7098
7099   /* dict */
7100   dbus_message_iter_append_dict (&iter, &child_iter);
7101   dbus_message_iter_append_dict_key (&child_iter, "test");
7102   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
7103
7104   /* array of array of int32  (in dict) */
7105   dbus_message_iter_append_dict_key (&child_iter, "array");
7106   dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY);
7107   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
7108   dbus_message_iter_append_int32 (&child_iter3, 0x12345678);
7109   dbus_message_iter_append_int32 (&child_iter3, 0x23456781);
7110   _dbus_warn ("next call expected to fail with wrong array type\n");
7111   _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32));
7112   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
7113   dbus_message_iter_append_int32 (&child_iter3, 0x34567812);
7114   dbus_message_iter_append_int32 (&child_iter3, 0x45678123);
7115   dbus_message_iter_append_int32 (&child_iter3, 0x56781234);
7116   
7117   dbus_message_iter_append_byte (&iter, 0xF0);
7118
7119   dbus_message_iter_append_nil (&iter);
7120
7121   dbus_message_iter_append_custom (&iter, "MyTypeName",
7122                                    "data", 5);
7123   
7124   message_iter_test (message);
7125   
7126   /* Message loader test */
7127   _dbus_message_lock (message);
7128   loader = _dbus_message_loader_new ();
7129
7130   /* check ref/unref */
7131   _dbus_message_loader_ref (loader);
7132   _dbus_message_loader_unref (loader);
7133   
7134   /* Write the header data one byte at a time */
7135   data = _dbus_string_get_const_data (&message->header);
7136   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
7137     {
7138       DBusString *buffer;
7139
7140       _dbus_message_loader_get_buffer (loader, &buffer);
7141       _dbus_string_append_byte (buffer, data[i]);
7142       _dbus_message_loader_return_buffer (loader, buffer, 1);
7143     }
7144
7145   /* Write the body data one byte at a time */
7146   data = _dbus_string_get_const_data (&message->body);
7147   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
7148     {
7149       DBusString *buffer;
7150
7151       _dbus_message_loader_get_buffer (loader, &buffer);
7152       _dbus_string_append_byte (buffer, data[i]);
7153       _dbus_message_loader_return_buffer (loader, buffer, 1);
7154     }
7155
7156   copy = dbus_message_copy (message); /* save for tests below */
7157   dbus_message_unref (message);
7158
7159   /* Now pop back the message */
7160   if (!_dbus_message_loader_queue_messages (loader))
7161     _dbus_assert_not_reached ("no memory to queue messages");
7162   
7163   if (_dbus_message_loader_get_is_corrupted (loader))
7164     _dbus_assert_not_reached ("message loader corrupted");
7165   
7166   message = _dbus_message_loader_pop_message (loader);
7167   if (!message)
7168     _dbus_assert_not_reached ("received a NULL message");
7169
7170   if (dbus_message_get_reply_serial (message) != 0x12345678)
7171     _dbus_assert_not_reached ("reply serial fields differ");
7172   
7173   message_iter_test (message);
7174   
7175   dbus_message_unref (message);
7176   _dbus_message_loader_unref (loader);
7177
7178   message = dbus_message_new_method_return (copy);
7179   if (message == NULL)
7180     _dbus_assert_not_reached ("out of memory\n");
7181   dbus_message_unref (copy);
7182
7183   if (!dbus_message_append_args (message,
7184                                  DBUS_TYPE_STRING, "hello",
7185                                  DBUS_TYPE_INVALID))
7186     _dbus_assert_not_reached ("no memory");
7187
7188   if (!dbus_message_has_signature (message, "s"))
7189     _dbus_assert_not_reached ("method return has wrong signature");
7190
7191   dbus_error_init (&error);
7192   if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING,
7193                               &t, DBUS_TYPE_INVALID))
7194     
7195     {
7196       _dbus_warn ("Failed to get expected string arg: %s\n", error.message);
7197       exit (1);
7198     }
7199   dbus_free (t);
7200   
7201   dbus_message_unref (message);
7202   
7203   /* Now load every message in test_data_dir if we have one */
7204   if (test_data_dir == NULL)
7205     return TRUE;
7206
7207   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
7208                                                         (DBusForeachMessageFileFunc)
7209                                                         dbus_internal_do_not_use_try_message_file,
7210                                                         NULL);
7211 }
7212
7213 #endif /* DBUS_BUILD_TESTS */