2003-12-02 Richard Hult <richard@imendio.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  * @returns the message
1508  * @see dbus_message_unref
1509  */
1510 DBusMessage *
1511 dbus_message_ref (DBusMessage *message)
1512 {
1513   dbus_int32_t old_refcount;
1514
1515   _dbus_return_val_if_fail (message != NULL, NULL);
1516   
1517   old_refcount = _dbus_atomic_inc (&message->refcount);
1518   _dbus_assert (old_refcount >= 1);
1519
1520   return message;
1521 }
1522
1523 static void
1524 free_size_counter (void *element,
1525                    void *data)
1526 {
1527   DBusCounter *counter = element;
1528   DBusMessage *message = data;
1529   
1530   _dbus_counter_adjust (counter, - message->size_counter_delta);
1531
1532   _dbus_counter_unref (counter);
1533 }
1534
1535 /**
1536  * Decrements the reference count of a DBusMessage.
1537  *
1538  * @param message The message
1539  * @see dbus_message_ref
1540  */
1541 void
1542 dbus_message_unref (DBusMessage *message)
1543 {
1544  dbus_int32_t old_refcount;
1545
1546   _dbus_return_if_fail (message != NULL);
1547   
1548   old_refcount = _dbus_atomic_dec (&message->refcount);
1549   
1550   _dbus_assert (old_refcount >= 0);
1551
1552   if (old_refcount == 1)
1553     {
1554       /* This calls application callbacks! */
1555       _dbus_data_slot_list_free (&message->slot_list);
1556       
1557       _dbus_list_foreach (&message->size_counters,
1558                           free_size_counter, message);
1559       _dbus_list_clear (&message->size_counters);
1560       
1561       _dbus_string_free (&message->header);
1562       _dbus_string_free (&message->body);
1563       _dbus_string_free (&message->signature);
1564       
1565       dbus_free (message);
1566     }
1567 }
1568
1569 /**
1570  * Gets the type of a message. Types include
1571  * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN,
1572  * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types
1573  * are allowed and all code must silently ignore messages of unknown
1574  * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however.
1575  *
1576  *
1577  * @param message the message
1578  * @returns the type of the message
1579  */
1580 int
1581 dbus_message_get_type (DBusMessage *message)
1582 {
1583   int type;
1584
1585   type = _dbus_string_get_byte (&message->header, 1);
1586   _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID);
1587
1588   return type;
1589 }
1590
1591 /**
1592  * Sets the object path this message is being sent to (for
1593  * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being
1594  * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL).
1595  *
1596  * @param message the message
1597  * @param object_path the path
1598  * @returns #FALSE if not enough memory
1599  */
1600 dbus_bool_t
1601 dbus_message_set_path (DBusMessage   *message,
1602                        const char    *object_path)
1603 {
1604   _dbus_return_val_if_fail (message != NULL, FALSE);
1605   _dbus_return_val_if_fail (!message->locked, FALSE);
1606
1607   return set_string_field (message,
1608                            DBUS_HEADER_FIELD_PATH,
1609                            DBUS_TYPE_OBJECT_PATH,
1610                            object_path);
1611 }
1612
1613 /**
1614  * Gets the object path this message is being sent to
1615  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1616  * from (for DBUS_MESSAGE_TYPE_SIGNAL).
1617  *
1618  * @param message the message
1619  * @returns the path (should not be freed)
1620  */
1621 const char*
1622 dbus_message_get_path (DBusMessage   *message)
1623 {
1624   _dbus_return_val_if_fail (message != NULL, NULL);
1625   
1626   return get_string_field (message, DBUS_HEADER_FIELD_PATH, NULL);
1627 }
1628
1629 /**
1630  * Gets the object path this message is being sent to
1631  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1632  * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed
1633  * format (one array element per path component).
1634  * Free the returned array with dbus_free_string_array().
1635  *
1636  * An empty but non-NULL path array means the path "/".
1637  * So the path "/foo/bar" becomes { "foo", "bar", NULL }
1638  * and the path "/" becomes { NULL }.
1639  *
1640  * @param message the message
1641  * @param path place to store allocated array of path components; #NULL set here if no path field exists
1642  * @returns #FALSE if no memory to allocate the array
1643  */
1644 dbus_bool_t
1645 dbus_message_get_path_decomposed (DBusMessage   *message,
1646                                   char        ***path)
1647 {
1648   _dbus_return_val_if_fail (message != NULL, FALSE);
1649   _dbus_return_val_if_fail (path != NULL, FALSE);
1650
1651   return get_path_field_decomposed (message,
1652                                     DBUS_HEADER_FIELD_PATH,
1653                                     path);
1654 }
1655
1656 /**
1657  * Sets the interface this message is being sent to
1658  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or
1659  * the interface a signal is being emitted from
1660  * (for DBUS_MESSAGE_TYPE_SIGNAL).
1661  *
1662  * @param message the message
1663  * @param interface the interface
1664  * @returns #FALSE if not enough memory
1665  */
1666 dbus_bool_t
1667 dbus_message_set_interface (DBusMessage  *message,
1668                             const char   *interface)
1669 {
1670   _dbus_return_val_if_fail (message != NULL, FALSE);
1671   _dbus_return_val_if_fail (!message->locked, FALSE);
1672
1673   return set_string_field (message,
1674                            DBUS_HEADER_FIELD_INTERFACE,
1675                            DBUS_TYPE_STRING,
1676                            interface);
1677 }
1678
1679 /**
1680  * Gets the interface this message is being sent to
1681  * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
1682  * from (for DBUS_MESSAGE_TYPE_SIGNAL).
1683  * The interface name is fully-qualified (namespaced).
1684  *
1685  * @param message the message
1686  * @returns the message interface (should not be freed)
1687  */
1688 const char*
1689 dbus_message_get_interface (DBusMessage *message)
1690 {
1691   _dbus_return_val_if_fail (message != NULL, NULL);
1692   
1693   return get_string_field (message, DBUS_HEADER_FIELD_INTERFACE, NULL);
1694 }
1695
1696 /**
1697  * Sets the interface member being invoked
1698  * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
1699  * (DBUS_MESSAGE_TYPE_SIGNAL).
1700  * The interface name is fully-qualified (namespaced).
1701  *
1702  * @param message the message
1703  * @param member the member
1704  * @returns #FALSE if not enough memory
1705  */
1706 dbus_bool_t
1707 dbus_message_set_member (DBusMessage  *message,
1708                        const char   *member)
1709 {
1710   _dbus_return_val_if_fail (message != NULL, FALSE);
1711   _dbus_return_val_if_fail (!message->locked, FALSE);
1712
1713   return set_string_field (message,
1714                            DBUS_HEADER_FIELD_MEMBER,
1715                            DBUS_TYPE_STRING,
1716                            member);
1717 }
1718
1719 /**
1720  * Gets the interface member being invoked
1721  * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
1722  * (DBUS_MESSAGE_TYPE_SIGNAL).
1723  * 
1724  * @param message the message
1725  * @returns the member name (should not be freed)
1726  */
1727 const char*
1728 dbus_message_get_member (DBusMessage *message)
1729 {
1730   _dbus_return_val_if_fail (message != NULL, NULL);
1731   
1732   return get_string_field (message,
1733                            DBUS_HEADER_FIELD_MEMBER,
1734                            NULL);
1735 }
1736
1737 /**
1738  * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR).
1739  * The name is fully-qualified (namespaced).
1740  *
1741  * @param message the message
1742  * @param error_name the name
1743  * @returns #FALSE if not enough memory
1744  */
1745 dbus_bool_t
1746 dbus_message_set_error_name (DBusMessage  *message,
1747                              const char   *error_name)
1748 {
1749   _dbus_return_val_if_fail (message != NULL, FALSE);
1750   _dbus_return_val_if_fail (!message->locked, FALSE);
1751
1752   return set_string_field (message,
1753                            DBUS_HEADER_FIELD_ERROR_NAME,
1754                            DBUS_TYPE_STRING,
1755                            error_name);
1756 }
1757
1758 /**
1759  * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only).
1760  * 
1761  * @param message the message
1762  * @returns the error name (should not be freed)
1763  */
1764 const char*
1765 dbus_message_get_error_name (DBusMessage *message)
1766 {
1767   _dbus_return_val_if_fail (message != NULL, NULL);
1768   
1769   return get_string_field (message,
1770                            DBUS_HEADER_FIELD_ERROR_NAME,
1771                            NULL);
1772 }
1773
1774 /**
1775  * Sets the message's destination service.
1776  *
1777  * @param message the message
1778  * @param destination the destination service name
1779  * @returns #FALSE if not enough memory
1780  */
1781 dbus_bool_t
1782 dbus_message_set_destination (DBusMessage  *message,
1783                               const char   *destination)
1784 {
1785   _dbus_return_val_if_fail (message != NULL, FALSE);
1786   _dbus_return_val_if_fail (!message->locked, FALSE);
1787
1788   return set_string_field (message,
1789                            DBUS_HEADER_FIELD_SERVICE,
1790                            DBUS_TYPE_STRING,
1791                            destination);
1792 }
1793
1794 /**
1795  * Gets the destination service of a message.
1796  * 
1797  * @param message the message
1798  * @returns the message destination service (should not be freed)
1799  */
1800 const char*
1801 dbus_message_get_destination (DBusMessage *message)
1802 {
1803   _dbus_return_val_if_fail (message != NULL, NULL);
1804   
1805   return get_string_field (message,
1806                            DBUS_HEADER_FIELD_SERVICE,
1807                            NULL);
1808 }
1809
1810 /**
1811  * Appends fields to a message given a variable argument list. The
1812  * variable argument list should contain the type of the argument
1813  * followed by the value to add.  Array values are specified by an int
1814  * typecode followed by a pointer to the array followed by an int
1815  * giving the length of the array.  The argument list must be
1816  * terminated with #DBUS_TYPE_INVALID.
1817  *
1818  * This function doesn't support dicts or non-fundamental arrays.
1819  *
1820  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
1821  * only if #DBUS_HAVE_INT64 is defined.
1822  *
1823  * @param message the message
1824  * @param first_arg_type type of the first argument
1825  * @param ... value of first argument, list of additional type-value pairs
1826  * @returns #TRUE on success
1827  */
1828 dbus_bool_t
1829 dbus_message_append_args (DBusMessage *message,
1830                           int first_arg_type,
1831                           ...)
1832 {
1833   dbus_bool_t retval;
1834   va_list var_args;
1835
1836   _dbus_return_val_if_fail (message != NULL, FALSE);
1837   
1838   va_start (var_args, first_arg_type);
1839   retval = dbus_message_append_args_valist (message,
1840                                             first_arg_type,
1841                                             var_args);
1842   va_end (var_args);
1843
1844   return retval;
1845 }
1846
1847 /**
1848  * This function takes a va_list for use by language bindings.
1849  * It's otherwise the same as dbus_message_append_args().
1850  *
1851  * @todo: Shouldn't this function clean up the changes to the message
1852  *        on failures? (Yes)
1853   
1854  * @see dbus_message_append_args.  
1855  * @param message the message
1856  * @param first_arg_type type of first argument
1857  * @param var_args value of first argument, then list of type/value pairs
1858  * @returns #TRUE on success
1859  */
1860 dbus_bool_t
1861 dbus_message_append_args_valist (DBusMessage *message,
1862                                  int          first_arg_type,
1863                                  va_list      var_args)
1864 {
1865   int type, old_len;
1866   DBusMessageIter iter;
1867
1868   _dbus_return_val_if_fail (message != NULL, FALSE);
1869   
1870   old_len = _dbus_string_get_length (&message->body);
1871   
1872   type = first_arg_type;
1873
1874   dbus_message_append_iter_init (message, &iter);
1875   
1876   while (type != DBUS_TYPE_INVALID)
1877     {
1878       switch (type)
1879         {
1880         case DBUS_TYPE_NIL:
1881           if (!dbus_message_iter_append_nil (&iter))
1882             goto errorout;
1883           break;
1884         case DBUS_TYPE_BOOLEAN:
1885           if (!dbus_message_iter_append_boolean (&iter, va_arg (var_args, dbus_bool_t)))
1886             goto errorout;
1887           break;
1888         case DBUS_TYPE_INT32:
1889           if (!dbus_message_iter_append_int32 (&iter, va_arg (var_args, dbus_int32_t)))
1890             goto errorout;
1891           break;
1892         case DBUS_TYPE_UINT32:
1893           if (!dbus_message_iter_append_uint32 (&iter, va_arg (var_args, dbus_uint32_t)))
1894             goto errorout;          
1895           break;
1896 #ifdef DBUS_HAVE_INT64
1897         case DBUS_TYPE_INT64:
1898           if (!dbus_message_iter_append_int64 (&iter, va_arg (var_args, dbus_int64_t)))
1899             goto errorout;
1900           break;
1901         case DBUS_TYPE_UINT64:
1902           if (!dbus_message_iter_append_uint64 (&iter, va_arg (var_args, dbus_uint64_t)))
1903             goto errorout;          
1904           break;
1905 #endif /* DBUS_HAVE_INT64 */
1906         case DBUS_TYPE_DOUBLE:
1907           if (!dbus_message_iter_append_double (&iter, va_arg (var_args, double)))
1908             goto errorout;
1909           break;
1910         case DBUS_TYPE_STRING:
1911           if (!dbus_message_iter_append_string (&iter, va_arg (var_args, const char *)))
1912             goto errorout;
1913           break;
1914         case DBUS_TYPE_OBJECT_PATH:
1915
1916           break;
1917         case DBUS_TYPE_CUSTOM:
1918           {
1919             const char *name;
1920             unsigned char *data;
1921             int len;
1922  
1923             name = va_arg (var_args, const char *);
1924             data = va_arg (var_args, unsigned char *);
1925             len = va_arg (var_args, int);
1926
1927             if (!dbus_message_iter_append_custom (&iter, name, data, len))
1928               goto errorout;
1929             break;
1930           }
1931         case DBUS_TYPE_ARRAY:
1932           {
1933             void *data;
1934             int len, type;
1935  
1936             type = va_arg (var_args, int);
1937             data = va_arg (var_args, void *);
1938             len = va_arg (var_args, int);
1939
1940             switch (type)
1941               {
1942               case DBUS_TYPE_BYTE:
1943                 if (!dbus_message_iter_append_byte_array (&iter, (unsigned char *)data, len))
1944                   goto errorout;
1945                 break;
1946               case DBUS_TYPE_BOOLEAN:
1947                 if (!dbus_message_iter_append_boolean_array (&iter, (unsigned char *)data, len))
1948                   goto errorout;
1949                 break;
1950               case DBUS_TYPE_INT32:
1951                 if (!dbus_message_iter_append_int32_array (&iter, (dbus_int32_t *)data, len))
1952                   goto errorout;
1953                 break;
1954               case DBUS_TYPE_UINT32:
1955                 if (!dbus_message_iter_append_uint32_array (&iter, (dbus_uint32_t *)data, len))
1956                   goto errorout;
1957                 break;
1958 #ifdef DBUS_HAVE_INT64
1959               case DBUS_TYPE_INT64:
1960                 if (!dbus_message_iter_append_int64_array (&iter, (dbus_int64_t *)data, len))
1961                   goto errorout;
1962                 break;
1963               case DBUS_TYPE_UINT64:
1964                 if (!dbus_message_iter_append_uint64_array (&iter, (dbus_uint64_t *)data, len))
1965                   goto errorout;
1966                 break;
1967 #endif /* DBUS_HAVE_INT64 */
1968               case DBUS_TYPE_DOUBLE:
1969                 if (!dbus_message_iter_append_double_array (&iter, (double *)data, len))
1970                   goto errorout;
1971                 break;
1972               case DBUS_TYPE_STRING:
1973                 if (!dbus_message_iter_append_string_array (&iter, (const char **)data, len))
1974                   goto errorout;
1975                 break;
1976               case DBUS_TYPE_NIL:
1977               case DBUS_TYPE_ARRAY:
1978               case DBUS_TYPE_CUSTOM:
1979               case DBUS_TYPE_DICT:
1980                 _dbus_warn ("dbus_message_append_args_valist doesn't support recursive arrays\n");
1981                 goto errorout;
1982               default:
1983                 _dbus_warn ("Unknown field type %d\n", type);
1984                 goto errorout;
1985               }
1986           }
1987           break;
1988           
1989         case DBUS_TYPE_DICT:
1990           _dbus_warn ("dbus_message_append_args_valist doesn't support dicts\n");
1991           goto errorout;
1992         default:
1993           _dbus_warn ("Unknown field type %d\n", type);
1994           goto errorout;
1995         }
1996
1997       type = va_arg (var_args, int);
1998     }
1999
2000   return TRUE;
2001
2002  errorout:
2003   return FALSE;
2004 }
2005
2006
2007 /**
2008  * Gets arguments from a message given a variable argument list.
2009  * The variable argument list should contain the type of the
2010  * argumen followed by a pointer to where the value should be
2011  * stored. The list is terminated with #DBUS_TYPE_INVALID.
2012  *
2013  * @param message the message
2014  * @param error error to be filled in on failure
2015  * @param first_arg_type the first argument type
2016  * @param ... location for first argument value, then list of type-location pairs
2017  * @returns #FALSE if the error was set
2018  */
2019 dbus_bool_t
2020 dbus_message_get_args (DBusMessage     *message,
2021                        DBusError       *error,
2022                        int              first_arg_type,
2023                        ...)
2024 {
2025   dbus_bool_t retval;
2026   va_list var_args;
2027
2028   _dbus_return_val_if_fail (message != NULL, FALSE);
2029   _dbus_return_val_if_error_is_set (error, FALSE);
2030   
2031   va_start (var_args, first_arg_type);
2032   retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args);
2033   va_end (var_args);
2034
2035   return retval;
2036 }
2037
2038 /**
2039  * This function takes a va_list for use by language bindings
2040  *
2041  * @todo We need to free the argument data when an error occurs.
2042  *
2043  * @see dbus_message_get_args
2044  * @param message the message
2045  * @param error error to be filled in
2046  * @param first_arg_type type of the first argument
2047  * @param var_args return location for first argument, followed by list of type/location pairs
2048  * @returns #FALSE if error was set
2049  */
2050 dbus_bool_t
2051 dbus_message_get_args_valist (DBusMessage     *message,
2052                               DBusError       *error,
2053                               int              first_arg_type,
2054                               va_list          var_args)
2055 {
2056   DBusMessageIter iter;
2057
2058   _dbus_return_val_if_fail (message != NULL, FALSE);
2059   _dbus_return_val_if_error_is_set (error, FALSE);
2060   
2061   dbus_message_iter_init (message, &iter);
2062   return dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args);
2063 }
2064
2065 /**
2066  * Gets arguments from a message iterator given a variable argument list.
2067  * The variable argument list should contain the type of the
2068  * argumen followed by a pointer to where the value should be
2069  * stored. The list is terminated with 0.
2070  *
2071  * @param iter the message iterator 
2072  * @param error error to be filled in on failure
2073  * @param first_arg_type the first argument type
2074  * @param ... location for first argument value, then list of type-location pairs
2075  * @returns #FALSE if the error was set
2076  */
2077 dbus_bool_t
2078 dbus_message_iter_get_args (DBusMessageIter *iter,
2079                             DBusError       *error,
2080                             int              first_arg_type,
2081                             ...)
2082 {
2083   dbus_bool_t retval;
2084   va_list var_args;
2085
2086   _dbus_return_val_if_fail (iter != NULL, FALSE);
2087   _dbus_return_val_if_error_is_set (error, FALSE);
2088   
2089   va_start (var_args, first_arg_type);
2090   retval = dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args);
2091   va_end (var_args);
2092
2093   return retval;
2094 }
2095
2096 /**
2097  * This function takes a va_list for use by language bindings
2098  *
2099  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
2100  * only if #DBUS_HAVE_INT64 is defined.
2101  *
2102  * @todo this function (or some lower-level non-convenience function)
2103  * needs better error handling; should allow the application to
2104  * distinguish between out of memory, and bad data from the remote
2105  * app. It also needs to not leak a bunch of args when it gets
2106  * to the arg that's bad, as that would be a security hole
2107  * (allow one app to force another to leak memory)
2108  *
2109  * @todo We need to free the argument data when an error occurs.
2110  *
2111  * @see dbus_message_get_args
2112  * @param iter the message iter
2113  * @param error error to be filled in
2114  * @param first_arg_type type of the first argument
2115  * @param var_args return location for first argument, followed by list of type/location pairs
2116  * @returns #FALSE if error was set
2117  */
2118 dbus_bool_t
2119 dbus_message_iter_get_args_valist (DBusMessageIter *iter,
2120                                    DBusError       *error,
2121                                    int              first_arg_type,
2122                                    va_list          var_args)
2123 {
2124   int spec_type, msg_type, i;
2125   dbus_bool_t retval;
2126
2127   _dbus_return_val_if_fail (iter != NULL, FALSE);
2128   _dbus_return_val_if_error_is_set (error, FALSE);
2129
2130   retval = FALSE;
2131   
2132   spec_type = first_arg_type;
2133   i = 0;
2134   
2135   while (spec_type != 0)
2136     {
2137       msg_type = dbus_message_iter_get_arg_type (iter);      
2138       
2139       if (msg_type != spec_type)
2140         {
2141           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2142                           "Argument %d is specified to be of type \"%s\", but "
2143                           "is actually of type \"%s\"\n", i,
2144                           _dbus_type_to_string (spec_type),
2145                           _dbus_type_to_string (msg_type));
2146
2147           goto out;
2148         }
2149
2150       switch (spec_type)
2151         {
2152         case DBUS_TYPE_NIL:
2153           break;
2154         case DBUS_TYPE_BYTE:
2155           {
2156             unsigned char *ptr;
2157
2158             ptr = va_arg (var_args, unsigned char *);
2159
2160             *ptr = dbus_message_iter_get_byte (iter);
2161             break;
2162           }
2163         case DBUS_TYPE_BOOLEAN:
2164           {
2165             dbus_bool_t *ptr;
2166
2167             ptr = va_arg (var_args, dbus_bool_t *);
2168
2169             *ptr = dbus_message_iter_get_boolean (iter);
2170             break;
2171           }
2172         case DBUS_TYPE_INT32:
2173           {
2174             dbus_int32_t *ptr;
2175
2176             ptr = va_arg (var_args, dbus_int32_t *);
2177
2178             *ptr = dbus_message_iter_get_int32 (iter);
2179             break;
2180           }
2181         case DBUS_TYPE_UINT32:
2182           {
2183             dbus_uint32_t *ptr;
2184
2185             ptr = va_arg (var_args, dbus_uint32_t *);
2186
2187             *ptr = dbus_message_iter_get_uint32 (iter);
2188             break;
2189           }
2190 #ifdef DBUS_HAVE_INT64
2191         case DBUS_TYPE_INT64:
2192           {
2193             dbus_int64_t *ptr;
2194
2195             ptr = va_arg (var_args, dbus_int64_t *);
2196
2197             *ptr = dbus_message_iter_get_int64 (iter);
2198             break;
2199           }
2200         case DBUS_TYPE_UINT64:
2201           {
2202             dbus_uint64_t *ptr;
2203
2204             ptr = va_arg (var_args, dbus_uint64_t *);
2205
2206             *ptr = dbus_message_iter_get_uint64 (iter);
2207             break;
2208           }
2209 #endif /* DBUS_HAVE_INT64 */
2210           
2211         case DBUS_TYPE_DOUBLE:
2212           {
2213             double *ptr;
2214
2215             ptr = va_arg (var_args, double *);
2216
2217             *ptr = dbus_message_iter_get_double (iter);
2218             break;
2219           }
2220
2221         case DBUS_TYPE_STRING:
2222           {
2223             char **ptr;
2224
2225             ptr = va_arg (var_args, char **);
2226
2227             *ptr = dbus_message_iter_get_string (iter);
2228
2229             if (!*ptr)
2230               {
2231                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2232                 goto out;
2233               }
2234             
2235             break;
2236           }
2237
2238         case DBUS_TYPE_CUSTOM:
2239           {
2240             char **name;
2241             unsigned char **data;
2242             int *len;
2243  
2244             name = va_arg (var_args, char **);
2245             data = va_arg (var_args, unsigned char **);
2246             len = va_arg (var_args, int *);
2247
2248             if (!dbus_message_iter_get_custom (iter, name, data, len))
2249               {
2250                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2251                 goto out;
2252               }
2253           }
2254           break;
2255         case DBUS_TYPE_ARRAY:
2256           {
2257             void **data;
2258             int *len, type;
2259  
2260             type = va_arg (var_args, int);
2261             data = va_arg (var_args, void *);
2262             len = va_arg (var_args, int *);
2263
2264             _dbus_return_val_if_fail (data != NULL, FALSE);
2265             _dbus_return_val_if_fail (len != NULL, FALSE);
2266             
2267             if (dbus_message_iter_get_array_type (iter) != type)
2268               {
2269                 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2270                                 "Argument %d is specified to be of type \"array of %s\", but "
2271                                 "is actually of type \"array of %s\"\n", i,
2272                                 _dbus_type_to_string (type),
2273                                 _dbus_type_to_string (dbus_message_iter_get_array_type (iter)));
2274                 goto out;
2275               }
2276             
2277             switch (type)
2278               {
2279               case DBUS_TYPE_BYTE:
2280                 if (!dbus_message_iter_get_byte_array (iter, (unsigned char **)data, len))
2281                   {
2282                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2283                     goto out;
2284                   }
2285                 break;
2286               case DBUS_TYPE_BOOLEAN:
2287                 if (!dbus_message_iter_get_boolean_array (iter, (unsigned char **)data, len))
2288                   {
2289                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2290                     goto out;
2291                   }
2292                 break;
2293               case DBUS_TYPE_INT32:
2294                 if (!dbus_message_iter_get_int32_array (iter, (dbus_int32_t **)data, len))
2295                   {
2296                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2297                     goto out;
2298                   }
2299                 break;
2300               case DBUS_TYPE_UINT32:
2301                 if (!dbus_message_iter_get_uint32_array (iter, (dbus_uint32_t **)data, len))
2302                   {
2303                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2304                     goto out;
2305                   }
2306                 break;
2307 #ifdef DBUS_HAVE_INT64
2308               case DBUS_TYPE_INT64:
2309                 if (!dbus_message_iter_get_int64_array (iter, (dbus_int64_t **)data, len))
2310                   {
2311                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2312                     goto out;
2313                   }
2314                 break;
2315               case DBUS_TYPE_UINT64:
2316                 if (!dbus_message_iter_get_uint64_array (iter, (dbus_uint64_t **)data, len))
2317                   {
2318                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2319                     goto out;
2320                   }
2321                 break;
2322 #endif /* DBUS_HAVE_INT64 */
2323               case DBUS_TYPE_DOUBLE:
2324                 if (!dbus_message_iter_get_double_array (iter, (double **)data, len))
2325                   {
2326                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2327                     goto out;
2328                   }
2329                 break;
2330               case DBUS_TYPE_STRING:
2331                 if (!dbus_message_iter_get_string_array (iter, (char ***)data, len))
2332                   {
2333                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
2334                     goto out;
2335                   }
2336                 break;
2337               case DBUS_TYPE_NIL:
2338               case DBUS_TYPE_ARRAY:
2339               case DBUS_TYPE_CUSTOM:
2340               case DBUS_TYPE_DICT:
2341                 _dbus_warn ("dbus_message_get_args_valist doesn't support recursive arrays\n");
2342                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2343                 goto out;
2344               default:
2345                 _dbus_warn ("Unknown field type %d\n", type);
2346                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2347                 goto out;
2348               }
2349           }
2350           break;
2351         case DBUS_TYPE_DICT:
2352           _dbus_warn ("dbus_message_get_args_valist doesn't support dicts\n");
2353           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2354           goto out;
2355         default:          
2356           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
2357           _dbus_warn ("Unknown field type %d\n", spec_type);
2358           goto out;
2359         }
2360       
2361       spec_type = va_arg (var_args, int);
2362       if (spec_type != 0 && !dbus_message_iter_next (iter))
2363         {
2364           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
2365                           "Message has only %d arguments, but more were expected", i);
2366           goto out;
2367         }
2368
2369       i++;
2370     }
2371   
2372   retval = TRUE;
2373   
2374  out:
2375   
2376   return retval;
2377 }
2378
2379
2380 /**
2381  * Initializes a DBusMessageIter representing the arguments of the
2382  * message passed in.
2383  *
2384  * @param message the message
2385  * @param iter pointer to an iterator to initialize
2386  */
2387 void
2388 dbus_message_iter_init (DBusMessage     *message,
2389                         DBusMessageIter *iter)
2390 {
2391   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2392
2393   _dbus_return_if_fail (message != NULL);
2394   _dbus_return_if_fail (iter != NULL);
2395   
2396   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
2397   
2398   real->message = message;
2399   real->parent_iter = NULL;
2400   real->changed_stamp = message->changed_stamp;
2401   
2402   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
2403   real->pos = 0;
2404   real->end = _dbus_string_get_length (&message->body);
2405   
2406   real->container_start = 0;
2407   real->container_length_pos = 0;
2408   real->wrote_dict_key = 0;
2409   real->array_type_pos = 0;
2410 }
2411
2412 #ifndef DBUS_DISABLE_CHECKS
2413 static dbus_bool_t
2414 dbus_message_iter_check (DBusMessageRealIter *iter)
2415 {
2416   if (iter == NULL)
2417     {
2418       _dbus_warn ("dbus iterator check failed: iterator is NULL\n");
2419       return FALSE;
2420     }
2421   
2422   if (iter->changed_stamp != iter->message->changed_stamp)
2423     {
2424       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message\n");
2425       return FALSE;
2426     }
2427   
2428   if (iter->pos < 0 || iter->pos > iter->end)
2429     {
2430       _dbus_warn ("dbus iterator check failed: invalid position\n");
2431       return FALSE;
2432     }
2433
2434   return TRUE;
2435 }
2436 #endif /* DBUS_DISABLE_CHECKS */
2437
2438 static int
2439 skip_array_type (DBusMessageRealIter *iter, int pos)
2440 {
2441   const char *data;
2442
2443   do
2444     {
2445       data = _dbus_string_get_const_data_len (&iter->message->body,
2446                                               pos++, 1);
2447     }
2448   while (*data == DBUS_TYPE_ARRAY);
2449   
2450   return pos;
2451 }
2452
2453 /* FIXME what are these _dbus_type_is_valid() checks for?
2454  * haven't we validated the message?
2455  */
2456 static int
2457 dbus_message_iter_get_data_start (DBusMessageRealIter *iter, int *type)
2458 {
2459   const char *data;
2460   int pos, len;
2461   
2462   switch (iter->type)
2463     {
2464     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2465       data = _dbus_string_get_const_data_len (&iter->message->body,
2466                                               iter->pos, 1);
2467       if (_dbus_type_is_valid (*data))
2468         *type = *data;
2469       else
2470         *type = DBUS_TYPE_INVALID;
2471       
2472       return skip_array_type (iter, iter->pos);
2473       
2474     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2475       data = _dbus_string_get_const_data_len (&iter->message->body,
2476                                               iter->array_type_pos, 1);
2477       if (_dbus_type_is_valid (*data))
2478         *type = *data;
2479       else
2480         *type = DBUS_TYPE_INVALID;
2481       
2482       return iter->pos;
2483       
2484     case DBUS_MESSAGE_ITER_TYPE_DICT:
2485       /* Get the length of the string */
2486       len = _dbus_demarshal_uint32 (&iter->message->body,
2487                                     iter->message->byte_order,
2488                                     iter->pos, &pos);
2489       pos = pos + len + 1;
2490
2491       data = _dbus_string_get_const_data_len (&iter->message->body,
2492                                               pos, 1);
2493       if (_dbus_type_is_valid (*data))
2494         *type = *data;
2495       else
2496         *type = DBUS_TYPE_INVALID;
2497
2498       return skip_array_type (iter, pos);
2499       
2500     default:
2501       _dbus_assert_not_reached ("Invalid iter type");
2502       break;
2503     }
2504   *type = DBUS_TYPE_INVALID;
2505   return iter->pos;
2506 }
2507
2508
2509 /**
2510  * Checks if an iterator has any more fields.
2511  *
2512  * @param iter the message iter
2513  * @returns #TRUE if there are more fields
2514  * following
2515  */
2516 dbus_bool_t
2517 dbus_message_iter_has_next (DBusMessageIter *iter)
2518 {
2519   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2520   int end_pos;
2521   int type, pos;
2522
2523   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2524
2525   if (real->pos >= real->end)
2526     return FALSE;
2527   
2528   pos = dbus_message_iter_get_data_start (real, &type);
2529   
2530   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
2531                                       real->message->byte_order,
2532                                       type, pos, &end_pos))
2533     return FALSE;
2534   
2535   if (end_pos >= real->end)
2536     return FALSE;
2537
2538   return TRUE;  
2539 }
2540
2541 /**
2542  * Moves the iterator to the next field.
2543  *
2544  * @param iter The message iter
2545  * @returns #TRUE if the iterator was moved to the next field
2546  */
2547 dbus_bool_t
2548 dbus_message_iter_next (DBusMessageIter *iter)
2549 {
2550   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2551   int end_pos;
2552   int type, pos;
2553
2554   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2555
2556   pos = dbus_message_iter_get_data_start (real, &type);
2557   
2558   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
2559                                       real->message->byte_order,
2560                                       type, pos, &end_pos))
2561     return FALSE;
2562
2563   if (end_pos >= real->end)
2564     return FALSE;
2565
2566   real->pos = end_pos;
2567
2568   return TRUE;
2569 }
2570
2571 /**
2572  * Returns the argument type of the argument that the
2573  * message iterator points at.
2574  *
2575  * @param iter the message iter
2576  * @returns the field type
2577  */
2578 int
2579 dbus_message_iter_get_arg_type (DBusMessageIter *iter)
2580 {
2581   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2582   int type, pos;
2583
2584   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
2585
2586   if (real->pos >= real->end)
2587     {
2588       _dbus_verbose ("  iterator at or beyond end of message\n");
2589       return DBUS_TYPE_INVALID;
2590     }
2591
2592   pos = dbus_message_iter_get_data_start (real, &type);
2593   
2594   return type;
2595 }
2596
2597 /* FIXME why do we validate the typecode in here, hasn't the message
2598  * already been verified?
2599  */
2600 static int
2601 iter_get_array_type (DBusMessageRealIter *iter, int *array_type_pos)
2602 {
2603   const char *data;
2604   int _array_type_pos;
2605   int len, pos;
2606   
2607   switch (iter->type)
2608     {
2609     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2610       _array_type_pos = iter->pos + 1;
2611       break;
2612     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2613       _array_type_pos = iter->array_type_pos + 1;
2614       break;
2615     case DBUS_MESSAGE_ITER_TYPE_DICT:
2616       /* Get the length of the string */
2617       len = _dbus_demarshal_uint32 (&iter->message->body,
2618                                     iter->message->byte_order,
2619                                     iter->pos, &pos);
2620       pos = pos + len + 1;
2621       data = _dbus_string_get_const_data_len (&iter->message->body,
2622                                               pos + 1, 1);
2623       _array_type_pos = pos + 1;
2624       break;
2625     default:
2626       _dbus_assert_not_reached ("wrong iter type");
2627       return DBUS_TYPE_INVALID;
2628     }
2629
2630   if (array_type_pos != NULL)
2631     *array_type_pos = _array_type_pos;
2632   
2633   data = _dbus_string_get_const_data_len (&iter->message->body,
2634                                           _array_type_pos, 1);
2635   if (_dbus_type_is_valid (*data))
2636     return  *data;
2637   
2638   return DBUS_TYPE_INVALID;
2639 }
2640
2641
2642 /**
2643  * Returns the element type of the array that the
2644  * message iterator points at. Note that you need
2645  * to check that the iterator points to an array
2646  * prior to using this function.
2647  *
2648  * @param iter the message iter
2649  * @returns the field type
2650  */
2651 int
2652 dbus_message_iter_get_array_type (DBusMessageIter *iter)
2653 {
2654   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2655   int type, pos;
2656
2657   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
2658
2659   if (real->pos >= real->end)
2660     return DBUS_TYPE_INVALID;
2661
2662   pos = dbus_message_iter_get_data_start (real, &type);
2663
2664   _dbus_assert (type == DBUS_TYPE_ARRAY);
2665
2666   return iter_get_array_type (real, NULL);
2667 }
2668
2669
2670 /**
2671  * Returns the string value that an iterator may point to.
2672  * Note that you need to check that the iterator points to
2673  * a string value before using this function.
2674  *
2675  * @see dbus_message_iter_get_arg_type
2676  * @param iter the message iter
2677  * @returns the string
2678  */
2679 char *
2680 dbus_message_iter_get_string (DBusMessageIter *iter)
2681 {
2682   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2683   int type, pos;
2684
2685   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2686
2687   pos = dbus_message_iter_get_data_start (real, &type);
2688   
2689   _dbus_assert (type == DBUS_TYPE_STRING);
2690
2691   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2692                                  pos, NULL);
2693 }
2694
2695 #if 0
2696 /**
2697  * @todo FIXME to finish this _dbus_demarshal_object_path() needs
2698  * to not explode the path.
2699  * 
2700  * Returns the object path value that an iterator may point to.
2701  * Note that you need to check that the iterator points to
2702  * an object path value before using this function.
2703  *
2704  * @see dbus_message_iter_get_arg_type
2705  * @param iter the message iter
2706  * @returns the path
2707  */
2708 char *
2709 dbus_message_iter_get_object_path (DBusMessageIter  *iter)
2710 {
2711   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2712   int type, pos;
2713
2714   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2715
2716   pos = dbus_message_iter_get_data_start (real, &type);
2717   
2718   _dbus_assert (type == DBUS_TYPE_OBJECT_PATH);
2719
2720   return _dbus_demarshal_object_path (&real->message->body, real->message->byte_order,
2721                                       pos, NULL);
2722 }
2723 #endif
2724
2725 /**
2726  * Returns the name and data from a custom type that an iterator may
2727  * point to. Note that you need to check that the iterator points to a
2728  * custom type before using this function.
2729  *
2730  * @see dbus_message_iter_get_arg_type
2731  * @param iter the message iter
2732  * @param name return location for the name of the custom type
2733  * @param value return location for data
2734  * @param len return location for length of data
2735  * @returns TRUE if get succeed
2736  * 
2737  */
2738 dbus_bool_t
2739 dbus_message_iter_get_custom (DBusMessageIter   *iter,
2740                               char             **name,
2741                               unsigned char    **value,
2742                               int               *len)
2743 {
2744   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2745   int type, pos;
2746   char *_name;
2747
2748   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2749
2750   pos = dbus_message_iter_get_data_start (real, &type);
2751   
2752   _dbus_assert (type == DBUS_TYPE_CUSTOM);
2753   
2754   _name = _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2755                                   pos, &pos);
2756
2757   if (_name == NULL)
2758     return FALSE;
2759   
2760   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
2761                                    pos, NULL, value, len))
2762     {
2763       dbus_free (_name);
2764       return FALSE;
2765     }
2766
2767   *name = _name;
2768   
2769   return TRUE;
2770 }
2771
2772 /**
2773  * Returns the byte value that an iterator may point to.
2774  * Note that you need to check that the iterator points to
2775  * a byte value before using this function.
2776  *
2777  * @see dbus_message_iter_get_arg_type
2778  * @param iter the message iter
2779  * @returns the byte value
2780  */
2781 unsigned char
2782 dbus_message_iter_get_byte (DBusMessageIter *iter)
2783 {
2784   unsigned char value;
2785   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2786   int type, pos;
2787
2788   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2789
2790   pos = dbus_message_iter_get_data_start (real, &type);
2791   
2792   _dbus_assert (type == DBUS_TYPE_BYTE);
2793
2794   value = _dbus_string_get_byte (&real->message->body, pos);
2795   
2796   return value;
2797 }
2798
2799
2800 /**
2801  * Returns the boolean value that an iterator may point to.
2802  * Note that you need to check that the iterator points to
2803  * a boolean value before using this function.
2804  *
2805  * @see dbus_message_iter_get_arg_type
2806  * @param iter the message iter
2807  * @returns the boolean value
2808  */
2809 dbus_bool_t
2810 dbus_message_iter_get_boolean (DBusMessageIter *iter)
2811 {
2812   unsigned char value;
2813   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2814   int type, pos;
2815
2816   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2817
2818   pos = dbus_message_iter_get_data_start (real, &type);
2819   
2820   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
2821
2822   value = _dbus_string_get_byte (&real->message->body, pos);
2823   
2824   return value;
2825 }
2826
2827 /**
2828  * Returns the 32 bit signed integer value that an iterator may point to.
2829  * Note that you need to check that the iterator points to
2830  * a 32-bit integer value before using this function.
2831  *
2832  * @see dbus_message_iter_get_arg_type
2833  * @param iter the message iter
2834  * @returns the integer
2835  */
2836 dbus_int32_t
2837 dbus_message_iter_get_int32 (DBusMessageIter *iter)
2838 {
2839   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2840   int type, pos;
2841
2842   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2843
2844   pos = dbus_message_iter_get_data_start (real, &type);
2845   
2846   _dbus_assert (type == DBUS_TYPE_INT32);
2847   
2848   return _dbus_demarshal_int32 (&real->message->body, real->message->byte_order,
2849                                 pos, NULL);
2850 }
2851
2852 /**
2853  * Returns the 32 bit unsigned integer value that an iterator may point to.
2854  * Note that you need to check that the iterator points to
2855  * a 32-bit unsigned integer value before using this function.
2856  *
2857  * @see dbus_message_iter_get_arg_type
2858  * @param iter the message iter
2859  * @returns the integer
2860  */
2861 dbus_uint32_t
2862 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
2863 {
2864   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2865   int type, pos;
2866
2867   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2868
2869   pos = dbus_message_iter_get_data_start (real, &type);
2870   
2871   _dbus_assert (type == DBUS_TYPE_UINT32);
2872   
2873   return _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2874                                  pos, NULL);
2875 }
2876
2877 #ifdef DBUS_HAVE_INT64
2878
2879 /**
2880  * Returns the 64 bit signed integer value that an iterator may point
2881  * to.  Note that you need to check that the iterator points to a
2882  * 64-bit integer value before using this function.
2883  *
2884  * This function only exists if #DBUS_HAVE_INT64 is defined.
2885  *
2886  * @see dbus_message_iter_get_arg_type
2887  * @param iter the message iter
2888  * @returns the integer
2889  */
2890 dbus_int64_t
2891 dbus_message_iter_get_int64 (DBusMessageIter *iter)
2892 {
2893   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2894   int type, pos;
2895
2896   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2897
2898   pos = dbus_message_iter_get_data_start (real, &type);
2899   
2900   _dbus_assert (type == DBUS_TYPE_INT64);
2901   
2902   return _dbus_demarshal_int64 (&real->message->body, real->message->byte_order,
2903                                 pos, NULL);
2904 }
2905
2906 /**
2907  * Returns the 64 bit unsigned integer value that an iterator may point to.
2908  * Note that you need to check that the iterator points to
2909  * a 64-bit unsigned integer value before using this function.
2910  * 
2911  * This function only exists if #DBUS_HAVE_INT64 is defined.
2912  * 
2913  * @see dbus_message_iter_get_arg_type
2914  * @param iter the message iter
2915  * @returns the integer
2916  */
2917 dbus_uint64_t
2918 dbus_message_iter_get_uint64 (DBusMessageIter *iter)
2919 {
2920   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2921   int type, pos;
2922
2923   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2924
2925   pos = dbus_message_iter_get_data_start (real, &type);
2926   
2927   _dbus_assert (type == DBUS_TYPE_UINT64);
2928   
2929   return _dbus_demarshal_uint64 (&real->message->body, real->message->byte_order,
2930                                  pos, NULL);
2931 }
2932
2933 #endif /* DBUS_HAVE_INT64 */
2934
2935 /**
2936  * Returns the double value that an iterator may point to.
2937  * Note that you need to check that the iterator points to
2938  * a string value before using this function.
2939  *
2940  * @see dbus_message_iter_get_arg_type
2941  * @param iter the message iter
2942  * @returns the double
2943  */
2944 double
2945 dbus_message_iter_get_double (DBusMessageIter *iter)
2946 {
2947   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2948   int type, pos;
2949
2950   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0.0);
2951
2952   pos = dbus_message_iter_get_data_start (real, &type);
2953   
2954   _dbus_assert (type == DBUS_TYPE_DOUBLE);
2955   
2956   return _dbus_demarshal_double (&real->message->body, real->message->byte_order,
2957                                  pos, NULL);
2958 }
2959
2960 /**
2961  * Initializes an iterator for the array that the iterator
2962  * may point to. Note that you need to check that the iterator
2963  * points to an array prior to using this function.
2964  *
2965  * The array element type is returned in array_type, and the array
2966  * iterator can only be used to get that type of data.
2967  *
2968  * @param iter the iterator
2969  * @param array_iter pointer to an iterator to initialize
2970  * @param array_type gets set to the type of the array elements
2971  */
2972 void
2973 dbus_message_iter_init_array_iterator (DBusMessageIter *iter,
2974                                        DBusMessageIter *array_iter,
2975                                        int             *array_type)
2976 {
2977   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2978   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
2979   int type, pos, len_pos, len, array_type_pos;
2980   int _array_type;
2981
2982   _dbus_return_if_fail (dbus_message_iter_check (real));
2983
2984   pos = dbus_message_iter_get_data_start (real, &type);
2985   
2986   _dbus_assert (type == DBUS_TYPE_ARRAY);
2987
2988   _array_type = iter_get_array_type (real, &array_type_pos);
2989   
2990   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
2991   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2992                                 pos, &pos);
2993   
2994   array_real->parent_iter = real;
2995   array_real->message = real->message;
2996   array_real->changed_stamp = real->message->changed_stamp;
2997   
2998   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
2999   array_real->pos = pos;
3000   array_real->end = pos + len;
3001   
3002   array_real->container_start = pos;
3003   array_real->container_length_pos = len_pos;
3004   array_real->wrote_dict_key = 0;
3005   array_real->array_type_pos = array_type_pos;
3006   array_real->array_type_done = TRUE;
3007   
3008   if (array_type != NULL)
3009     *array_type = _array_type;
3010 }
3011
3012
3013 /**
3014  * Initializes an iterator for the dict that the iterator
3015  * may point to. Note that you need to check that the iterator
3016  * points to a dict prior to using this function.
3017  *
3018  * @param iter the iterator
3019  * @param dict_iter pointer to an iterator to initialize
3020  */
3021 void
3022 dbus_message_iter_init_dict_iterator (DBusMessageIter *iter,
3023                                       DBusMessageIter *dict_iter)
3024 {
3025   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3026   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
3027   int type, pos, len_pos, len;
3028
3029   _dbus_return_if_fail (dbus_message_iter_check (real));
3030
3031   pos = dbus_message_iter_get_data_start (real, &type);
3032   
3033   _dbus_assert (type == DBUS_TYPE_DICT);
3034
3035   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
3036   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
3037                                 pos, &pos);
3038   
3039   dict_real->parent_iter = real;
3040   dict_real->message = real->message;
3041   dict_real->changed_stamp = real->message->changed_stamp;
3042   
3043   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
3044   dict_real->pos = pos;
3045   dict_real->end = pos + len;
3046   
3047   dict_real->container_start = pos;
3048   dict_real->container_length_pos = len_pos;
3049   dict_real->wrote_dict_key = 0;
3050 }
3051
3052 /**
3053  * Returns the byte array that the iterator may point to.
3054  * Note that you need to check that the iterator points
3055  * to a byte array prior to using this function.
3056  *
3057  * @param iter the iterator
3058  * @param value return location for array values
3059  * @param len return location for length of byte array
3060  * @returns #TRUE on success
3061  */
3062 dbus_bool_t
3063 dbus_message_iter_get_byte_array (DBusMessageIter  *iter,
3064                                   unsigned char   **value,
3065                                   int              *len)
3066 {
3067   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3068   int type, pos;
3069
3070   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3071
3072   pos = dbus_message_iter_get_data_start (real, &type);
3073   
3074   _dbus_assert (type == DBUS_TYPE_ARRAY);
3075
3076   type = iter_get_array_type (real, NULL);
3077
3078   _dbus_assert (type == DBUS_TYPE_BYTE);
3079
3080   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
3081                                    pos, NULL, value, len))
3082     return FALSE;
3083   else
3084     return TRUE;
3085 }
3086
3087 /**
3088  * Returns the boolean array that the iterator may point to. Note that
3089  * you need to check that the iterator points to an array of the
3090  * correct type prior to using this function.
3091  *
3092  * @param iter the iterator
3093  * @param value return location for the array
3094  * @param len return location for the array length
3095  * @returns #TRUE on success
3096  */
3097 dbus_bool_t
3098 dbus_message_iter_get_boolean_array (DBusMessageIter   *iter,
3099                                      unsigned char    **value,
3100                                      int               *len)
3101 {
3102   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3103   int type, pos;
3104
3105   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3106
3107   pos = dbus_message_iter_get_data_start (real, &type);
3108   
3109   _dbus_assert (type == DBUS_TYPE_ARRAY);
3110
3111   type = iter_get_array_type (real, NULL);
3112
3113   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
3114
3115   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
3116                                    pos, NULL, value, len))
3117     return FALSE;
3118   else
3119     return TRUE;
3120 }
3121
3122 /**
3123  * Returns the 32 bit signed integer array that the iterator may point
3124  * to. Note that you need to check that the iterator points to an
3125  * array of the correct type prior to using this function.
3126  *
3127  * @param iter the iterator
3128  * @param value return location for the array
3129  * @param len return location for the array length
3130  * @returns #TRUE on success
3131  */
3132 dbus_bool_t
3133 dbus_message_iter_get_int32_array  (DBusMessageIter *iter,
3134                                     dbus_int32_t   **value,
3135                                     int             *len)
3136 {
3137   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3138   int type, pos;
3139
3140   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3141
3142   pos = dbus_message_iter_get_data_start (real, &type);
3143   
3144   _dbus_assert (type == DBUS_TYPE_ARRAY);
3145
3146   type = iter_get_array_type (real, NULL);
3147   
3148   _dbus_assert (type == DBUS_TYPE_INT32);
3149
3150   if (!_dbus_demarshal_int32_array (&real->message->body, real->message->byte_order,
3151                                     pos, NULL, value, len))
3152     return FALSE;
3153   else
3154     return TRUE;
3155 }
3156
3157 /**
3158  * Returns the 32 bit unsigned integer array that the iterator may point
3159  * to. Note that you need to check that the iterator points to an
3160  * array of the correct type prior to using this function.
3161  *
3162  * @param iter the iterator
3163  * @param value return location for the array
3164  * @param len return location for the array length
3165  * @returns #TRUE on success
3166  */
3167 dbus_bool_t
3168 dbus_message_iter_get_uint32_array  (DBusMessageIter *iter,
3169                                      dbus_uint32_t  **value,
3170                                      int             *len)
3171 {
3172   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3173   int type, pos;
3174
3175   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3176
3177   pos = dbus_message_iter_get_data_start (real, &type);
3178   
3179   _dbus_assert (type == DBUS_TYPE_ARRAY);
3180
3181   type = iter_get_array_type (real, NULL);
3182   _dbus_assert (type == DBUS_TYPE_UINT32);
3183
3184   if (!_dbus_demarshal_uint32_array (&real->message->body, real->message->byte_order,
3185                                     pos, NULL, value, len))
3186     return FALSE;
3187   else
3188     return TRUE;
3189 }
3190
3191 #ifdef DBUS_HAVE_INT64
3192
3193 /**
3194  * Returns the 64 bit signed integer array that the iterator may point
3195  * to. Note that you need to check that the iterator points to an
3196  * array of the correct type prior to using this function.
3197  * 
3198  * This function only exists if #DBUS_HAVE_INT64 is defined.
3199  *
3200  * @param iter the iterator
3201  * @param value return location for the array
3202  * @param len return location for the array length
3203  * @returns #TRUE on success
3204  */
3205 dbus_bool_t
3206 dbus_message_iter_get_int64_array  (DBusMessageIter *iter,
3207                                     dbus_int64_t   **value,
3208                                     int             *len)
3209 {
3210   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3211   int type, pos;
3212
3213   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3214
3215   pos = dbus_message_iter_get_data_start (real, &type);
3216   
3217   _dbus_assert (type == DBUS_TYPE_ARRAY);
3218
3219   type = iter_get_array_type (real, NULL);
3220   
3221   _dbus_assert (type == DBUS_TYPE_INT64);
3222
3223   if (!_dbus_demarshal_int64_array (&real->message->body, real->message->byte_order,
3224                                     pos, NULL, value, len))
3225     return FALSE;
3226   else
3227     return TRUE;
3228 }
3229
3230 /**
3231  * Returns the 64 bit unsigned integer array that the iterator may point
3232  * to. Note that you need to check that the iterator points to an
3233  * array of the correct type prior to using this function.
3234  *
3235  * This function only exists if #DBUS_HAVE_INT64 is defined.
3236  *
3237  * @param iter the iterator
3238  * @param value return location for the array
3239  * @param len return location for the array length
3240  * @returns #TRUE on success
3241  */
3242 dbus_bool_t
3243 dbus_message_iter_get_uint64_array  (DBusMessageIter *iter,
3244                                      dbus_uint64_t  **value,
3245                                      int             *len)
3246 {
3247   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3248   int type, pos;
3249
3250   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3251
3252   pos = dbus_message_iter_get_data_start (real, &type);
3253   
3254   _dbus_assert (type == DBUS_TYPE_ARRAY);
3255
3256   type = iter_get_array_type (real, NULL);
3257   _dbus_assert (type == DBUS_TYPE_UINT64);
3258
3259   if (!_dbus_demarshal_uint64_array (&real->message->body, real->message->byte_order,
3260                                     pos, NULL, value, len))
3261     return FALSE;
3262   else
3263     return TRUE;
3264 }
3265
3266 #endif /* DBUS_HAVE_INT64 */
3267
3268 /**
3269  * Returns the double array that the iterator may point to. Note that
3270  * you need to check that the iterator points to an array of the
3271  * correct type prior to using this function.
3272  *
3273  * @param iter the iterator
3274  * @param value return location for the array
3275  * @param len return location for the array length
3276  * @returns #TRUE on success
3277  */
3278 dbus_bool_t
3279 dbus_message_iter_get_double_array  (DBusMessageIter *iter,
3280                                      double         **value,
3281                                      int             *len)
3282 {
3283   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3284   int type, pos;
3285
3286   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3287
3288   pos = dbus_message_iter_get_data_start (real, &type);
3289   
3290   _dbus_assert (type == DBUS_TYPE_ARRAY);
3291
3292   type = iter_get_array_type (real, NULL);
3293   _dbus_assert (type == DBUS_TYPE_DOUBLE);
3294
3295   if (!_dbus_demarshal_double_array (&real->message->body, real->message->byte_order,
3296                                      pos, NULL, value, len))
3297     return FALSE;
3298   else
3299     return TRUE;
3300 }
3301
3302 /**
3303  * Returns the string array that the iterator may point to.
3304  * Note that you need to check that the iterator points
3305  * to a string array prior to using this function.
3306  *
3307  * The returned value is a #NULL-terminated array of strings.
3308  * Each string is a separate malloc block, and the array
3309  * itself is a malloc block. You can free this type of
3310  * string array with dbus_free_string_array().
3311  *
3312  * @param iter the iterator
3313  * @param value return location for string values
3314  * @param len return location for length of byte array
3315  * @returns #TRUE on success
3316  */
3317 dbus_bool_t
3318 dbus_message_iter_get_string_array (DBusMessageIter *iter,
3319                                     char          ***value,
3320                                     int             *len)
3321 {
3322   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3323   int type, pos;
3324
3325   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3326
3327   pos = dbus_message_iter_get_data_start (real, &type);
3328   
3329   _dbus_assert (type == DBUS_TYPE_ARRAY);
3330
3331   type = iter_get_array_type (real, NULL);
3332   _dbus_assert (type == DBUS_TYPE_STRING);
3333
3334   if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order,
3335                                      pos, NULL, value, len))
3336     return FALSE;
3337   else
3338     return TRUE;
3339 }
3340
3341 #if 0
3342 /**
3343  * @todo FIXME to implement this _dbus_demarshal_object_path_array()
3344  * needs implementing
3345  * 
3346  * Returns the object path array that the iterator may point to.
3347  * Note that you need to check that the iterator points
3348  * to an object path array prior to using this function.
3349  *
3350  * The returned value is a #NULL-terminated array of strings.
3351  * Each string is a separate malloc block, and the array
3352  * itself is a malloc block. You can free this type of
3353  * array with dbus_free_string_array().
3354  *
3355  * @param iter the iterator
3356  * @param value return location for string values
3357  * @param len return location for length of byte array
3358  * @returns #TRUE on success
3359  */
3360 dbus_bool_t
3361 dbus_message_iter_get_object_path_array (DBusMessageIter *iter,
3362                                          char          ***value,
3363                                          int             *len)
3364 {
3365   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3366   int type, pos;
3367
3368   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
3369
3370   pos = dbus_message_iter_get_data_start (real, &type);
3371   
3372   _dbus_assert (type == DBUS_TYPE_ARRAY);
3373
3374   type = iter_get_array_type (real, NULL);
3375   _dbus_assert (type == DBUS_TYPE_OBJECT_PATH);
3376
3377   if (!_dbus_demarshal_object_path_array (&real->message->body, real->message->byte_order,
3378                                           pos, NULL, value, len))
3379     return FALSE;
3380   else
3381     return TRUE;
3382 }
3383 #endif
3384
3385 /**
3386  * Returns the key name fot the dict entry that an iterator
3387  * may point to. Note that you need to check that the iterator
3388  * points to a dict entry before using this function.
3389  *
3390  * @see dbus_message_iter_init_dict_iterator
3391  * @param iter the message iter
3392  * @returns the key name
3393  */
3394 char *
3395 dbus_message_iter_get_dict_key (DBusMessageIter   *iter)
3396 {
3397   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3398
3399   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
3400
3401   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
3402
3403   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
3404                                  real->pos, NULL);
3405 }
3406
3407 /**
3408  * Initializes a DBusMessageIter pointing to the end of the
3409  * message. This iterator can be used to append data to the
3410  * message.
3411  *
3412  * @param message the message
3413  * @param iter pointer to an iterator to initialize
3414  */
3415 void
3416 dbus_message_append_iter_init (DBusMessage     *message,
3417                                DBusMessageIter *iter)
3418 {
3419   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3420
3421   _dbus_return_if_fail (message != NULL);
3422   _dbus_return_if_fail (iter != NULL);
3423   
3424   real->message = message;
3425   real->parent_iter = NULL;
3426   real->changed_stamp = message->changed_stamp;
3427   
3428   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
3429   real->end = _dbus_string_get_length (&real->message->body);
3430   real->pos = real->end;
3431   
3432   real->container_length_pos = 0;
3433   real->wrote_dict_key = 0;
3434 }
3435
3436 #ifndef DBUS_DISABLE_CHECKS
3437 static dbus_bool_t
3438 dbus_message_iter_append_check (DBusMessageRealIter *iter)
3439 {
3440   if (iter == NULL)
3441     {
3442       _dbus_warn ("dbus iterator check failed: NULL iterator\n");
3443       return FALSE;
3444     }
3445   
3446   if (iter->message->locked)
3447     {
3448       _dbus_warn ("dbus iterator check failed: message is locked (has already been sent)\n");
3449       return FALSE;
3450     }
3451       
3452   if (iter->changed_stamp != iter->message->changed_stamp)
3453     {
3454       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message");
3455       return FALSE;
3456     }
3457   
3458   if (iter->pos != iter->end)
3459     {
3460       _dbus_warn ("dbus iterator check failed: can only append at end of message");
3461       return FALSE;
3462     }
3463   
3464   if (iter->pos != _dbus_string_get_length (&iter->message->body))
3465     {
3466       _dbus_warn ("dbus iterator check failed: append pos not at end of message string");
3467       return FALSE;
3468     }
3469
3470   return TRUE;
3471 }
3472 #endif /* DBUS_DISABLE_CHECKS */
3473
3474 static dbus_bool_t
3475 dbus_message_iter_append_type (DBusMessageRealIter *iter,
3476                                int                  type)
3477 {
3478   const char *data;
3479   switch (iter->type)
3480     {
3481     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
3482       if (!_dbus_string_append_byte (&iter->message->signature, type))
3483         return FALSE;
3484       
3485       if (!_dbus_string_append_byte (&iter->message->body, type))
3486         {
3487           _dbus_string_shorten (&iter->message->signature, 1);
3488           return FALSE;
3489         }
3490       break;
3491       
3492     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
3493       data = _dbus_string_get_const_data_len (&iter->message->body,
3494                                               iter->array_type_pos, 1);
3495       if (type != *data)
3496         {
3497           _dbus_warn ("Appended element of wrong type for array\n");
3498           return FALSE;
3499         }
3500       break;
3501       
3502     case DBUS_MESSAGE_ITER_TYPE_DICT:
3503       if (!iter->wrote_dict_key)
3504         {
3505           _dbus_warn ("Appending dict data before key name\n");
3506           return FALSE;
3507         }
3508       
3509       if (!_dbus_string_append_byte (&iter->message->body, type))
3510         return FALSE;
3511       
3512       break;
3513       
3514     default:
3515       _dbus_assert_not_reached ("Invalid iter type");
3516       break;
3517     }
3518   
3519   return TRUE;
3520 }
3521
3522 static void
3523 dbus_message_iter_update_after_change (DBusMessageRealIter *iter)
3524 {
3525   iter->changed_stamp = iter->message->changed_stamp;
3526   
3527   /* Set new end of iter */
3528   iter->end = _dbus_string_get_length (&iter->message->body);
3529   iter->pos = iter->end;
3530
3531   /* Set container length */
3532   if (iter->type == DBUS_MESSAGE_ITER_TYPE_DICT ||
3533       (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY && iter->array_type_done))
3534     _dbus_marshal_set_uint32 (&iter->message->body,
3535                               iter->message->byte_order,
3536                               iter->container_length_pos,
3537                               iter->end - iter->container_start);
3538   
3539   if (iter->parent_iter)
3540     dbus_message_iter_update_after_change (iter->parent_iter);
3541 }
3542
3543 static void
3544 dbus_message_iter_append_done (DBusMessageRealIter *iter)
3545 {
3546   iter->message->changed_stamp++;
3547   dbus_message_iter_update_after_change (iter);
3548   iter->wrote_dict_key = FALSE;
3549 }
3550
3551 /**
3552  * Appends a nil value to the message
3553  *
3554  * @param iter an iterator pointing to the end of the message
3555  * @returns #TRUE on success
3556  */
3557 dbus_bool_t
3558 dbus_message_iter_append_nil (DBusMessageIter *iter)
3559 {
3560   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3561
3562   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3563
3564   if (!dbus_message_iter_append_type (real, DBUS_TYPE_NIL))
3565     return FALSE;
3566   
3567   dbus_message_iter_append_done (real);
3568   
3569   return TRUE;
3570 }
3571
3572 /**
3573  * Appends a boolean value to the message
3574  *
3575  * @param iter an iterator pointing to the end of the message
3576  * @param value the boolean value
3577  * @returns #TRUE on success
3578  */
3579 dbus_bool_t
3580 dbus_message_iter_append_boolean (DBusMessageIter *iter,
3581                                   dbus_bool_t     value)
3582 {
3583   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3584
3585   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3586
3587   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BOOLEAN))
3588     return FALSE;
3589   
3590   if (!_dbus_string_append_byte (&real->message->body, (value != FALSE)))
3591     {
3592       _dbus_string_set_length (&real->message->body, real->pos);
3593       return FALSE;
3594     }
3595
3596   dbus_message_iter_append_done (real);
3597   
3598   return TRUE;
3599 }
3600
3601 /**
3602  * Appends a byte to the message
3603  *
3604  * @param iter an iterator pointing to the end of the message
3605  * @param value the byte value
3606  * @returns #TRUE on success
3607  */
3608 dbus_bool_t
3609 dbus_message_iter_append_byte (DBusMessageIter *iter,
3610                                unsigned char    value)
3611 {
3612   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3613
3614   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3615
3616   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BYTE))
3617     return FALSE;
3618   
3619   if (!_dbus_string_append_byte (&real->message->body, value))
3620     {
3621       _dbus_string_set_length (&real->message->body, real->pos);
3622       return FALSE;
3623     }
3624
3625   dbus_message_iter_append_done (real);
3626   
3627   return TRUE;
3628 }
3629
3630
3631 /**
3632  * Appends a 32 bit signed integer to the message.
3633  *
3634  * @param iter an iterator pointing to the end of the message
3635  * @param value the integer value
3636  * @returns #TRUE on success
3637  */
3638 dbus_bool_t
3639 dbus_message_iter_append_int32   (DBusMessageIter *iter,
3640                                   dbus_int32_t  value)
3641 {
3642   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3643
3644   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3645
3646   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT32))
3647     return FALSE;
3648   
3649   if (!_dbus_marshal_int32 (&real->message->body, real->message->byte_order, value))
3650     {
3651       _dbus_string_set_length (&real->message->body, real->pos);
3652       return FALSE;
3653     }
3654
3655   dbus_message_iter_append_done (real);
3656   
3657   return TRUE;
3658 }
3659
3660 /**
3661  * Appends a 32 bit unsigned integer to the message.
3662  *
3663  * @param iter an iterator pointing to the end of the message
3664  * @param value the integer value
3665  * @returns #TRUE on success
3666  */
3667 dbus_bool_t
3668 dbus_message_iter_append_uint32 (DBusMessageIter *iter,
3669                                  dbus_uint32_t    value)
3670 {
3671   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3672
3673   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3674
3675   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT32))
3676     return FALSE;
3677   
3678   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, value))
3679     {
3680       _dbus_string_set_length (&real->message->body, real->pos);
3681       return FALSE;
3682     }
3683
3684   dbus_message_iter_append_done (real);
3685   
3686   return TRUE;
3687 }
3688
3689 #ifdef DBUS_HAVE_INT64
3690
3691 /**
3692  * Appends a 64 bit signed integer to the message.
3693  *
3694  * This function only exists if #DBUS_HAVE_INT64 is defined.
3695  *
3696  * @param iter an iterator pointing to the end of the message
3697  * @param value the integer value
3698  * @returns #TRUE on success
3699  */
3700 dbus_bool_t
3701 dbus_message_iter_append_int64   (DBusMessageIter *iter,
3702                                   dbus_int64_t  value)
3703 {
3704   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3705
3706   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3707
3708   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT64))
3709     return FALSE;
3710   
3711   if (!_dbus_marshal_int64 (&real->message->body, real->message->byte_order, value))
3712     {
3713       _dbus_string_set_length (&real->message->body, real->pos);
3714       return FALSE;
3715     }
3716
3717   dbus_message_iter_append_done (real);
3718   
3719   return TRUE;
3720 }
3721
3722 /**
3723  * Appends a 64 bit unsigned integer to the message.
3724  *
3725  * This function only exists if #DBUS_HAVE_INT64 is defined.
3726  *
3727  * @param iter an iterator pointing to the end of the message
3728  * @param value the integer value
3729  * @returns #TRUE on success
3730  */
3731 dbus_bool_t
3732 dbus_message_iter_append_uint64 (DBusMessageIter *iter,
3733                                  dbus_uint64_t    value)
3734 {
3735   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3736
3737   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3738
3739   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT64))
3740     return FALSE;
3741   
3742   if (!_dbus_marshal_uint64 (&real->message->body, real->message->byte_order, value))
3743     {
3744       _dbus_string_set_length (&real->message->body, real->pos);
3745       return FALSE;
3746     }
3747
3748   dbus_message_iter_append_done (real);
3749   
3750   return TRUE;
3751 }
3752
3753 #endif /* DBUS_HAVE_INT64 */
3754
3755 /**
3756  * Appends a double value to the message.
3757  *
3758  * @param iter an iterator pointing to the end of the message
3759  * @param value the double value
3760  * @returns #TRUE on success
3761  */
3762 dbus_bool_t
3763 dbus_message_iter_append_double (DBusMessageIter *iter,
3764                                  double           value)
3765 {
3766   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3767
3768   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3769
3770   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DOUBLE))
3771     return FALSE;
3772   
3773   if (!_dbus_marshal_double (&real->message->body, real->message->byte_order, value))
3774     {
3775       _dbus_string_set_length (&real->message->body, real->pos);
3776       return FALSE;
3777     }
3778
3779   dbus_message_iter_append_done (real);
3780   
3781   return TRUE;
3782 }
3783
3784 /**
3785  * Appends a UTF-8 string to the message.
3786  *
3787  * @todo add return_val_if_fail(UTF-8 is valid)
3788  *
3789  * @param iter an iterator pointing to the end of the message
3790  * @param value the string
3791  * @returns #TRUE on success
3792  */
3793 dbus_bool_t
3794 dbus_message_iter_append_string (DBusMessageIter *iter,
3795                                  const char      *value)
3796 {
3797   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3798
3799   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3800   
3801   if (!dbus_message_iter_append_type (real, DBUS_TYPE_STRING))
3802     return FALSE;
3803   
3804   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3805     {
3806       _dbus_string_set_length (&real->message->body, real->pos);
3807       return FALSE;
3808     }
3809
3810   dbus_message_iter_append_done (real);
3811   
3812   return TRUE;
3813 }
3814
3815 /**
3816  * Appends a custom type data chunk to the message. A custom
3817  * type is simply an arbitrary UTF-8 string used as a type
3818  * tag, plus an array of arbitrary bytes to be interpreted
3819  * according to the type tag.
3820  *
3821  * @param iter an iterator pointing to the end of the message
3822  * @param name the name of the type
3823  * @param data the binary data used to store the value
3824  * @param len the length of the binary data in bytes
3825  * @returns #TRUE on success
3826  */
3827 dbus_bool_t
3828 dbus_message_iter_append_custom (DBusMessageIter      *iter,
3829                                  const char           *name,
3830                                  const unsigned char  *data,
3831                                  int                   len)
3832 {
3833   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3834
3835   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3836
3837   if (!dbus_message_iter_append_type (real, DBUS_TYPE_CUSTOM))
3838     return FALSE;
3839   
3840    if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, name))
3841     {
3842       _dbus_string_set_length (&real->message->body, real->pos);
3843       return FALSE;
3844     }
3845    
3846   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, data, len))
3847     {
3848       _dbus_string_set_length (&real->message->body, real->pos);
3849       return FALSE;
3850     }
3851
3852   dbus_message_iter_append_done (real);
3853   
3854   return TRUE;
3855 }
3856
3857
3858 /**
3859  * Appends a dict key name to the message. The iterator used
3860  * must point to a dict.
3861  *
3862  * @param iter an iterator pointing to the end of the message
3863  * @param value the string
3864  * @returns #TRUE on success
3865  */
3866 dbus_bool_t
3867 dbus_message_iter_append_dict_key (DBusMessageIter *iter,
3868                                    const char      *value)
3869 {
3870   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3871
3872   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3873   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
3874   
3875   if (real->wrote_dict_key)
3876     {
3877       _dbus_warn ("Appending multiple dict key names\n");
3878       return FALSE;
3879     }
3880   
3881   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3882     {
3883       return FALSE;
3884     }
3885
3886   dbus_message_iter_append_done (real);
3887   real->wrote_dict_key = TRUE;
3888   
3889   return TRUE;
3890 }
3891
3892 static dbus_bool_t
3893 array_iter_type_mark_done (DBusMessageRealIter *iter)
3894 {
3895   int len_pos;
3896   
3897   if (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY)
3898     array_iter_type_mark_done (iter->parent_iter);
3899   else
3900     return TRUE;
3901
3902   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&iter->message->body),
3903                                sizeof (dbus_uint32_t));
3904
3905   /* Empty length for now, backfill later */
3906   if (!_dbus_marshal_uint32 (&iter->message->body, iter->message->byte_order, 0))
3907     {
3908       _dbus_string_set_length (&iter->message->body, iter->pos);
3909       return FALSE;
3910     }
3911
3912   iter->container_start = _dbus_string_get_length (&iter->message->body);
3913   iter->container_length_pos = len_pos;
3914   iter->array_type_done = TRUE;
3915
3916   return TRUE;
3917 }
3918
3919 static dbus_bool_t
3920 append_array_type (DBusMessageRealIter *real,
3921                    int                  element_type,
3922                    dbus_bool_t         *array_type_done,
3923                    int                 *array_type_pos)
3924 {
3925   int existing_element_type;
3926   
3927   if (!dbus_message_iter_append_type (real, DBUS_TYPE_ARRAY))
3928     return FALSE;
3929   
3930   if (real->type == DBUS_MESSAGE_ITER_TYPE_ARRAY &&
3931       real->array_type_done)
3932     {
3933       existing_element_type = iter_get_array_type (real, array_type_pos);
3934       if (existing_element_type != element_type)
3935         {
3936           _dbus_warn ("Appending array of %s, when expecting array of %s\n",
3937                       _dbus_type_to_string (element_type),
3938                       _dbus_type_to_string (existing_element_type));
3939           _dbus_string_set_length (&real->message->body, real->pos);
3940           return FALSE;
3941         }
3942       if (array_type_done != NULL)
3943           *array_type_done = TRUE;
3944     }
3945   else
3946     {
3947       if (array_type_pos != NULL)
3948         *array_type_pos = _dbus_string_get_length (&real->message->body);
3949
3950
3951       if (!_dbus_string_append_byte (&real->message->signature, element_type))
3952         {
3953           _dbus_string_set_length (&real->message->body, real->pos);
3954           return FALSE;
3955         }
3956       
3957       /* Append element type */
3958       if (!_dbus_string_append_byte (&real->message->body, element_type))
3959         {
3960           _dbus_string_shorten (&real->message->signature, 1);
3961           _dbus_string_set_length (&real->message->body, real->pos);
3962           return FALSE;
3963         }
3964
3965       if (array_type_done != NULL)
3966         *array_type_done = element_type != DBUS_TYPE_ARRAY;
3967       
3968       if (element_type != DBUS_TYPE_ARRAY &&
3969           !array_iter_type_mark_done (real))
3970         {
3971           _dbus_string_shorten (&real->message->signature, 1);
3972           return FALSE;
3973         }        
3974     }
3975
3976   return TRUE;
3977 }
3978
3979 /**
3980  * Appends an array to the message and initializes an iterator that
3981  * can be used to append to the array.
3982  *
3983  * @param iter an iterator pointing to the end of the message
3984  * @param array_iter pointer to an iter that will be initialized
3985  * @param element_type the type of the array elements
3986  * @returns #TRUE on success
3987  */
3988 dbus_bool_t
3989 dbus_message_iter_append_array (DBusMessageIter      *iter,
3990                                 DBusMessageIter      *array_iter,
3991                                 int                   element_type)
3992 {
3993   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3994   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
3995   int len_pos;
3996   int array_type_pos;
3997   dbus_bool_t array_type_done;
3998
3999   if (element_type == DBUS_TYPE_NIL)
4000     {
4001       _dbus_warn ("Can't create NIL arrays\n");
4002       return FALSE;
4003     }
4004   
4005   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4006
4007   if (!append_array_type (real, element_type, &array_type_done, &array_type_pos))
4008     return FALSE;
4009
4010   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
4011
4012   if (array_type_done)
4013     {
4014       /* Empty length for now, backfill later */
4015       if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
4016         {
4017           _dbus_string_set_length (&real->message->body, real->pos);
4018           return FALSE;
4019         }
4020     }
4021   
4022   array_real->parent_iter = real;
4023   array_real->message = real->message;
4024   array_real->changed_stamp = real->message->changed_stamp;
4025   
4026   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
4027   array_real->pos = _dbus_string_get_length (&real->message->body);
4028   array_real->end = array_real->end;
4029   
4030   array_real->container_start = array_real->pos;
4031   array_real->container_length_pos = len_pos;
4032   array_real->wrote_dict_key = 0;
4033   array_real->array_type_done = array_type_done;
4034   array_real->array_type_pos = array_type_pos;
4035
4036   dbus_message_iter_append_done (array_real);
4037   
4038   return TRUE;
4039 }
4040
4041 /**
4042  * Appends a dict to the message and initializes an iterator that
4043  * can be used to append to the dict.
4044  *
4045  * @param iter an iterator pointing to the end of the message
4046  * @param dict_iter pointer to an iter that will be initialized
4047  * @returns #TRUE on success
4048  */
4049 dbus_bool_t
4050 dbus_message_iter_append_dict (DBusMessageIter      *iter,
4051                                DBusMessageIter      *dict_iter)
4052 {
4053   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4054   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
4055   int len_pos;
4056
4057   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4058   
4059   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DICT))
4060     return FALSE;  
4061   
4062   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
4063
4064   /* Empty length for now, backfill later */
4065   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
4066     {
4067       _dbus_string_set_length (&real->message->body, real->pos);
4068       return FALSE;
4069     }
4070   
4071   dict_real->parent_iter = real;
4072   dict_real->message = real->message;
4073   dict_real->changed_stamp = real->message->changed_stamp;
4074   
4075   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
4076   dict_real->pos = _dbus_string_get_length (&real->message->body);
4077   dict_real->end = dict_real->end;
4078   
4079   dict_real->container_start = dict_real->pos;
4080   dict_real->container_length_pos = len_pos;
4081   dict_real->wrote_dict_key = 0;
4082
4083   dbus_message_iter_append_done (dict_real);
4084   
4085   real->wrote_dict_key = FALSE;
4086   
4087   return TRUE;
4088 }
4089
4090
4091 /**
4092  * Appends a boolean array to the message.
4093  *
4094  * @param iter an iterator pointing to the end of the message
4095  * @param value the array
4096  * @param len the length of the array
4097  * @returns #TRUE on success
4098  */
4099 dbus_bool_t
4100 dbus_message_iter_append_boolean_array (DBusMessageIter     *iter,
4101                                         unsigned const char *value,
4102                                         int                  len)
4103 {
4104   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4105
4106   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4107
4108   if (!append_array_type (real, DBUS_TYPE_BOOLEAN, NULL, NULL))
4109     return FALSE;
4110   
4111   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
4112     {
4113       _dbus_string_set_length (&real->message->body, real->pos);
4114       return FALSE;
4115     }
4116
4117   dbus_message_iter_append_done (real);
4118   
4119   return TRUE;
4120 }
4121
4122 /**
4123  * Appends a 32 bit signed integer array to the message.
4124  *
4125  * @param iter an iterator pointing to the end of the message
4126  * @param value the array
4127  * @param len the length of the array
4128  * @returns #TRUE on success
4129  */
4130 dbus_bool_t
4131 dbus_message_iter_append_int32_array (DBusMessageIter    *iter,
4132                                       const dbus_int32_t *value,
4133                                       int                 len)
4134 {
4135   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4136
4137   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4138
4139   if (!append_array_type (real, DBUS_TYPE_INT32, NULL, NULL))
4140     return FALSE;
4141   
4142   if (!_dbus_marshal_int32_array (&real->message->body, real->message->byte_order, value, len))
4143     {
4144       _dbus_string_set_length (&real->message->body, real->pos);
4145       return FALSE;
4146     }
4147
4148   dbus_message_iter_append_done (real);
4149   
4150   return TRUE;
4151 }
4152
4153 /**
4154  * Appends a 32 bit unsigned integer array to the message.
4155  *
4156  * @param iter an iterator pointing to the end of the message
4157  * @param value the array
4158  * @param len the length of the array
4159  * @returns #TRUE on success
4160  */
4161 dbus_bool_t
4162 dbus_message_iter_append_uint32_array (DBusMessageIter     *iter,
4163                                        const dbus_uint32_t *value,
4164                                        int                  len)
4165 {
4166   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4167
4168   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4169
4170   if (!append_array_type (real, DBUS_TYPE_UINT32, NULL, NULL))
4171     return FALSE;
4172   
4173   if (!_dbus_marshal_uint32_array (&real->message->body, real->message->byte_order, value, len))
4174     {
4175       _dbus_string_set_length (&real->message->body, real->pos);
4176       return FALSE;
4177     }
4178
4179   dbus_message_iter_append_done (real);
4180   
4181   return TRUE;
4182 }
4183
4184 #ifdef DBUS_HAVE_INT64
4185
4186 /**
4187  * Appends a 64 bit signed integer array to the message.
4188  *
4189  * This function only exists if #DBUS_HAVE_INT64 is defined.
4190  *
4191  * @param iter an iterator pointing to the end of the message
4192  * @param value the array
4193  * @param len the length of the array
4194  * @returns #TRUE on success
4195  */
4196 dbus_bool_t
4197 dbus_message_iter_append_int64_array (DBusMessageIter    *iter,
4198                                       const dbus_int64_t *value,
4199                                       int                 len)
4200 {
4201   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4202
4203   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4204
4205   if (!append_array_type (real, DBUS_TYPE_INT64, NULL, NULL))
4206     return FALSE;
4207   
4208   if (!_dbus_marshal_int64_array (&real->message->body, real->message->byte_order, value, len))
4209     {
4210       _dbus_string_set_length (&real->message->body, real->pos);
4211       return FALSE;
4212     }
4213
4214   dbus_message_iter_append_done (real);
4215   
4216   return TRUE;
4217 }
4218
4219 /**
4220  * Appends a 64 bit unsigned integer array to the message.
4221  *
4222  * This function only exists if #DBUS_HAVE_INT64 is defined.
4223  *
4224  * @param iter an iterator pointing to the end of the message
4225  * @param value the array
4226  * @param len the length of the array
4227  * @returns #TRUE on success
4228  */
4229 dbus_bool_t
4230 dbus_message_iter_append_uint64_array (DBusMessageIter     *iter,
4231                                        const dbus_uint64_t *value,
4232                                        int                  len)
4233 {
4234   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4235
4236   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4237
4238   if (!append_array_type (real, DBUS_TYPE_UINT64, NULL, NULL))
4239     return FALSE;
4240   
4241   if (!_dbus_marshal_uint64_array (&real->message->body, real->message->byte_order, value, len))
4242     {
4243       _dbus_string_set_length (&real->message->body, real->pos);
4244       return FALSE;
4245     }
4246
4247   dbus_message_iter_append_done (real);
4248   
4249   return TRUE;
4250 }
4251 #endif /* DBUS_HAVE_INT64 */
4252
4253 /**
4254  * Appends a double array to the message.
4255  *
4256  * @param iter an iterator pointing to the end of the message
4257  * @param value the array
4258  * @param len the length of the array
4259  * @returns #TRUE on success
4260  */
4261 dbus_bool_t
4262 dbus_message_iter_append_double_array (DBusMessageIter *iter,
4263                                        const double    *value,
4264                                        int              len)
4265 {
4266   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4267
4268   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4269
4270   if (!append_array_type (real, DBUS_TYPE_DOUBLE, NULL, NULL))
4271     return FALSE;
4272   
4273   if (!_dbus_marshal_double_array (&real->message->body, real->message->byte_order, value, len))
4274     {
4275       _dbus_string_set_length (&real->message->body, real->pos);
4276       return FALSE;
4277     }
4278
4279   dbus_message_iter_append_done (real);
4280   
4281   return TRUE;
4282 }
4283
4284 /**
4285  * Appends a byte array to the message.
4286  *
4287  * @param iter an iterator pointing to the end of the message
4288  * @param value the array
4289  * @param len the length of the array
4290  * @returns #TRUE on success
4291  */
4292 dbus_bool_t
4293 dbus_message_iter_append_byte_array (DBusMessageIter     *iter,
4294                                      unsigned const char *value,
4295                                      int                  len)
4296 {
4297   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4298
4299   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4300
4301   if (!append_array_type (real, DBUS_TYPE_BYTE, NULL, NULL))
4302     return FALSE;
4303   
4304   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
4305     {
4306       _dbus_string_set_length (&real->message->body, real->pos);
4307       return FALSE;
4308     }
4309
4310   dbus_message_iter_append_done (real);
4311   
4312   return TRUE;
4313 }
4314
4315 /**
4316  * Appends a string array to the message.
4317  *
4318  * @param iter an iterator pointing to the end of the message
4319  * @param value the array
4320  * @param len the length of the array
4321  * @returns #TRUE on success
4322  */
4323 dbus_bool_t
4324 dbus_message_iter_append_string_array (DBusMessageIter *iter,
4325                                        const char     **value,
4326                                        int              len)
4327 {
4328   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
4329
4330   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
4331
4332   if (!append_array_type (real, DBUS_TYPE_STRING, NULL, NULL))
4333     return FALSE;
4334   
4335   if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len))
4336     {
4337       _dbus_string_set_length (&real->message->body, real->pos);
4338       return FALSE;
4339     }
4340
4341   dbus_message_iter_append_done (real);
4342   
4343   return TRUE;
4344 }
4345
4346 /**
4347  * Sets the message sender.
4348  *
4349  * @param message the message
4350  * @param sender the sender
4351  * @returns #FALSE if not enough memory
4352  */
4353 dbus_bool_t
4354 dbus_message_set_sender (DBusMessage  *message,
4355                          const char   *sender)
4356 {
4357   _dbus_return_val_if_fail (message != NULL, FALSE);
4358   _dbus_return_val_if_fail (!message->locked, FALSE);
4359
4360   return set_string_field (message,
4361                            DBUS_HEADER_FIELD_SENDER_SERVICE,
4362                            DBUS_TYPE_STRING,
4363                            sender);
4364 }
4365
4366 /**
4367  * Sets a flag indicating that the message does not want a reply; if
4368  * this flag is set, the other end of the connection may (but is not
4369  * required to) optimize by not sending method return or error
4370  * replies. If this flag is set, there is no way to know whether the
4371  * message successfully arrived at the remote end.
4372  *
4373  * @param message the message
4374  * @param no_reply #TRUE if no reply is desired
4375  */
4376 void
4377 dbus_message_set_no_reply (DBusMessage *message,
4378                            dbus_bool_t  no_reply)
4379 {
4380   char *header;
4381
4382   _dbus_return_if_fail (message != NULL);
4383   _dbus_return_if_fail (!message->locked);
4384   
4385   header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1);
4386   
4387   if (no_reply)
4388     *header |= DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;
4389   else
4390     *header &= ~DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;    
4391 }
4392
4393 /**
4394  * Returns #TRUE if the message does not expect
4395  * a reply.
4396  *
4397  * @param message the message
4398  * @returns #TRUE if the message sender isn't waiting for a reply
4399  */
4400 dbus_bool_t
4401 dbus_message_get_no_reply (DBusMessage *message)
4402 {
4403   const char *header;
4404
4405   _dbus_return_val_if_fail (message != NULL, FALSE);
4406   
4407   header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1);
4408
4409   return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0;
4410 }
4411
4412 /**
4413  * Gets the service which originated this message,
4414  * or #NULL if unknown or inapplicable.
4415  *
4416  * @param message the message
4417  * @returns the service name or #NULL
4418  */
4419 const char*
4420 dbus_message_get_sender (DBusMessage *message)
4421 {
4422   _dbus_return_val_if_fail (message != NULL, NULL);
4423   
4424   return get_string_field (message, 
4425                            DBUS_HEADER_FIELD_SENDER_SERVICE,
4426                            NULL);
4427 }
4428
4429 /**
4430  * Gets the type signature of the message, i.e. the arguments in the
4431  * message payload. The signature includes only "in" arguments for
4432  * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for
4433  * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from
4434  * what you might expect (it does not include the signature of the
4435  * entire C++-style method).
4436  *
4437  * The signature is a string made up of type codes such
4438  * as #DBUS_TYPE_STRING. The string is terminated with nul
4439  * (nul is also the value of #DBUS_TYPE_INVALID).
4440  * 
4441  * @param message the message
4442  * @returns the type signature
4443  */
4444 const char*
4445 dbus_message_get_signature (DBusMessage *message)
4446 {
4447   _dbus_return_val_if_fail (message != NULL, NULL);
4448   
4449   return _dbus_string_get_const_data (&message->signature);
4450 }
4451
4452 static dbus_bool_t
4453 _dbus_message_has_type_interface_member (DBusMessage *message,
4454                                          int          type,
4455                                          const char  *interface,
4456                                          const char  *method)
4457 {
4458   const char *n;
4459
4460   _dbus_assert (message != NULL);
4461   _dbus_assert (interface != NULL);
4462   _dbus_assert (method != NULL);
4463
4464   if (dbus_message_get_type (message) != type)
4465     return FALSE;
4466
4467   /* Optimize by checking the short method name first
4468    * instead of the longer interface name
4469    */  
4470
4471   n = dbus_message_get_member (message);
4472
4473   if (n && strcmp (n, method) == 0)
4474     {
4475       n = dbus_message_get_interface (message);
4476       
4477       if (n && strcmp (n, interface) == 0)
4478         return TRUE;
4479     }
4480
4481   return FALSE;
4482 }
4483
4484 /**
4485  * Checks whether the message is a method call with the given
4486  * interface and member fields.  If the message is not
4487  * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or member field,
4488  * returns #FALSE.
4489  *
4490  * @param message the message
4491  * @param interface the name to check (must not be #NULL)
4492  * @param method the name to check (must not be #NULL)
4493  * 
4494  * @returns #TRUE if the message is the specified method call
4495  */
4496 dbus_bool_t
4497 dbus_message_is_method_call (DBusMessage *message,
4498                              const char  *interface,
4499                              const char  *method)
4500 {
4501   _dbus_return_val_if_fail (message != NULL, FALSE);
4502   _dbus_return_val_if_fail (interface != NULL, FALSE);
4503   _dbus_return_val_if_fail (method != NULL, FALSE);
4504
4505   return _dbus_message_has_type_interface_member (message,
4506                                                   DBUS_MESSAGE_TYPE_METHOD_CALL,
4507                                                   interface, method);
4508 }
4509
4510 /**
4511  * Checks whether the message is a signal with the given
4512  * interface and member fields.  If the message is not
4513  * #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field,
4514  * returns #FALSE.
4515  *
4516  * @param message the message
4517  * @param interface the name to check (must not be #NULL)
4518  * @param signal_name the name to check (must not be #NULL)
4519  * 
4520  * @returns #TRUE if the message is the specified signal
4521  */
4522 dbus_bool_t
4523 dbus_message_is_signal (DBusMessage *message,
4524                         const char  *interface,
4525                         const char  *signal_name)
4526 {
4527   _dbus_return_val_if_fail (message != NULL, FALSE);
4528   _dbus_return_val_if_fail (interface != NULL, FALSE);
4529   _dbus_return_val_if_fail (signal_name != NULL, FALSE);
4530
4531   return _dbus_message_has_type_interface_member (message,
4532                                                   DBUS_MESSAGE_TYPE_SIGNAL,
4533                                                   interface, signal_name);
4534 }
4535
4536 /**
4537  * Checks whether the message is an error reply with the given error
4538  * name.  If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a
4539  * different name, returns #FALSE.
4540  *
4541  * @param message the message
4542  * @param error_name the name to check (must not be #NULL)
4543  * 
4544  * @returns #TRUE if the message is the specified error
4545  */
4546 dbus_bool_t
4547 dbus_message_is_error (DBusMessage *message,
4548                         const char  *error_name)
4549 {
4550   const char *n;
4551   
4552   _dbus_return_val_if_fail (message != NULL, FALSE);
4553   _dbus_return_val_if_fail (error_name != NULL, FALSE);
4554
4555   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
4556     return FALSE;
4557
4558   n = dbus_message_get_error_name (message);
4559
4560   if (n && strcmp (n, error_name) == 0)
4561     return TRUE;
4562   else
4563     return FALSE;
4564 }
4565
4566 /**
4567  * Checks whether the message was sent to the given service.  If the
4568  * message has no service specified or has a different name, returns
4569  * #FALSE.
4570  *
4571  * @param message the message
4572  * @param service the service to check (must not be #NULL)
4573  * 
4574  * @returns #TRUE if the message has the given destination service
4575  */
4576 dbus_bool_t
4577 dbus_message_has_destination (DBusMessage  *message,
4578                               const char   *service)
4579 {
4580   const char *s;
4581
4582   _dbus_return_val_if_fail (message != NULL, FALSE);
4583   _dbus_return_val_if_fail (service != NULL, FALSE);
4584   
4585   s = dbus_message_get_destination (message);
4586
4587   if (s && strcmp (s, service) == 0)
4588     return TRUE;
4589   else
4590     return FALSE;
4591 }
4592
4593 /**
4594  * Checks whether the message has the given service as its sender.  If
4595  * the message has no sender specified or has a different sender,
4596  * returns #FALSE. Note that if a peer application owns multiple
4597  * services, its messages will have only one of those services as the
4598  * sender (usually the base service). So you can't use this
4599  * function to prove the sender didn't own service Foo, you can
4600  * only use it to prove that it did.
4601  *
4602  * @param message the message
4603  * @param service the service to check (must not be #NULL)
4604  * 
4605  * @returns #TRUE if the message has the given origin service
4606  */
4607 dbus_bool_t
4608 dbus_message_has_sender (DBusMessage  *message,
4609                          const char   *service)
4610 {
4611   const char *s;
4612
4613   _dbus_return_val_if_fail (message != NULL, FALSE);
4614   _dbus_return_val_if_fail (service != NULL, FALSE);
4615   
4616   s = dbus_message_get_sender (message);
4617
4618   if (s && strcmp (s, service) == 0)
4619     return TRUE;
4620   else
4621     return FALSE;
4622 }
4623
4624 /**
4625  * Checks whether the message has the given signature;
4626  * see dbus_message_get_signature() for more details on
4627  * what the signature looks like.
4628  *
4629  * @param message the message
4630  * @param signature typecode array
4631  * @returns #TRUE if message has the given signature
4632 */
4633 dbus_bool_t
4634 dbus_message_has_signature (DBusMessage   *message,
4635                             const char    *signature)
4636 {
4637   _dbus_return_val_if_fail (message != NULL, FALSE);
4638   _dbus_return_val_if_fail (signature != NULL, FALSE);
4639
4640   return _dbus_string_equal_c_str (&message->signature, signature);
4641 }
4642
4643 /**
4644  * Sets a #DBusError based on the contents of the given
4645  * message. The error is only set if the message
4646  * is an error message, as in DBUS_MESSAGE_TYPE_ERROR.
4647  * The name of the error is set to the name of the message,
4648  * and the error message is set to the first argument
4649  * if the argument exists and is a string.
4650  *
4651  * The return value indicates whether the error was set (the error is
4652  * set if and only if the message is an error message).
4653  * So you can check for an error reply and convert it to DBusError
4654  * in one go.
4655  *
4656  * @param error the error to set
4657  * @param message the message to set it from
4658  * @returns #TRUE if dbus_message_get_is_error() returns #TRUE for the message
4659  */
4660 dbus_bool_t
4661 dbus_set_error_from_message (DBusError   *error,
4662                              DBusMessage *message)
4663 {
4664   char *str;
4665
4666   _dbus_return_val_if_fail (message != NULL, FALSE);
4667   _dbus_return_val_if_error_is_set (error, FALSE);
4668   
4669   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
4670     return FALSE;
4671
4672   str = NULL;
4673   dbus_message_get_args (message, NULL,
4674                          DBUS_TYPE_STRING, &str,
4675                          DBUS_TYPE_INVALID);
4676
4677   dbus_set_error (error, dbus_message_get_error_name (message),
4678                   str ? "%s" : NULL, str);
4679
4680   dbus_free (str);
4681   
4682   return TRUE;
4683 }
4684
4685 /** @} */
4686
4687 /**
4688  * @addtogroup DBusMessageInternals
4689  *
4690  * @{
4691  */
4692 /**
4693  * @typedef DBusMessageLoader
4694  *
4695  * The DBusMessageLoader object encapsulates the process of converting
4696  * a byte stream into a series of DBusMessage. It buffers the incoming
4697  * bytes as efficiently as possible, and generates a queue of
4698  * messages. DBusMessageLoader is typically used as part of a
4699  * DBusTransport implementation. The DBusTransport then hands off
4700  * the loaded messages to a DBusConnection, making the messages
4701  * visible to the application.
4702  *
4703  * @todo write tests for break-loader that a) randomly delete header
4704  * fields and b) set string fields to zero-length and other funky
4705  * values.
4706  * 
4707  */
4708
4709 /* we definitely use signed ints for sizes, so don't exceed
4710  * _DBUS_INT_MAX; and add 16 for paranoia, since a message
4711  * over 128M is pretty nuts anyhow.
4712  */
4713
4714 /**
4715  * The maximum sane message size.
4716  */
4717 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
4718
4719 /**
4720  * Implementation details of DBusMessageLoader.
4721  * All members are private.
4722  */
4723 struct DBusMessageLoader
4724 {
4725   int refcount;        /**< Reference count. */
4726
4727   DBusString data;     /**< Buffered data */
4728   
4729   DBusList *messages;  /**< Complete messages. */
4730
4731   long max_message_size; /**< Maximum size of a message */
4732   
4733   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
4734
4735   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
4736 };
4737
4738 /**
4739  * The initial buffer size of the message loader.
4740  * 
4741  * @todo this should be based on min header size plus some average
4742  * body size, or something. Or rather, the min header size only, if we
4743  * want to try to read only the header, store that in a DBusMessage,
4744  * then read only the body and store that, etc., depends on
4745  * how we optimize _dbus_message_loader_get_buffer() and what
4746  * the exact message format is.
4747  */
4748 #define INITIAL_LOADER_DATA_LEN 32
4749
4750 /**
4751  * Creates a new message loader. Returns #NULL if memory can't
4752  * be allocated.
4753  *
4754  * @returns new loader, or #NULL.
4755  */
4756 DBusMessageLoader*
4757 _dbus_message_loader_new (void)
4758 {
4759   DBusMessageLoader *loader;
4760
4761   loader = dbus_new0 (DBusMessageLoader, 1);
4762   if (loader == NULL)
4763     return NULL;
4764   
4765   loader->refcount = 1;
4766
4767   /* Try to cap message size at something that won't *totally* hose
4768    * the system if we have a couple of them.
4769    */
4770   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
4771   
4772   if (!_dbus_string_init (&loader->data))
4773     {
4774       dbus_free (loader);
4775       return NULL;
4776     }
4777
4778   /* preallocate the buffer for speed, ignore failure */
4779   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
4780   _dbus_string_set_length (&loader->data, 0);
4781   
4782   return loader;
4783 }
4784
4785 /**
4786  * Increments the reference count of the loader.
4787  *
4788  * @param loader the loader.
4789  * @returns the loader
4790  */
4791 DBusMessageLoader *
4792 _dbus_message_loader_ref (DBusMessageLoader *loader)
4793 {
4794   loader->refcount += 1;
4795
4796   return loader;
4797 }
4798
4799 /**
4800  * Decrements the reference count of the loader and finalizes the
4801  * loader when the count reaches zero.
4802  *
4803  * @param loader the loader.
4804  */
4805 void
4806 _dbus_message_loader_unref (DBusMessageLoader *loader)
4807 {
4808   loader->refcount -= 1;
4809   if (loader->refcount == 0)
4810     {
4811       _dbus_list_foreach (&loader->messages,
4812                           (DBusForeachFunction) dbus_message_unref,
4813                           NULL);
4814       _dbus_list_clear (&loader->messages);
4815       _dbus_string_free (&loader->data);
4816       dbus_free (loader);
4817     }
4818 }
4819
4820 /**
4821  * Gets the buffer to use for reading data from the network.  Network
4822  * data is read directly into an allocated buffer, which is then used
4823  * in the DBusMessage, to avoid as many extra memcpy's as possible.
4824  * The buffer must always be returned immediately using
4825  * _dbus_message_loader_return_buffer(), even if no bytes are
4826  * successfully read.
4827  *
4828  * @todo this function can be a lot more clever. For example
4829  * it can probably always return a buffer size to read exactly
4830  * the body of the next message, thus avoiding any memory wastage
4831  * or reallocs.
4832  *
4833  * @todo we need to enforce a max length on strings in header fields.
4834  * 
4835  * @param loader the message loader.
4836  * @param buffer the buffer
4837  */
4838 void
4839 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
4840                                  DBusString        **buffer)
4841 {
4842   _dbus_assert (!loader->buffer_outstanding);
4843
4844   *buffer = &loader->data;
4845   
4846   loader->buffer_outstanding = TRUE;
4847 }
4848
4849 /**
4850  * The smallest header size that can occur. 
4851  * (It won't be valid)
4852  */
4853 #define DBUS_MINIMUM_HEADER_SIZE 16
4854
4855 static dbus_bool_t
4856 decode_string_field (const DBusString   *data,
4857                      int                 field,
4858                      HeaderField        *header_field,
4859                      DBusString         *field_data,
4860                      int                 pos,
4861                      int                 type)
4862 {
4863   int string_data_pos;
4864
4865   _dbus_assert (header_field != NULL);
4866   _dbus_assert (field_data != NULL);
4867   
4868   if (header_field->name_offset >= 0)
4869     {
4870       _dbus_verbose ("%s field provided twice\n",
4871                      _dbus_header_field_to_string (field));
4872       return FALSE;
4873     }
4874
4875   if (type != DBUS_TYPE_STRING)
4876     {
4877       _dbus_verbose ("%s field has wrong type %s\n",
4878                      _dbus_header_field_to_string (field),
4879                      _dbus_type_to_string (type));
4880       return FALSE;
4881     }
4882
4883   /* skip padding after typecode, skip string length;
4884    * we assume that the string arg has already been validated
4885    * for sanity and UTF-8
4886    */
4887   string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
4888   _dbus_assert (string_data_pos < _dbus_string_get_length (data));
4889   
4890   _dbus_string_init_const (field_data,
4891                            _dbus_string_get_const_data (data) + string_data_pos);
4892
4893   header_field->name_offset  = pos;
4894   header_field->value_offset = _DBUS_ALIGN_VALUE (pos, 4);
4895   
4896 #if 0
4897   _dbus_verbose ("Found field %s at offset %d\n",
4898                  _dbus_header_field_to_string (field),
4899                  header_field->value_offset);
4900 #endif
4901
4902   return TRUE;
4903 }
4904
4905 /* FIXME because the service/interface/member/error names are already
4906  * validated to be in the particular ASCII subset, UTF-8 validating
4907  * them could be skipped as a probably-interesting optimization.
4908  * The UTF-8 validation definitely shows up in profiles.
4909  */
4910 static dbus_bool_t
4911 decode_header_data (const DBusString   *data,
4912                     int                 header_len,
4913                     int                 byte_order,
4914                     int                 message_type,
4915                     HeaderField         fields[DBUS_HEADER_FIELD_LAST + 1],
4916                     int                *message_padding)
4917 {
4918   DBusString field_data;
4919   int pos, new_pos;
4920   int i;
4921   int field;
4922   int type;
4923   
4924   if (header_len < 16)
4925     {
4926       _dbus_verbose ("Header length %d is too short\n", header_len);
4927       return FALSE;
4928     }
4929   
4930   i = 0;
4931   while (i <= DBUS_HEADER_FIELD_LAST)
4932     {
4933       fields[i].name_offset  = -1;
4934       fields[i].value_offset = -1;
4935       ++i;
4936     }
4937   
4938   pos = 16;
4939   while (pos < header_len)
4940     {
4941       field = _dbus_string_get_byte (data, pos);
4942       if (field == DBUS_HEADER_FIELD_INVALID)
4943         break; /* Must be padding */
4944       pos++;
4945
4946       if (!_dbus_marshal_validate_type (data, pos, &type, &pos))
4947         {
4948           _dbus_verbose ("Failed to validate type of named header field pos = %d\n",
4949                          pos);
4950           return FALSE;
4951         }
4952       
4953       if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos))
4954         {
4955           _dbus_verbose ("Failed to validate argument to named header field pos = %d\n",
4956                          pos);
4957           return FALSE;
4958         }
4959
4960       if (new_pos > header_len)
4961         {
4962           _dbus_verbose ("Named header field tries to extend beyond header length\n");
4963           return FALSE;
4964         }
4965       
4966       switch (field)
4967         {
4968         case DBUS_HEADER_FIELD_SERVICE:
4969           if (!decode_string_field (data, field, &fields[field],
4970                                     &field_data, pos, type))
4971             return FALSE;
4972
4973           if (!_dbus_string_validate_service (&field_data, 0,
4974                                               _dbus_string_get_length (&field_data)))
4975             {
4976               _dbus_verbose ("service field has invalid content \"%s\"\n",
4977                              _dbus_string_get_const_data (&field_data));
4978               return FALSE;
4979             }
4980           break;
4981
4982         case DBUS_HEADER_FIELD_INTERFACE:
4983           if (!decode_string_field (data, field, &fields[field],
4984                                     &field_data, pos, type))
4985             return FALSE;
4986
4987           if (!_dbus_string_validate_interface (&field_data, 0,
4988                                                 _dbus_string_get_length (&field_data)))
4989             {
4990               _dbus_verbose ("interface field has invalid content \"%s\"\n",
4991                              _dbus_string_get_const_data (&field_data));
4992               return FALSE;
4993             }
4994       
4995           if (_dbus_string_equal_c_str (&field_data,
4996                                         DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL))
4997             {
4998               _dbus_verbose ("Message is on the local interface\n");
4999               return FALSE;
5000             }
5001           break;
5002
5003         case DBUS_HEADER_FIELD_MEMBER:
5004           if (!decode_string_field (data, field, &fields[field],
5005                                     &field_data, pos, type))
5006             return FALSE;
5007           
5008           if (!_dbus_string_validate_member (&field_data, 0,
5009                                              _dbus_string_get_length (&field_data)))
5010             {
5011               _dbus_verbose ("member field has invalid content \"%s\"\n",
5012                              _dbus_string_get_const_data (&field_data));
5013               return FALSE;
5014             }
5015           break;
5016
5017         case DBUS_HEADER_FIELD_ERROR_NAME:
5018           if (!decode_string_field (data, field, &fields[field],
5019                                     &field_data, pos, type))
5020             return FALSE;
5021           
5022           if (!_dbus_string_validate_error_name (&field_data, 0,
5023                                                  _dbus_string_get_length (&field_data)))
5024             {
5025               _dbus_verbose ("error-name field has invalid content \"%s\"\n",
5026                              _dbus_string_get_const_data (&field_data));
5027               return FALSE;
5028             }
5029           break;
5030           
5031         case DBUS_HEADER_FIELD_SENDER_SERVICE:
5032           if (!decode_string_field (data, field, &fields[field],
5033                                     &field_data, pos, type))
5034             return FALSE;
5035           
5036           if (!_dbus_string_validate_service (&field_data, 0,
5037                                               _dbus_string_get_length (&field_data)))
5038             {
5039               _dbus_verbose ("sender-service field has invalid content \"%s\"\n",
5040                              _dbus_string_get_const_data (&field_data));
5041               return FALSE;
5042             }
5043           break;
5044
5045         case DBUS_HEADER_FIELD_PATH:
5046
5047           /* Path was already validated as part of standard
5048            * type validation, since there's an OBJECT_PATH
5049            * type.
5050            */
5051           
5052           if (fields[field].name_offset >= 0)
5053             {
5054               _dbus_verbose ("path field provided twice\n");
5055               return FALSE;
5056             }
5057           if (type != DBUS_TYPE_OBJECT_PATH)
5058             {
5059               _dbus_verbose ("path field has wrong type\n");
5060               return FALSE;
5061             }
5062
5063           fields[field].name_offset  = pos;
5064           fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
5065
5066           /* No forging signals from the local path */
5067           {
5068             const char *s;
5069             s = _dbus_string_get_const_data_len (data,
5070                                                  fields[field].value_offset,
5071                                                  _dbus_string_get_length (data) -
5072                                                  fields[field].value_offset);
5073             if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0)
5074               {
5075                 _dbus_verbose ("Message is on the local path\n");
5076                 return FALSE;
5077               }
5078           }
5079           
5080           _dbus_verbose ("Found path at offset %d\n",
5081                          fields[field].value_offset);
5082           break;
5083           
5084         case DBUS_HEADER_FIELD_REPLY_SERIAL:
5085           if (fields[field].name_offset >= 0)
5086             {
5087               _dbus_verbose ("reply field provided twice\n");
5088               return FALSE;
5089             }
5090
5091           if (type != DBUS_TYPE_UINT32)
5092             {
5093               _dbus_verbose ("reply field has wrong type\n");
5094               return FALSE;
5095             }
5096           
5097           fields[field].name_offset  = pos;
5098           fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
5099
5100           _dbus_verbose ("Found reply serial %u at offset %d\n",
5101                          _dbus_demarshal_uint32 (data,
5102                                                  byte_order,
5103                                                  fields[field].value_offset,
5104                                                  NULL),
5105                          fields[field].value_offset);
5106           break;
5107
5108         default:
5109           _dbus_verbose ("Ignoring an unknown header field: %d at offset %d\n",
5110                          field, pos);
5111         }
5112       
5113       pos = new_pos;
5114     }
5115
5116   if (pos < header_len)
5117     {
5118       /* Alignment padding, verify that it's nul */
5119       if ((header_len - pos) >= 8)
5120         {
5121           _dbus_verbose ("too much header alignment padding\n");
5122           return FALSE;
5123         }
5124
5125       if (!_dbus_string_validate_nul (data,
5126                                       pos, (header_len - pos)))
5127         {
5128           _dbus_verbose ("header alignment padding is not nul\n");
5129           return FALSE;
5130         }
5131     }
5132
5133   /* Depending on message type, enforce presence of certain fields. */
5134   switch (message_type)
5135     {
5136     case DBUS_MESSAGE_TYPE_SIGNAL:
5137     case DBUS_MESSAGE_TYPE_METHOD_CALL:
5138       if (fields[DBUS_HEADER_FIELD_PATH].value_offset < 0)
5139         {
5140           _dbus_verbose ("No path field provided\n");
5141           return FALSE;
5142         }
5143       /* FIXME make this optional, only for method calls */
5144       if (fields[DBUS_HEADER_FIELD_INTERFACE].value_offset < 0)
5145         {
5146           _dbus_verbose ("No interface field provided\n");
5147           return FALSE;
5148         }
5149       if (fields[DBUS_HEADER_FIELD_MEMBER].value_offset < 0)
5150         {
5151           _dbus_verbose ("No member field provided\n");
5152           return FALSE;
5153         }
5154       break;
5155     case DBUS_MESSAGE_TYPE_ERROR:
5156       if (fields[DBUS_HEADER_FIELD_ERROR_NAME].value_offset < 0)
5157         {
5158           _dbus_verbose ("No error-name field provided\n");
5159           return FALSE;
5160         }
5161       if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0)
5162         {
5163           _dbus_verbose ("No reply serial field provided in error\n");
5164           return FALSE;
5165         }
5166       break;
5167     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
5168       if (fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset < 0)
5169         {
5170           _dbus_verbose ("No reply serial field provided in method return\n");
5171           return FALSE;
5172         }
5173       break;
5174     default:
5175       /* An unknown type, spec requires us to ignore it */
5176       break;
5177     }
5178   
5179   if (message_padding)
5180     *message_padding = header_len - pos;  
5181   
5182   return TRUE;
5183 }
5184
5185 /**
5186  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
5187  * indicating to the loader how many bytes of the buffer were filled
5188  * in. This function must always be called, even if no bytes were
5189  * successfully read.
5190  *
5191  * @param loader the loader.
5192  * @param buffer the buffer.
5193  * @param bytes_read number of bytes that were read into the buffer.
5194  */
5195 void
5196 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
5197                                     DBusString         *buffer,
5198                                     int                 bytes_read)
5199 {
5200   _dbus_assert (loader->buffer_outstanding);
5201   _dbus_assert (buffer == &loader->data);
5202
5203   loader->buffer_outstanding = FALSE;
5204 }
5205
5206 static dbus_bool_t
5207 load_one_message (DBusMessageLoader *loader,
5208                   int                byte_order,
5209                   int                message_type,
5210                   int                header_len,
5211                   int                body_len)
5212 {
5213   DBusMessage *message;
5214   HeaderField fields[DBUS_HEADER_FIELD_LAST + 1];
5215   int i;
5216   int next_arg;
5217   dbus_bool_t oom;
5218   int header_padding;
5219   
5220   message = NULL;
5221   oom = FALSE;
5222   
5223 #if 0
5224   _dbus_verbose_bytes_of_string (&loader->data, 0, header_len /* + body_len */);
5225 #endif    
5226
5227   if (!decode_header_data (&loader->data,
5228                            header_len, byte_order,
5229                            message_type,
5230                            fields, &header_padding))
5231     {
5232       _dbus_verbose ("Header was invalid\n");
5233       loader->corrupted = TRUE;
5234       goto failed;
5235     }
5236           
5237   next_arg = header_len;
5238   while (next_arg < (header_len + body_len))
5239     {
5240       int type;
5241       int prev = next_arg;
5242
5243       if (!_dbus_marshal_validate_type (&loader->data, next_arg,
5244                                         &type, &next_arg))
5245         {
5246           _dbus_verbose ("invalid typecode at offset %d\n", prev);
5247           loader->corrupted = TRUE;
5248           goto failed;
5249         }
5250       
5251       if (!_dbus_marshal_validate_arg (&loader->data,
5252                                        byte_order,
5253                                        0,
5254                                        type, -1,
5255                                        next_arg,
5256                                        &next_arg))
5257         {
5258           _dbus_verbose ("invalid type data at %d, next_arg\n", next_arg);
5259           loader->corrupted = TRUE;
5260           goto failed;
5261         }
5262
5263       _dbus_assert (next_arg > prev);
5264     }
5265           
5266   if (next_arg > (header_len + body_len))
5267     {
5268       _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
5269                      next_arg, header_len, body_len,
5270                      header_len + body_len);
5271       loader->corrupted = TRUE;
5272       goto failed;
5273     }
5274
5275   message = dbus_message_new_empty_header ();
5276   if (message == NULL)
5277     {
5278       _dbus_verbose ("Failed to allocate empty message\n");
5279       oom = TRUE;
5280       goto failed;
5281     }
5282
5283   message->byte_order = byte_order;
5284   message->header_padding = header_padding;
5285           
5286   /* Copy in the offsets we found */
5287   i = 0;
5288   while (i <= DBUS_HEADER_FIELD_LAST)
5289     {
5290       message->header_fields[i] = fields[i];
5291       ++i;
5292     }
5293           
5294   if (!_dbus_list_append (&loader->messages, message))
5295     {
5296       _dbus_verbose ("Failed to append new message to loader queue\n");
5297       oom = TRUE;
5298       goto failed;
5299     }
5300
5301   _dbus_assert (_dbus_string_get_length (&message->header) == 0);
5302   _dbus_assert (_dbus_string_get_length (&message->body) == 0);
5303
5304   _dbus_assert (_dbus_string_get_length (&loader->data) >=
5305                 (header_len + body_len));
5306           
5307   if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
5308     {
5309       _dbus_verbose ("Failed to move header into new message\n");
5310       oom = TRUE;
5311       goto failed;
5312     }
5313           
5314   if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
5315     {
5316       _dbus_verbose ("Failed to move body into new message\n");
5317       
5318       oom = TRUE;
5319       goto failed;
5320     }
5321
5322   _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
5323   _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
5324
5325   /* Fill in caches (we checked the types of these fields
5326    * earlier)
5327    */
5328   message->reply_serial = get_uint_field (message,
5329                                           DBUS_HEADER_FIELD_REPLY_SERIAL);
5330   
5331   message->client_serial = _dbus_demarshal_uint32 (&message->header,
5332                                                    message->byte_order,
5333                                                    CLIENT_SERIAL_OFFSET,
5334                                                    NULL);
5335   if (message->client_serial == 0 ||
5336       (message->header_fields[DBUS_HEADER_FIELD_REPLY_SERIAL].value_offset >= 0 && message->reply_serial == 0))
5337     {
5338       _dbus_verbose ("client_serial = %d reply_serial = %d, one of these no good\n",
5339                      message->client_serial,
5340                      message->reply_serial);
5341       
5342       loader->corrupted = TRUE;
5343       goto failed;
5344     }
5345           
5346   /* Fill in signature (FIXME should do this during validation,
5347    * but I didn't want to spend time on it since we want to change
5348    * the wire format to contain the signature anyway)
5349    */
5350   {
5351     DBusMessageIter iter;
5352
5353     dbus_message_iter_init (message, &iter);
5354
5355     do
5356       {
5357         int t;
5358
5359         t = dbus_message_iter_get_arg_type (&iter);
5360         if (t == DBUS_TYPE_INVALID)
5361           break;
5362
5363         if (!_dbus_string_append_byte (&message->signature,
5364                                        t))
5365           {
5366             _dbus_verbose ("failed to append type byte to signature\n");
5367             oom = TRUE;
5368             goto failed;
5369           }
5370
5371         if (t == DBUS_TYPE_ARRAY)
5372           {
5373             DBusMessageIter child_iter;
5374             int array_type = t;
5375
5376             child_iter = iter;
5377                     
5378             while (array_type == DBUS_TYPE_ARRAY)
5379               {
5380                 DBusMessageIter parent_iter = child_iter;
5381                 dbus_message_iter_init_array_iterator (&parent_iter,
5382                                                        &child_iter,
5383                                                        &array_type);
5384                                             
5385                 if (!_dbus_string_append_byte (&message->signature,
5386                                                array_type))
5387                   {
5388                     _dbus_verbose ("failed to append array type byte to signature\n");
5389
5390                     oom = TRUE;
5391                     goto failed;
5392                   }
5393               }
5394           }
5395       }
5396     while (dbus_message_iter_next (&iter));
5397   }
5398           
5399   _dbus_verbose ("Loaded message %p\n", message);
5400
5401   _dbus_assert (!oom);
5402   _dbus_assert (!loader->corrupted);
5403
5404   return TRUE;
5405
5406  failed:
5407   
5408   /* Clean up */
5409   
5410   if (message != NULL)
5411     {
5412       /* Put the data back so we can try again later if it was an OOM issue */
5413       if (_dbus_string_get_length (&message->body) > 0)
5414         {
5415           dbus_bool_t result;
5416           
5417           result = _dbus_string_copy_len (&message->body, 0, body_len,
5418                                           &loader->data, 0);
5419           
5420           _dbus_assert (result); /* because DBusString never reallocs smaller */
5421         }
5422       
5423       if (_dbus_string_get_length (&message->header) > 0)
5424         {
5425           dbus_bool_t result;
5426           
5427           result = _dbus_string_copy_len (&message->header, 0, header_len,
5428                                           &loader->data, 0);
5429           
5430           _dbus_assert (result); /* because DBusString never reallocs smaller */
5431         }
5432
5433       /* does nothing if the message isn't in the list */
5434       _dbus_list_remove_last (&loader->messages, message);
5435
5436       dbus_message_unref (message);
5437     }
5438
5439   
5440   return !oom;
5441 }
5442
5443 /**
5444  * Converts buffered data into messages.
5445  *
5446  * @todo we need to check that the proper named header fields exist
5447  * for each message type.
5448  * 
5449  * @todo If a message has unknown type, we should probably eat it
5450  * right here rather than passing it out to applications.  However
5451  * it's not an error to see messages of unknown type.
5452  * 
5453  * @param loader the loader.
5454  * @returns #TRUE if we had enough memory to finish.
5455  */
5456 dbus_bool_t
5457 _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
5458 {
5459   while (!loader->corrupted && _dbus_string_get_length (&loader->data) >= 16)
5460     {
5461       const char *header_data;
5462       int byte_order, message_type, header_len, body_len;
5463       dbus_uint32_t header_len_unsigned, body_len_unsigned;
5464       
5465       header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16);
5466
5467       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
5468
5469       if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION)
5470         {
5471           _dbus_verbose ("Message has protocol version %d ours is %d\n",
5472                          (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION);
5473           loader->corrupted = TRUE;
5474           return TRUE;
5475         }
5476       
5477       byte_order = header_data[BYTE_ORDER_OFFSET];
5478
5479       if (byte_order != DBUS_LITTLE_ENDIAN &&
5480           byte_order != DBUS_BIG_ENDIAN)
5481         {
5482           _dbus_verbose ("Message with bad byte order '%c' received\n",
5483                          byte_order);
5484           loader->corrupted = TRUE;
5485           return TRUE;
5486         }
5487
5488       /* Unknown types are ignored, but INVALID is
5489        * disallowed
5490        */
5491       message_type = header_data[TYPE_OFFSET];
5492       if (message_type == DBUS_MESSAGE_TYPE_INVALID)
5493         {
5494           _dbus_verbose ("Message with bad type '%d' received\n",
5495                          message_type);
5496           loader->corrupted = TRUE;
5497           return TRUE;
5498         }      
5499       
5500       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
5501       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
5502
5503       if (header_len_unsigned < 16)
5504         {
5505           _dbus_verbose ("Message had broken too-small header length %u\n",
5506                          header_len_unsigned);
5507           loader->corrupted = TRUE;
5508           return TRUE;
5509         }
5510
5511       if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE ||
5512           body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE)
5513         {
5514           _dbus_verbose ("Header or body length too large (%u %u)\n",
5515                          header_len_unsigned,
5516                          body_len_unsigned);
5517           loader->corrupted = TRUE;
5518           return TRUE;
5519         }
5520
5521       /* Now that we know the values are in signed range, get
5522        * rid of stupid unsigned, just causes bugs
5523        */
5524       header_len = header_len_unsigned;
5525       body_len = body_len_unsigned;
5526
5527       if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned)
5528         {
5529           
5530           _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
5531                          header_len);
5532           loader->corrupted = TRUE;
5533           return TRUE;
5534         }
5535       
5536       if (header_len + body_len > loader->max_message_size)
5537         {
5538           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %ld\n",
5539                          header_len, body_len, loader->max_message_size);
5540           loader->corrupted = TRUE;
5541           return TRUE;
5542         }
5543
5544       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
5545         {
5546           if (!load_one_message (loader, byte_order, message_type,
5547                                  header_len, body_len))
5548             return FALSE;
5549         }
5550       else
5551         return TRUE;
5552     }
5553
5554   return TRUE;
5555 }
5556
5557 /**
5558  * Peeks at first loaded message, returns #NULL if no messages have
5559  * been queued.
5560  *
5561  * @param loader the loader.
5562  * @returns the next message, or #NULL if none.
5563  */
5564 DBusMessage*
5565 _dbus_message_loader_peek_message (DBusMessageLoader *loader)
5566 {
5567   if (loader->messages)
5568     return loader->messages->data;
5569   else
5570     return NULL;
5571 }
5572
5573 /**
5574  * Pops a loaded message (passing ownership of the message
5575  * to the caller). Returns #NULL if no messages have been
5576  * queued.
5577  *
5578  * @param loader the loader.
5579  * @returns the next message, or #NULL if none.
5580  */
5581 DBusMessage*
5582 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
5583 {
5584   return _dbus_list_pop_first (&loader->messages);
5585 }
5586
5587 /**
5588  * Pops a loaded message inside a list link (passing ownership of the
5589  * message and link to the caller). Returns #NULL if no messages have
5590  * been loaded.
5591  *
5592  * @param loader the loader.
5593  * @returns the next message link, or #NULL if none.
5594  */
5595 DBusList*
5596 _dbus_message_loader_pop_message_link (DBusMessageLoader *loader)
5597 {
5598   return _dbus_list_pop_first_link (&loader->messages);
5599 }
5600
5601 /**
5602  * Returns a popped message link, used to undo a pop.
5603  *
5604  * @param loader the loader
5605  * @param link the link with a message in it
5606  */
5607 void
5608 _dbus_message_loader_putback_message_link (DBusMessageLoader  *loader,
5609                                            DBusList           *link)
5610 {
5611   _dbus_list_prepend_link (&loader->messages, link);
5612 }
5613
5614 /**
5615  * Checks whether the loader is confused due to bad data.
5616  * If messages are received that are invalid, the
5617  * loader gets confused and gives up permanently.
5618  * This state is called "corrupted."
5619  *
5620  * @param loader the loader
5621  * @returns #TRUE if the loader is hosed.
5622  */
5623 dbus_bool_t
5624 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
5625 {
5626   return loader->corrupted;
5627 }
5628
5629 /**
5630  * Sets the maximum size message we allow.
5631  *
5632  * @param loader the loader
5633  * @param size the max message size in bytes
5634  */
5635 void
5636 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
5637                                            long                size)
5638 {
5639   if (size > MAX_SANE_MESSAGE_SIZE)
5640     {
5641       _dbus_verbose ("clamping requested max message size %ld to %d\n",
5642                      size, MAX_SANE_MESSAGE_SIZE);
5643       size = MAX_SANE_MESSAGE_SIZE;
5644     }
5645   loader->max_message_size = size;
5646 }
5647
5648 /**
5649  * Gets the maximum allowed message size in bytes.
5650  *
5651  * @param loader the loader
5652  * @returns max size in bytes
5653  */
5654 long
5655 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
5656 {
5657   return loader->max_message_size;
5658 }
5659
5660 static DBusDataSlotAllocator slot_allocator;
5661 _DBUS_DEFINE_GLOBAL_LOCK (message_slots);
5662
5663 /**
5664  * Allocates an integer ID to be used for storing application-specific
5665  * data on any DBusMessage. The allocated ID may then be used
5666  * with dbus_message_set_data() and dbus_message_get_data().
5667  * The passed-in slot must be initialized to -1, and is filled in
5668  * with the slot ID. If the passed-in slot is not -1, it's assumed
5669  * to be already allocated, and its refcount is incremented.
5670  * 
5671  * The allocated slot is global, i.e. all DBusMessage objects will
5672  * have a slot with the given integer ID reserved.
5673  *
5674  * @param slot_p address of a global variable storing the slot
5675  * @returns #FALSE on failure (no memory)
5676  */
5677 dbus_bool_t
5678 dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
5679 {
5680   return _dbus_data_slot_allocator_alloc (&slot_allocator,
5681                                           _DBUS_LOCK_NAME (message_slots),
5682                                           slot_p);
5683 }
5684
5685 /**
5686  * Deallocates a global ID for message data slots.
5687  * dbus_message_get_data() and dbus_message_set_data() may no
5688  * longer be used with this slot.  Existing data stored on existing
5689  * DBusMessage objects will be freed when the message is
5690  * finalized, but may not be retrieved (and may only be replaced if
5691  * someone else reallocates the slot).  When the refcount on the
5692  * passed-in slot reaches 0, it is set to -1.
5693  *
5694  * @param slot_p address storing the slot to deallocate
5695  */
5696 void
5697 dbus_message_free_data_slot (dbus_int32_t *slot_p)
5698 {
5699   _dbus_return_if_fail (*slot_p >= 0);
5700   
5701   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
5702 }
5703
5704 /**
5705  * Stores a pointer on a DBusMessage, along
5706  * with an optional function to be used for freeing
5707  * the data when the data is set again, or when
5708  * the message is finalized. The slot number
5709  * must have been allocated with dbus_message_allocate_data_slot().
5710  *
5711  * @param message the message
5712  * @param slot the slot number
5713  * @param data the data to store
5714  * @param free_data_func finalizer function for the data
5715  * @returns #TRUE if there was enough memory to store the data
5716  */
5717 dbus_bool_t
5718 dbus_message_set_data (DBusMessage     *message,
5719                        dbus_int32_t     slot,
5720                        void            *data,
5721                        DBusFreeFunction free_data_func)
5722 {
5723   DBusFreeFunction old_free_func;
5724   void *old_data;
5725   dbus_bool_t retval;
5726
5727   _dbus_return_val_if_fail (message != NULL, FALSE);
5728   _dbus_return_val_if_fail (slot >= 0, FALSE);
5729
5730   retval = _dbus_data_slot_list_set (&slot_allocator,
5731                                      &message->slot_list,
5732                                      slot, data, free_data_func,
5733                                      &old_free_func, &old_data);
5734
5735   if (retval)
5736     {
5737       /* Do the actual free outside the message lock */
5738       if (old_free_func)
5739         (* old_free_func) (old_data);
5740     }
5741
5742   return retval;
5743 }
5744
5745 /**
5746  * Retrieves data previously set with dbus_message_set_data().
5747  * The slot must still be allocated (must not have been freed).
5748  *
5749  * @param message the message
5750  * @param slot the slot to get data from
5751  * @returns the data, or #NULL if not found
5752  */
5753 void*
5754 dbus_message_get_data (DBusMessage   *message,
5755                        dbus_int32_t   slot)
5756 {
5757   void *res;
5758
5759   _dbus_return_val_if_fail (message != NULL, NULL);
5760   
5761   res = _dbus_data_slot_list_get (&slot_allocator,
5762                                   &message->slot_list,
5763                                   slot);
5764
5765   return res;
5766 }
5767
5768 /**
5769  * Utility function to convert a machine-readable (not translated)
5770  * string into a D-BUS message type.
5771  *
5772  * @code
5773  *   "method_call"    -> DBUS_MESSAGE_TYPE_METHOD_CALL
5774  *   "method_return"  -> DBUS_MESSAGE_TYPE_METHOD_RETURN
5775  *   "signal"         -> DBUS_MESSAGE_TYPE_SIGNAL
5776  *   "error"          -> DBUS_MESSAGE_TYPE_ERROR
5777  *   anything else    -> DBUS_MESSAGE_TYPE_INVALID
5778  * @endcode
5779  * 
5780  */
5781 int
5782 dbus_message_type_from_string (const char *type_str)
5783 {
5784   if (strcmp (type_str, "method_call") == 0)
5785     return DBUS_MESSAGE_TYPE_METHOD_CALL;
5786   if (strcmp (type_str, "method_return") == 0)
5787     return DBUS_MESSAGE_TYPE_METHOD_RETURN;
5788   else if (strcmp (type_str, "signal") == 0)
5789     return DBUS_MESSAGE_TYPE_SIGNAL;
5790   else if (strcmp (type_str, "error") == 0)
5791     return DBUS_MESSAGE_TYPE_ERROR;
5792   else
5793     return DBUS_MESSAGE_TYPE_INVALID;
5794 }
5795
5796 /** @} */
5797 #ifdef DBUS_BUILD_TESTS
5798 #include "dbus-test.h"
5799 #include <stdio.h>
5800 #include <stdlib.h>
5801
5802 static void
5803 message_iter_test (DBusMessage *message)
5804 {
5805   DBusMessageIter iter, dict, dict2, array, array2;
5806   char *str;
5807   unsigned char *data;
5808   dbus_int32_t *our_int_array;
5809   int len;
5810   
5811   dbus_message_iter_init (message, &iter);
5812
5813   /* String tests */
5814   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
5815     _dbus_assert_not_reached ("Argument type isn't string");
5816
5817   str = dbus_message_iter_get_string (&iter);
5818   if (strcmp (str, "Test string") != 0)
5819     _dbus_assert_not_reached ("Strings differ");
5820   dbus_free (str);
5821
5822   if (!dbus_message_iter_next (&iter))
5823     _dbus_assert_not_reached ("Reached end of arguments");
5824
5825   /* Signed integer tests */
5826   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32)
5827     _dbus_assert_not_reached ("Argument type isn't int32");
5828
5829   if (dbus_message_iter_get_int32 (&iter) != -0x12345678)
5830     _dbus_assert_not_reached ("Signed integers differ");
5831
5832   if (!dbus_message_iter_next (&iter))
5833     _dbus_assert_not_reached ("Reached end of fields");
5834   
5835   /* Unsigned integer tests */
5836   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
5837     _dbus_assert_not_reached ("Argument type isn't int32");
5838
5839   if (dbus_message_iter_get_uint32 (&iter) != 0xedd1e)
5840     _dbus_assert_not_reached ("Unsigned integers differ");
5841
5842   if (!dbus_message_iter_next (&iter))
5843     _dbus_assert_not_reached ("Reached end of arguments");
5844
5845   /* Double tests */
5846   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DOUBLE)
5847     _dbus_assert_not_reached ("Argument type isn't double");
5848
5849   if (dbus_message_iter_get_double (&iter) != 3.14159)
5850     _dbus_assert_not_reached ("Doubles differ");
5851
5852   if (!dbus_message_iter_next (&iter))
5853     _dbus_assert_not_reached ("Reached end of arguments");
5854
5855   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
5856     _dbus_assert_not_reached ("Argument type not an array");
5857
5858   if (dbus_message_iter_get_array_type (&iter) != DBUS_TYPE_DOUBLE)
5859     _dbus_assert_not_reached ("Array type not double");
5860
5861   
5862   dbus_message_iter_init_array_iterator (&iter, &array, NULL);
5863
5864   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
5865     _dbus_assert_not_reached ("Argument type isn't double");
5866
5867   if (dbus_message_iter_get_double (&array) != 1.5)
5868     _dbus_assert_not_reached ("Unsigned integers differ");
5869
5870   if (!dbus_message_iter_next (&array))
5871     _dbus_assert_not_reached ("Reached end of arguments");
5872
5873   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
5874     _dbus_assert_not_reached ("Argument type isn't double");
5875
5876   if (dbus_message_iter_get_double (&array) != 2.5)
5877     _dbus_assert_not_reached ("Unsigned integers differ");
5878
5879   if (dbus_message_iter_next (&array))
5880     _dbus_assert_not_reached ("Didn't reach end of arguments");
5881   
5882   if (!dbus_message_iter_next (&iter))
5883     _dbus_assert_not_reached ("Reached end of arguments");
5884   
5885
5886   /* dict */
5887
5888   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
5889     _dbus_assert_not_reached ("not dict type");
5890      
5891   dbus_message_iter_init_dict_iterator (&iter, &dict);
5892
5893   str = dbus_message_iter_get_dict_key (&dict);
5894   if (str == NULL || strcmp (str, "test") != 0)
5895     _dbus_assert_not_reached ("wrong dict key");
5896   dbus_free (str);
5897
5898   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
5899     _dbus_assert_not_reached ("wrong dict entry type");
5900
5901   if (dbus_message_iter_get_uint32 (&dict) != 0xDEADBEEF)
5902     _dbus_assert_not_reached ("wrong dict entry value");
5903
5904   /* dict (in dict) */
5905
5906   if (!dbus_message_iter_next (&dict))
5907     _dbus_assert_not_reached ("reached end of dict");
5908   
5909   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_DICT)
5910     _dbus_assert_not_reached ("not dict type");
5911     
5912   dbus_message_iter_init_dict_iterator (&dict, &dict2);
5913   
5914   str = dbus_message_iter_get_dict_key (&dict2);
5915   if (str == NULL || strcmp (str, "dictkey") != 0)
5916     _dbus_assert_not_reached ("wrong dict key");
5917   dbus_free (str);
5918   
5919   if (dbus_message_iter_get_arg_type (&dict2) != DBUS_TYPE_STRING)
5920     _dbus_assert_not_reached ("wrong dict entry type");
5921   
5922   str = dbus_message_iter_get_string (&dict2);
5923   if (str == NULL || strcmp (str, "dictvalue") != 0)
5924     _dbus_assert_not_reached ("wrong dict entry value");
5925   dbus_free (str);
5926   
5927   if (dbus_message_iter_next (&dict2))
5928     _dbus_assert_not_reached ("didn't reach end of dict");
5929
5930   if (!dbus_message_iter_next (&dict))
5931     _dbus_assert_not_reached ("reached end of dict");
5932   
5933   /* array of array of int32 (in dict) */
5934
5935   str = dbus_message_iter_get_dict_key (&dict);
5936   if (str == NULL || strcmp (str, "array") != 0)
5937     _dbus_assert_not_reached ("wrong dict key");
5938   dbus_free (str);
5939   
5940   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_ARRAY)
5941     _dbus_assert_not_reached ("Argument type not an array");
5942
5943   if (dbus_message_iter_get_array_type (&dict) != DBUS_TYPE_ARRAY)
5944     _dbus_assert_not_reached ("Array type not array");
5945
5946   dbus_message_iter_init_array_iterator (&dict, &array, NULL);
5947
5948   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_ARRAY)
5949     _dbus_assert_not_reached ("Argument type isn't array");
5950   
5951   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
5952     _dbus_assert_not_reached ("Array type not int32");
5953   
5954   dbus_message_iter_init_array_iterator (&array, &array2, NULL);
5955
5956   if (dbus_message_iter_get_arg_type (&array2) != DBUS_TYPE_INT32)
5957     _dbus_assert_not_reached ("Argument type isn't int32");
5958
5959   if (dbus_message_iter_get_int32 (&array2) != 0x12345678)
5960     _dbus_assert_not_reached ("Signed integers differ");
5961
5962   if (!dbus_message_iter_next (&array2))
5963     _dbus_assert_not_reached ("Reached end of arguments");
5964
5965   if (dbus_message_iter_get_int32 (&array2) != 0x23456781)
5966     _dbus_assert_not_reached ("Signed integers differ");
5967
5968   if (dbus_message_iter_next (&array2))
5969     _dbus_assert_not_reached ("Didn't reached end of arguments");
5970
5971   if (!dbus_message_iter_next (&array))
5972     _dbus_assert_not_reached ("Reached end of arguments");
5973
5974   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
5975     _dbus_assert_not_reached ("Array type not int32");
5976
5977   if (!dbus_message_iter_get_int32_array (&array,
5978                                           &our_int_array,
5979                                           &len))
5980     _dbus_assert_not_reached ("couldn't get int32 array");
5981
5982   _dbus_assert (len == 3);
5983   _dbus_assert (our_int_array[0] == 0x34567812 &&
5984                 our_int_array[1] == 0x45678123 &&
5985                 our_int_array[2] == 0x56781234);
5986   dbus_free (our_int_array);
5987   
5988   if (dbus_message_iter_next (&array))
5989     _dbus_assert_not_reached ("Didn't reach end of array");
5990
5991   if (dbus_message_iter_next (&dict))
5992     _dbus_assert_not_reached ("Didn't reach end of dict");
5993   
5994   if (!dbus_message_iter_next (&iter))
5995     _dbus_assert_not_reached ("Reached end of arguments");
5996   
5997   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_BYTE)
5998     {
5999       _dbus_warn ("type was: %d\n", dbus_message_iter_get_arg_type (&iter));
6000       _dbus_assert_not_reached ("wrong type after dict (should be byte)");
6001     }
6002   
6003   if (dbus_message_iter_get_byte (&iter) != 0xF0)
6004     _dbus_assert_not_reached ("wrong value after dict");
6005
6006
6007   if (!dbus_message_iter_next (&iter))
6008     _dbus_assert_not_reached ("Reached end of arguments");
6009   
6010   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NIL)
6011     _dbus_assert_not_reached ("not a nil type");
6012   
6013   if (!dbus_message_iter_next (&iter))
6014     _dbus_assert_not_reached ("Reached end of arguments");
6015   
6016   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_CUSTOM)
6017     _dbus_assert_not_reached ("wrong type after dict");
6018
6019   if (!dbus_message_iter_get_custom (&iter, &str, &data, &len))
6020     _dbus_assert_not_reached ("failed to get custom type");
6021
6022   _dbus_assert (strcmp (str, "MyTypeName")==0);
6023   _dbus_assert (len == 5);
6024   _dbus_assert (strcmp (data, "data")==0);
6025   dbus_free (str);
6026   dbus_free (data);
6027   
6028   if (dbus_message_iter_next (&iter))
6029     _dbus_assert_not_reached ("Didn't reach end of arguments");
6030 }
6031
6032
6033 static dbus_bool_t
6034 check_message_handling_type (DBusMessageIter *iter,
6035                              int type)
6036 {
6037   DBusMessageIter child_iter;
6038   
6039   switch (type)
6040     {
6041     case DBUS_TYPE_NIL:
6042       break;
6043     case DBUS_TYPE_BYTE:
6044       dbus_message_iter_get_byte (iter);
6045       break;
6046     case DBUS_TYPE_BOOLEAN:
6047       dbus_message_iter_get_boolean (iter);
6048       break;
6049     case DBUS_TYPE_INT32:
6050       dbus_message_iter_get_int32 (iter);
6051       break;
6052     case DBUS_TYPE_UINT32:
6053       dbus_message_iter_get_uint32 (iter);
6054       break;
6055     case DBUS_TYPE_INT64:
6056 #ifdef DBUS_HAVE_INT64
6057       dbus_message_iter_get_int64 (iter);
6058 #endif
6059       break;
6060     case DBUS_TYPE_UINT64:
6061 #ifdef DBUS_HAVE_INT64
6062       dbus_message_iter_get_uint64 (iter);
6063 #endif
6064       break;
6065     case DBUS_TYPE_DOUBLE:
6066       dbus_message_iter_get_double (iter);
6067       break;
6068     case DBUS_TYPE_STRING:
6069       {
6070         char *str;
6071         str = dbus_message_iter_get_string (iter);
6072         if (str == NULL)
6073           {
6074             _dbus_warn ("NULL string in message\n");
6075             return FALSE;
6076           }
6077         dbus_free (str);
6078       }
6079       break;
6080     case DBUS_TYPE_CUSTOM:
6081       {
6082         char *name;
6083         unsigned char *data;
6084         int len;
6085         
6086         if (!dbus_message_iter_get_custom (iter, &name, &data, &len))
6087           {
6088             _dbus_warn ("error reading name from custom type\n");
6089             return FALSE;
6090           }
6091         dbus_free (data);
6092         dbus_free (name);
6093       }
6094       break;
6095     case DBUS_TYPE_ARRAY:
6096       {
6097         int array_type;
6098
6099         dbus_message_iter_init_array_iterator (iter, &child_iter, &array_type);
6100
6101         while (dbus_message_iter_has_next (&child_iter))
6102           {
6103             if (!check_message_handling_type (&child_iter, array_type))
6104               {
6105                 _dbus_warn ("error in array element\n");
6106                 return FALSE;
6107               }
6108             
6109             if (!dbus_message_iter_next (&child_iter))
6110               break;
6111           }
6112       }
6113       break;
6114     case DBUS_TYPE_DICT:
6115       {
6116         int entry_type;
6117         char *key;
6118         
6119         dbus_message_iter_init_dict_iterator (iter, &child_iter);
6120
6121         while ((entry_type = dbus_message_iter_get_arg_type (&child_iter)) != DBUS_TYPE_INVALID)
6122           {
6123             key = dbus_message_iter_get_dict_key (&child_iter);
6124             if (key == NULL)
6125               {
6126                 _dbus_warn ("error reading dict key\n");
6127                 return FALSE;
6128               }
6129             dbus_free (key);
6130             
6131             if (!check_message_handling_type (&child_iter, entry_type))
6132               {
6133                 _dbus_warn ("error in dict value\n");
6134                 return FALSE;
6135               }
6136             
6137             if (!dbus_message_iter_next (&child_iter))
6138               break;
6139           }
6140       }
6141       break;
6142       
6143     default:
6144       _dbus_warn ("unknown type %d\n", type);
6145       return FALSE;
6146       break;
6147     }
6148   return TRUE;
6149 }
6150   
6151   
6152 static dbus_bool_t
6153 check_message_handling (DBusMessage *message)
6154 {
6155   DBusMessageIter iter;
6156   int type;
6157   dbus_bool_t retval;
6158   dbus_uint32_t client_serial;
6159   
6160   retval = FALSE;
6161   
6162   client_serial = dbus_message_get_serial (message);
6163
6164   /* can't use set_serial due to the assertions at the start of it */
6165   _dbus_marshal_set_uint32 (&message->header,
6166                             message->byte_order,
6167                             CLIENT_SERIAL_OFFSET,
6168                             client_serial);
6169   
6170   if (client_serial != dbus_message_get_serial (message))
6171     {
6172       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
6173       goto failed;
6174     }
6175   
6176   /* If we implement message_set_arg (message, n, value)
6177    * then we would want to test it here
6178    */
6179
6180   dbus_message_iter_init (message, &iter);
6181   while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
6182     {
6183       if (!check_message_handling_type (&iter, type))
6184         goto failed;
6185
6186       if (!dbus_message_iter_next (&iter))
6187         break;
6188     }
6189   
6190   retval = TRUE;
6191   
6192  failed:
6193   return retval;
6194 }
6195
6196 static dbus_bool_t
6197 check_have_valid_message (DBusMessageLoader *loader)
6198 {
6199   DBusMessage *message;
6200   dbus_bool_t retval;
6201
6202   message = NULL;
6203   retval = FALSE;
6204
6205   if (!_dbus_message_loader_queue_messages (loader))
6206     _dbus_assert_not_reached ("no memory to queue messages");
6207   
6208   if (_dbus_message_loader_get_is_corrupted (loader))
6209     {
6210       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
6211       goto failed;
6212     }
6213   
6214   message = _dbus_message_loader_pop_message (loader);
6215   if (message == NULL)
6216     {
6217       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
6218       goto failed;
6219     }
6220   
6221   if (_dbus_string_get_length (&loader->data) > 0)
6222     {
6223       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
6224       goto failed;
6225     }
6226
6227   /* Verify that we're able to properly deal with the message.
6228    * For example, this would detect improper handling of messages
6229    * in nonstandard byte order.
6230    */
6231   if (!check_message_handling (message))
6232     goto failed;  
6233   
6234   retval = TRUE;
6235
6236  failed:
6237   if (message)
6238     dbus_message_unref (message);
6239
6240   return retval;
6241 }
6242
6243 static dbus_bool_t
6244 check_invalid_message (DBusMessageLoader *loader)
6245 {
6246   dbus_bool_t retval;
6247
6248   retval = FALSE;
6249
6250   if (!_dbus_message_loader_queue_messages (loader))
6251     _dbus_assert_not_reached ("no memory to queue messages");
6252   
6253   if (!_dbus_message_loader_get_is_corrupted (loader))
6254     {
6255       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
6256       goto failed;
6257     }
6258
6259   retval = TRUE;
6260
6261  failed:
6262   return retval;
6263 }
6264
6265 static dbus_bool_t
6266 check_incomplete_message (DBusMessageLoader *loader)
6267 {
6268   DBusMessage *message;
6269   dbus_bool_t retval;
6270
6271   message = NULL;
6272   retval = FALSE;
6273
6274   if (!_dbus_message_loader_queue_messages (loader))
6275     _dbus_assert_not_reached ("no memory to queue messages");
6276   
6277   if (_dbus_message_loader_get_is_corrupted (loader))
6278     {
6279       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
6280       goto failed;
6281     }
6282   
6283   message = _dbus_message_loader_pop_message (loader);
6284   if (message != NULL)
6285     {
6286       _dbus_warn ("loaded message that was expected to be incomplete\n");
6287       goto failed;
6288     }
6289
6290   retval = TRUE;
6291
6292  failed:
6293   if (message)
6294     dbus_message_unref (message);
6295   return retval;
6296 }
6297
6298 static dbus_bool_t
6299 check_loader_results (DBusMessageLoader      *loader,
6300                       DBusMessageValidity     validity)
6301 {
6302   if (!_dbus_message_loader_queue_messages (loader))
6303     _dbus_assert_not_reached ("no memory to queue messages");
6304   
6305   switch (validity)
6306     {
6307     case _DBUS_MESSAGE_VALID:
6308       return check_have_valid_message (loader);
6309     case _DBUS_MESSAGE_INVALID:
6310       return check_invalid_message (loader);
6311     case _DBUS_MESSAGE_INCOMPLETE:
6312       return check_incomplete_message (loader);
6313     case _DBUS_MESSAGE_UNKNOWN:
6314       return TRUE;
6315     }
6316
6317   _dbus_assert_not_reached ("bad DBusMessageValidity");
6318   return FALSE;
6319 }
6320
6321
6322 /**
6323  * Loads the message in the given message file.
6324  *
6325  * @param filename filename to load
6326  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
6327  * @param data string to load message into
6328  * @returns #TRUE if the message was loaded
6329  */
6330 dbus_bool_t
6331 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
6332                                             dbus_bool_t          is_raw,
6333                                             DBusString          *data)
6334 {
6335   dbus_bool_t retval;
6336
6337   retval = FALSE;  
6338
6339   if (is_raw)
6340     {
6341       DBusError error;
6342
6343       _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename));
6344       dbus_error_init (&error);
6345       if (!_dbus_file_get_contents (data, filename, &error))
6346         {
6347           _dbus_warn ("Could not load message file %s: %s\n",
6348                       _dbus_string_get_const_data (filename),
6349                       error.message);
6350           dbus_error_free (&error);
6351           goto failed;
6352         }
6353     }
6354   else
6355     {
6356       if (!_dbus_message_data_load (data, filename))
6357         {
6358           _dbus_warn ("Could not load message file %s\n",
6359                       _dbus_string_get_const_data (filename));
6360           goto failed;
6361         }
6362     }
6363
6364   retval = TRUE;
6365   
6366  failed:
6367
6368   return retval;
6369 }
6370
6371 /**
6372  * Tries loading the message in the given message file
6373  * and verifies that DBusMessageLoader can handle it.
6374  *
6375  * @param filename filename to load
6376  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
6377  * @param expected_validity what the message has to be like to return #TRUE
6378  * @returns #TRUE if the message has the expected validity
6379  */
6380 dbus_bool_t
6381 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
6382                                            dbus_bool_t          is_raw,
6383                                            DBusMessageValidity  expected_validity)
6384 {
6385   DBusString data;
6386   dbus_bool_t retval;
6387
6388   retval = FALSE;
6389   
6390   if (!_dbus_string_init (&data))
6391     _dbus_assert_not_reached ("could not allocate string\n");
6392
6393   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
6394                                                    &data))
6395     goto failed;
6396
6397   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
6398
6399  failed:
6400
6401   if (!retval)
6402     {
6403       if (_dbus_string_get_length (&data) > 0)
6404         _dbus_verbose_bytes_of_string (&data, 0,
6405                                        _dbus_string_get_length (&data));
6406       
6407       _dbus_warn ("Failed message loader test on %s\n",
6408                   _dbus_string_get_const_data (filename));
6409     }
6410   
6411   _dbus_string_free (&data);
6412
6413   return retval;
6414 }
6415
6416 /**
6417  * Tries loading the given message data.
6418  *
6419  *
6420  * @param data the message data
6421  * @param expected_validity what the message has to be like to return #TRUE
6422  * @returns #TRUE if the message has the expected validity
6423  */
6424 dbus_bool_t
6425 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
6426                                            DBusMessageValidity  expected_validity)
6427 {
6428   DBusMessageLoader *loader;
6429   dbus_bool_t retval;
6430   int len;
6431   int i;
6432
6433   loader = NULL;
6434   retval = FALSE;
6435
6436   /* Write the data one byte at a time */
6437   
6438   loader = _dbus_message_loader_new ();
6439
6440   /* check some trivial loader functions */
6441   _dbus_message_loader_ref (loader);
6442   _dbus_message_loader_unref (loader);
6443   _dbus_message_loader_get_max_message_size (loader);
6444   
6445   len = _dbus_string_get_length (data);
6446   for (i = 0; i < len; i++)
6447     {
6448       DBusString *buffer;
6449
6450       _dbus_message_loader_get_buffer (loader, &buffer);
6451       _dbus_string_append_byte (buffer,
6452                                 _dbus_string_get_byte (data, i));
6453       _dbus_message_loader_return_buffer (loader, buffer, 1);
6454     }
6455   
6456   if (!check_loader_results (loader, expected_validity))
6457     goto failed;
6458
6459   _dbus_message_loader_unref (loader);
6460   loader = NULL;
6461
6462   /* Write the data all at once */
6463   
6464   loader = _dbus_message_loader_new ();
6465
6466   {
6467     DBusString *buffer;
6468     
6469     _dbus_message_loader_get_buffer (loader, &buffer);
6470     _dbus_string_copy (data, 0, buffer,
6471                        _dbus_string_get_length (buffer));
6472     _dbus_message_loader_return_buffer (loader, buffer, 1);
6473   }
6474   
6475   if (!check_loader_results (loader, expected_validity))
6476     goto failed;
6477
6478   _dbus_message_loader_unref (loader);
6479   loader = NULL;  
6480
6481   /* Write the data 2 bytes at a time */
6482   
6483   loader = _dbus_message_loader_new ();
6484
6485   len = _dbus_string_get_length (data);
6486   for (i = 0; i < len; i += 2)
6487     {
6488       DBusString *buffer;
6489
6490       _dbus_message_loader_get_buffer (loader, &buffer);
6491       _dbus_string_append_byte (buffer,
6492                                 _dbus_string_get_byte (data, i));
6493       if ((i+1) < len)
6494         _dbus_string_append_byte (buffer,
6495                                   _dbus_string_get_byte (data, i+1));
6496       _dbus_message_loader_return_buffer (loader, buffer, 1);
6497     }
6498   
6499   if (!check_loader_results (loader, expected_validity))
6500     goto failed;
6501
6502   _dbus_message_loader_unref (loader);
6503   loader = NULL;
6504   
6505   retval = TRUE;
6506   
6507  failed:
6508   
6509   if (loader)
6510     _dbus_message_loader_unref (loader);
6511   
6512   return retval;
6513 }
6514
6515 static dbus_bool_t
6516 process_test_subdir (const DBusString          *test_base_dir,
6517                      const char                *subdir,
6518                      DBusMessageValidity        validity,
6519                      DBusForeachMessageFileFunc function,
6520                      void                      *user_data)
6521 {
6522   DBusString test_directory;
6523   DBusString filename;
6524   DBusDirIter *dir;
6525   dbus_bool_t retval;
6526   DBusError error;
6527
6528   retval = FALSE;
6529   dir = NULL;
6530   
6531   if (!_dbus_string_init (&test_directory))
6532     _dbus_assert_not_reached ("didn't allocate test_directory\n");
6533
6534   _dbus_string_init_const (&filename, subdir);
6535   
6536   if (!_dbus_string_copy (test_base_dir, 0,
6537                           &test_directory, 0))
6538     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
6539   
6540   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
6541     _dbus_assert_not_reached ("couldn't allocate full path");
6542
6543   _dbus_string_free (&filename);
6544   if (!_dbus_string_init (&filename))
6545     _dbus_assert_not_reached ("didn't allocate filename string\n");
6546
6547   dbus_error_init (&error);
6548   dir = _dbus_directory_open (&test_directory, &error);
6549   if (dir == NULL)
6550     {
6551       _dbus_warn ("Could not open %s: %s\n",
6552                   _dbus_string_get_const_data (&test_directory),
6553                   error.message);
6554       dbus_error_free (&error);
6555       goto failed;
6556     }
6557
6558   printf ("Testing %s:\n", subdir);
6559   
6560  next:
6561   while (_dbus_directory_get_next_file (dir, &filename, &error))
6562     {
6563       DBusString full_path;
6564       dbus_bool_t is_raw;
6565       
6566       if (!_dbus_string_init (&full_path))
6567         _dbus_assert_not_reached ("couldn't init string");
6568
6569       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
6570         _dbus_assert_not_reached ("couldn't copy dir to full_path");
6571
6572       if (!_dbus_concat_dir_and_file (&full_path, &filename))
6573         _dbus_assert_not_reached ("couldn't concat file to dir");
6574
6575       if (_dbus_string_ends_with_c_str (&filename, ".message"))
6576         is_raw = FALSE;
6577       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
6578         is_raw = TRUE;
6579       else
6580         {
6581           _dbus_verbose ("Skipping non-.message file %s\n",
6582                          _dbus_string_get_const_data (&filename));
6583           _dbus_string_free (&full_path);
6584           goto next;
6585         }
6586
6587       printf ("    %s\n",
6588               _dbus_string_get_const_data (&filename));
6589       
6590       _dbus_verbose (" expecting %s for %s\n",
6591                      validity == _DBUS_MESSAGE_VALID ? "valid" :
6592                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
6593                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")),
6594                      _dbus_string_get_const_data (&filename));
6595       
6596       if (! (*function) (&full_path, is_raw, validity, user_data))
6597         {
6598           _dbus_string_free (&full_path);
6599           goto failed;
6600         }
6601       else
6602         _dbus_string_free (&full_path);
6603     }
6604
6605   if (dbus_error_is_set (&error))
6606     {
6607       _dbus_warn ("Could not get next file in %s: %s\n",
6608                   _dbus_string_get_const_data (&test_directory),
6609                   error.message);
6610       dbus_error_free (&error);
6611       goto failed;
6612     }
6613     
6614   retval = TRUE;
6615   
6616  failed:
6617
6618   if (dir)
6619     _dbus_directory_close (dir);
6620   _dbus_string_free (&test_directory);
6621   _dbus_string_free (&filename);
6622
6623   return retval;
6624 }
6625                      
6626 /**
6627  * Runs the given function on every message file in the test suite.
6628  * The function should return #FALSE on test failure or fatal error.
6629  *
6630  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
6631  * @param func the function to run
6632  * @param user_data data for function
6633  * @returns #FALSE if there's a failure
6634  */
6635 dbus_bool_t
6636 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
6637                                                DBusForeachMessageFileFunc func,
6638                                                void                      *user_data)
6639 {
6640   DBusString test_directory;
6641   dbus_bool_t retval;
6642
6643   retval = FALSE;
6644   
6645   _dbus_string_init_const (&test_directory, test_data_dir);
6646
6647   if (!process_test_subdir (&test_directory, "valid-messages",
6648                             _DBUS_MESSAGE_VALID, func, user_data))
6649     goto failed;
6650
6651   if (!process_test_subdir (&test_directory, "invalid-messages",
6652                             _DBUS_MESSAGE_INVALID, func, user_data))
6653     goto failed;
6654   
6655   if (!process_test_subdir (&test_directory, "incomplete-messages",
6656                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
6657     goto failed;
6658
6659   retval = TRUE;
6660   
6661  failed:
6662
6663   _dbus_string_free (&test_directory);
6664   
6665   return retval;
6666 }
6667
6668 static void
6669 verify_test_message (DBusMessage *message)
6670 {
6671   DBusMessageIter iter, dict;
6672   DBusError error;
6673   dbus_int32_t our_int;
6674   char *our_str;
6675   double our_double;
6676   dbus_bool_t our_bool;
6677   dbus_uint32_t our_uint32;
6678   dbus_int32_t *our_uint32_array;
6679   int our_uint32_array_len;
6680   dbus_int32_t *our_int32_array;
6681   int our_int32_array_len;
6682   char **our_string_array;
6683   int our_string_array_len;
6684 #ifdef DBUS_HAVE_INT64
6685   dbus_int64_t our_int64;
6686   dbus_uint64_t our_uint64;
6687   dbus_int64_t *our_uint64_array;
6688   int our_uint64_array_len;
6689   dbus_int64_t *our_int64_array;
6690   int our_int64_array_len;
6691 #endif
6692   double *our_double_array;
6693   int our_double_array_len;
6694   unsigned char *our_byte_array;
6695   int our_byte_array_len;
6696   unsigned char *our_boolean_array;
6697   int our_boolean_array_len;
6698   
6699   dbus_message_iter_init (message, &iter);
6700
6701   dbus_error_init (&error);
6702   if (!dbus_message_iter_get_args (&iter, &error,
6703                                    DBUS_TYPE_INT32, &our_int,
6704 #ifdef DBUS_HAVE_INT64
6705                                    DBUS_TYPE_INT64, &our_int64,
6706                                    DBUS_TYPE_UINT64, &our_uint64,
6707 #endif
6708                                    DBUS_TYPE_STRING, &our_str,
6709                                    DBUS_TYPE_DOUBLE, &our_double,
6710                                    DBUS_TYPE_BOOLEAN, &our_bool,
6711                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
6712                                    &our_uint32_array, &our_uint32_array_len,
6713                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
6714                                    &our_int32_array, &our_int32_array_len,
6715 #ifdef DBUS_HAVE_INT64
6716                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64,
6717                                    &our_uint64_array, &our_uint64_array_len,
6718                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT64,
6719                                    &our_int64_array, &our_int64_array_len,
6720 #endif
6721                                    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
6722                                    &our_string_array, &our_string_array_len,
6723                                    DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE,
6724                                    &our_double_array, &our_double_array_len,
6725                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
6726                                    &our_byte_array, &our_byte_array_len,
6727                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN,
6728                                    &our_boolean_array, &our_boolean_array_len,
6729                                    0))
6730     {
6731       _dbus_warn ("error: %s - %s\n", error.name,
6732                   (error.message != NULL) ? error.message : "no message");
6733       _dbus_assert_not_reached ("Could not get arguments");
6734     }
6735
6736   if (our_int != -0x12345678)
6737     _dbus_assert_not_reached ("integers differ!");
6738
6739 #ifdef DBUS_HAVE_INT64
6740   if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd))
6741     _dbus_assert_not_reached ("64-bit integers differ!");
6742   if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd))
6743     _dbus_assert_not_reached ("64-bit unsigned integers differ!");
6744 #endif
6745   
6746   if (our_double != 3.14159)
6747     _dbus_assert_not_reached ("doubles differ!");
6748
6749   if (strcmp (our_str, "Test string") != 0)
6750     _dbus_assert_not_reached ("strings differ!");
6751   dbus_free (our_str);
6752
6753   if (!our_bool)
6754     _dbus_assert_not_reached ("booleans differ");
6755
6756   if (our_uint32_array_len != 4 ||
6757       our_uint32_array[0] != 0x12345678 ||
6758       our_uint32_array[1] != 0x23456781 ||
6759       our_uint32_array[2] != 0x34567812 ||
6760       our_uint32_array[3] != 0x45678123)
6761     _dbus_assert_not_reached ("uint array differs");
6762   dbus_free (our_uint32_array);
6763
6764   if (our_int32_array_len != 4 ||
6765       our_int32_array[0] != 0x12345678 ||
6766       our_int32_array[1] != -0x23456781 ||
6767       our_int32_array[2] != 0x34567812 ||
6768       our_int32_array[3] != -0x45678123)
6769     _dbus_assert_not_reached ("int array differs");
6770   dbus_free (our_int32_array);
6771
6772 #ifdef DBUS_HAVE_INT64
6773   if (our_uint64_array_len != 4 ||
6774       our_uint64_array[0] != 0x12345678 ||
6775       our_uint64_array[1] != 0x23456781 ||
6776       our_uint64_array[2] != 0x34567812 ||
6777       our_uint64_array[3] != 0x45678123)
6778     _dbus_assert_not_reached ("uint64 array differs");
6779   dbus_free (our_uint64_array);
6780   
6781   if (our_int64_array_len != 4 ||
6782       our_int64_array[0] != 0x12345678 ||
6783       our_int64_array[1] != -0x23456781 ||
6784       our_int64_array[2] != 0x34567812 ||
6785       our_int64_array[3] != -0x45678123)
6786     _dbus_assert_not_reached ("int64 array differs");
6787   dbus_free (our_int64_array);
6788 #endif /* DBUS_HAVE_INT64 */
6789   
6790   if (our_string_array_len != 4)
6791     _dbus_assert_not_reached ("string array has wrong length");
6792
6793   if (strcmp (our_string_array[0], "Foo") != 0 ||
6794       strcmp (our_string_array[1], "bar") != 0 ||
6795       strcmp (our_string_array[2], "") != 0 ||
6796       strcmp (our_string_array[3], "woo woo woo woo") != 0)
6797     _dbus_assert_not_reached ("string array differs");
6798
6799   dbus_free_string_array (our_string_array);
6800
6801   if (our_double_array_len != 3)
6802     _dbus_assert_not_reached ("double array had wrong length");
6803
6804   /* On all IEEE machines (i.e. everything sane) exact equality
6805    * should be preserved over the wire
6806    */
6807   if (our_double_array[0] != 0.1234 ||
6808       our_double_array[1] != 9876.54321 ||
6809       our_double_array[2] != -300.0)
6810     _dbus_assert_not_reached ("double array had wrong values");
6811
6812   dbus_free (our_double_array);
6813
6814   if (our_byte_array_len != 4)
6815     _dbus_assert_not_reached ("byte array had wrong length");
6816
6817   if (our_byte_array[0] != 'a' ||
6818       our_byte_array[1] != 'b' ||
6819       our_byte_array[2] != 'c' ||
6820       our_byte_array[3] != 234)
6821     _dbus_assert_not_reached ("byte array had wrong values");
6822
6823   dbus_free (our_byte_array);
6824
6825   if (our_boolean_array_len != 5)
6826     _dbus_assert_not_reached ("bool array had wrong length");
6827
6828   if (our_boolean_array[0] != TRUE ||
6829       our_boolean_array[1] != FALSE ||
6830       our_boolean_array[2] != TRUE ||
6831       our_boolean_array[3] != TRUE ||
6832       our_boolean_array[4] != FALSE)
6833     _dbus_assert_not_reached ("bool array had wrong values");
6834
6835   dbus_free (our_boolean_array);
6836   
6837   if (!dbus_message_iter_next (&iter))
6838     _dbus_assert_not_reached ("Reached end of arguments");
6839
6840   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
6841     _dbus_assert_not_reached ("not dict type");
6842      
6843   dbus_message_iter_init_dict_iterator (&iter, &dict);
6844
6845   our_str = dbus_message_iter_get_dict_key (&dict);
6846   if (our_str == NULL || strcmp (our_str, "test") != 0)
6847     _dbus_assert_not_reached ("wrong dict key");
6848   dbus_free (our_str);
6849
6850   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
6851     {
6852       _dbus_verbose ("dict entry type: %d\n", dbus_message_iter_get_arg_type (&dict));
6853       _dbus_assert_not_reached ("wrong dict entry type");
6854     }
6855
6856   if ((our_uint32 = dbus_message_iter_get_uint32 (&dict)) != 0xDEADBEEF)
6857     {
6858       _dbus_verbose ("dict entry val: %x\n", our_uint32);
6859       _dbus_assert_not_reached ("wrong dict entry value");
6860     }
6861
6862   if (dbus_message_iter_next (&dict))
6863     _dbus_assert_not_reached ("Didn't reach end of dict");
6864   
6865   if (!dbus_message_iter_next (&iter))
6866     _dbus_assert_not_reached ("Reached end of arguments");
6867   
6868   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
6869     _dbus_assert_not_reached ("wrong type after dict");
6870   
6871   if (dbus_message_iter_get_uint32 (&iter) != 0xCAFEBABE)
6872     _dbus_assert_not_reached ("wrong value after dict");
6873
6874   if (dbus_message_iter_next (&iter))
6875     _dbus_assert_not_reached ("Didn't reach end of arguments");
6876 }
6877
6878 /**
6879  * @ingroup DBusMessageInternals
6880  * Unit test for DBusMessage.
6881  *
6882  * @returns #TRUE on success.
6883  */
6884 dbus_bool_t
6885 _dbus_message_test (const char *test_data_dir)
6886 {
6887   DBusMessage *message;
6888   DBusMessageLoader *loader;
6889   DBusMessageIter iter, child_iter, child_iter2, child_iter3;
6890   int i;
6891   const char *data;
6892   DBusMessage *copy;
6893   const char *name1;
6894   const char *name2;
6895   const dbus_uint32_t our_uint32_array[] =
6896     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
6897   const dbus_uint32_t our_int32_array[] =
6898     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
6899 #ifdef DBUS_HAVE_INT64
6900   const dbus_uint64_t our_uint64_array[] =
6901     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
6902   const dbus_uint64_t our_int64_array[] =
6903     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
6904 #endif
6905   const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" };
6906   const double our_double_array[] = { 0.1234, 9876.54321, -300.0 };
6907   const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 };
6908   const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE };
6909   char sig[64];
6910   const char *s;
6911   char *t;
6912   DBusError error;
6913   
6914   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
6915
6916   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
6917                                           "/org/freedesktop/TestPath",
6918                                           "Foo.TestInterface",
6919                                           "TestMethod");
6920   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
6921   _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",
6922                                              "TestMethod"));
6923   _dbus_assert (strcmp (dbus_message_get_path (message),
6924                         "/org/freedesktop/TestPath") == 0);
6925   _dbus_message_set_serial (message, 1234);
6926   /* string length including nul byte not a multiple of 4 */
6927   if (!dbus_message_set_sender (message, "org.foo.bar1"))
6928     _dbus_assert_not_reached ("out of memory");
6929   _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1"));
6930   dbus_message_set_reply_serial (message, 5678);
6931   if (!dbus_message_set_sender (message, NULL))
6932     _dbus_assert_not_reached ("out of memory");
6933   _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1"));
6934   _dbus_assert (dbus_message_get_serial (message) == 1234);
6935   _dbus_assert (dbus_message_get_reply_serial (message) == 5678);
6936   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
6937
6938   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
6939   dbus_message_set_no_reply (message, TRUE);
6940   _dbus_assert (dbus_message_get_no_reply (message) == TRUE);
6941   dbus_message_set_no_reply (message, FALSE);
6942   _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
6943
6944   /* Set/get some header fields */
6945   
6946   if (!dbus_message_set_path (message, "/foo"))
6947     _dbus_assert_not_reached ("out of memory");
6948   _dbus_assert (strcmp (dbus_message_get_path (message),
6949                         "/foo") == 0);
6950
6951   if (!dbus_message_set_interface (message, "org.Foo"))
6952     _dbus_assert_not_reached ("out of memory");
6953   _dbus_assert (strcmp (dbus_message_get_interface (message),
6954                         "org.Foo") == 0);
6955   
6956   if (!dbus_message_set_member (message, "Bar"))
6957     _dbus_assert_not_reached ("out of memory");
6958   _dbus_assert (strcmp (dbus_message_get_member (message),
6959                         "Bar") == 0);
6960
6961   /* Set/get them with longer values */
6962   if (!dbus_message_set_path (message, "/foo/bar"))
6963     _dbus_assert_not_reached ("out of memory");
6964   _dbus_assert (strcmp (dbus_message_get_path (message),
6965                         "/foo/bar") == 0);
6966
6967   if (!dbus_message_set_interface (message, "org.Foo.Bar"))
6968     _dbus_assert_not_reached ("out of memory");
6969   _dbus_assert (strcmp (dbus_message_get_interface (message),
6970                         "org.Foo.Bar") == 0);
6971   
6972   if (!dbus_message_set_member (message, "BarFoo"))
6973     _dbus_assert_not_reached ("out of memory");
6974   _dbus_assert (strcmp (dbus_message_get_member (message),
6975                         "BarFoo") == 0);
6976
6977   /* Realloc shorter again */
6978   
6979   if (!dbus_message_set_path (message, "/foo"))
6980     _dbus_assert_not_reached ("out of memory");
6981   _dbus_assert (strcmp (dbus_message_get_path (message),
6982                         "/foo") == 0);
6983
6984   if (!dbus_message_set_interface (message, "org.Foo"))
6985     _dbus_assert_not_reached ("out of memory");
6986   _dbus_assert (strcmp (dbus_message_get_interface (message),
6987                         "org.Foo") == 0);
6988   
6989   if (!dbus_message_set_member (message, "Bar"))
6990     _dbus_assert_not_reached ("out of memory");
6991   _dbus_assert (strcmp (dbus_message_get_member (message),
6992                         "Bar") == 0);
6993   
6994   dbus_message_unref (message);
6995   
6996   /* Test the vararg functions */
6997   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
6998                                           "/org/freedesktop/TestPath",
6999                                           "Foo.TestInterface",
7000                                           "TestMethod");
7001   _dbus_message_set_serial (message, 1);
7002   dbus_message_append_args (message,
7003                             DBUS_TYPE_INT32, -0x12345678,
7004 #ifdef DBUS_HAVE_INT64
7005                             DBUS_TYPE_INT64, DBUS_INT64_CONSTANT (-0x123456789abcd),
7006                             DBUS_TYPE_UINT64, DBUS_UINT64_CONSTANT (0x123456789abcd),
7007 #endif
7008                             DBUS_TYPE_STRING, "Test string",
7009                             DBUS_TYPE_DOUBLE, 3.14159,
7010                             DBUS_TYPE_BOOLEAN, TRUE,
7011                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, our_uint32_array,
7012                             _DBUS_N_ELEMENTS (our_uint32_array),
7013                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, our_int32_array,
7014                             _DBUS_N_ELEMENTS (our_int32_array),
7015 #ifdef DBUS_HAVE_INT64
7016                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, our_uint64_array,
7017                             _DBUS_N_ELEMENTS (our_uint64_array),
7018                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array,
7019                             _DBUS_N_ELEMENTS (our_int64_array),
7020 #endif
7021                             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array,
7022                             _DBUS_N_ELEMENTS (our_string_array),
7023                             DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array,
7024                             _DBUS_N_ELEMENTS (our_double_array),
7025                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, our_byte_array,
7026                             _DBUS_N_ELEMENTS (our_byte_array),
7027                             DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, our_boolean_array,
7028                             _DBUS_N_ELEMENTS (our_boolean_array),
7029                             0);
7030   
7031   dbus_message_append_iter_init (message, &iter);
7032   dbus_message_iter_append_dict (&iter, &child_iter);
7033   dbus_message_iter_append_dict_key (&child_iter, "test");
7034   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
7035   dbus_message_iter_append_uint32 (&iter, 0xCAFEBABE);
7036
7037   i = 0;
7038   sig[i++] = DBUS_TYPE_INT32;
7039 #ifdef DBUS_HAVE_INT64
7040   sig[i++] = DBUS_TYPE_INT64;
7041   sig[i++] = DBUS_TYPE_UINT64;
7042 #endif
7043   sig[i++] = DBUS_TYPE_STRING;
7044   sig[i++] = DBUS_TYPE_DOUBLE;
7045   sig[i++] = DBUS_TYPE_BOOLEAN;
7046   sig[i++] = DBUS_TYPE_ARRAY;
7047   sig[i++] = DBUS_TYPE_UINT32;
7048   sig[i++] = DBUS_TYPE_ARRAY;
7049   sig[i++] = DBUS_TYPE_INT32;
7050 #ifdef DBUS_HAVE_INT64
7051   sig[i++] = DBUS_TYPE_ARRAY;
7052   sig[i++] = DBUS_TYPE_UINT64;
7053   sig[i++] = DBUS_TYPE_ARRAY;
7054   sig[i++] = DBUS_TYPE_INT64;
7055 #endif
7056   sig[i++] = DBUS_TYPE_ARRAY;
7057   sig[i++] = DBUS_TYPE_STRING;
7058   sig[i++] = DBUS_TYPE_ARRAY;
7059   sig[i++] = DBUS_TYPE_DOUBLE;
7060   sig[i++] = DBUS_TYPE_ARRAY;
7061   sig[i++] = DBUS_TYPE_BYTE;
7062   sig[i++] = DBUS_TYPE_ARRAY;
7063   sig[i++] = DBUS_TYPE_BOOLEAN;
7064   sig[i++] = DBUS_TYPE_DICT;
7065   sig[i++] = DBUS_TYPE_UINT32;
7066   sig[i++] = DBUS_TYPE_INVALID;
7067
7068   _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig));
7069   
7070   _dbus_verbose_bytes_of_string (&message->header, 0,
7071                                  _dbus_string_get_length (&message->header));
7072   _dbus_verbose_bytes_of_string (&message->body, 0,
7073                                  _dbus_string_get_length (&message->body));
7074   
7075   _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n",
7076                  sig, dbus_message_get_signature (message));
7077   
7078   s = dbus_message_get_signature (message);
7079   
7080   _dbus_assert (dbus_message_has_signature (message, sig));
7081   _dbus_assert (strcmp (s, sig) == 0);
7082   
7083   verify_test_message (message);
7084
7085   copy = dbus_message_copy (message);
7086   
7087   _dbus_assert (message->client_serial == copy->client_serial);
7088   _dbus_assert (message->reply_serial == copy->reply_serial);
7089   _dbus_assert (message->header_padding == copy->header_padding);
7090   
7091   _dbus_assert (_dbus_string_get_length (&message->header) ==
7092                 _dbus_string_get_length (&copy->header));
7093
7094   _dbus_assert (_dbus_string_get_length (&message->body) ==
7095                 _dbus_string_get_length (&copy->body));
7096
7097   _dbus_assert (_dbus_string_get_length (&message->signature) ==
7098                 _dbus_string_get_length (&copy->signature));
7099   
7100   verify_test_message (copy);
7101
7102   name1 = dbus_message_get_interface (message);
7103   name2 = dbus_message_get_interface (copy);
7104
7105   _dbus_assert (strcmp (name1, name2) == 0);
7106
7107   name1 = dbus_message_get_member (message);
7108   name2 = dbus_message_get_member (copy);
7109
7110   _dbus_assert (strcmp (name1, name2) == 0);
7111   
7112   dbus_message_unref (message);  
7113   dbus_message_unref (copy);
7114
7115   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
7116                                           "/org/freedesktop/TestPath",
7117                                           "Foo.TestInterface",
7118                                           "TestMethod");
7119
7120   _dbus_message_set_serial (message, 1);
7121   dbus_message_set_reply_serial (message, 0x12345678);
7122
7123   dbus_message_append_iter_init (message, &iter);
7124   dbus_message_iter_append_string (&iter, "Test string");
7125   dbus_message_iter_append_int32 (&iter, -0x12345678);
7126   dbus_message_iter_append_uint32 (&iter, 0xedd1e);
7127   dbus_message_iter_append_double (&iter, 3.14159);
7128
7129   dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE);
7130   dbus_message_iter_append_double (&child_iter, 1.5);
7131   dbus_message_iter_append_double (&child_iter, 2.5);
7132
7133   /* dict */
7134   dbus_message_iter_append_dict (&iter, &child_iter);
7135   dbus_message_iter_append_dict_key (&child_iter, "test");
7136   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
7137
7138   /* dict (in dict) */
7139   dbus_message_iter_append_dict_key (&child_iter, "testdict");
7140   dbus_message_iter_append_dict (&child_iter, &child_iter2);
7141
7142   dbus_message_iter_append_dict_key (&child_iter2, "dictkey");
7143   dbus_message_iter_append_string (&child_iter2, "dictvalue");
7144
7145   /* array of array of int32  (in dict) */
7146   dbus_message_iter_append_dict_key (&child_iter, "array");
7147   dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY);
7148   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
7149   dbus_message_iter_append_int32 (&child_iter3, 0x12345678);
7150   dbus_message_iter_append_int32 (&child_iter3, 0x23456781);
7151   _dbus_warn ("next call expected to fail with wrong array type\n");
7152   _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32));
7153   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
7154   dbus_message_iter_append_int32 (&child_iter3, 0x34567812);
7155   dbus_message_iter_append_int32 (&child_iter3, 0x45678123);
7156   dbus_message_iter_append_int32 (&child_iter3, 0x56781234);
7157   
7158   dbus_message_iter_append_byte (&iter, 0xF0);
7159
7160   dbus_message_iter_append_nil (&iter);
7161
7162   dbus_message_iter_append_custom (&iter, "MyTypeName",
7163                                    "data", 5);
7164   
7165   message_iter_test (message);
7166   
7167   /* Message loader test */
7168   _dbus_message_lock (message);
7169   loader = _dbus_message_loader_new ();
7170
7171   /* check ref/unref */
7172   _dbus_message_loader_ref (loader);
7173   _dbus_message_loader_unref (loader);
7174   
7175   /* Write the header data one byte at a time */
7176   data = _dbus_string_get_const_data (&message->header);
7177   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
7178     {
7179       DBusString *buffer;
7180
7181       _dbus_message_loader_get_buffer (loader, &buffer);
7182       _dbus_string_append_byte (buffer, data[i]);
7183       _dbus_message_loader_return_buffer (loader, buffer, 1);
7184     }
7185
7186   /* Write the body data one byte at a time */
7187   data = _dbus_string_get_const_data (&message->body);
7188   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
7189     {
7190       DBusString *buffer;
7191
7192       _dbus_message_loader_get_buffer (loader, &buffer);
7193       _dbus_string_append_byte (buffer, data[i]);
7194       _dbus_message_loader_return_buffer (loader, buffer, 1);
7195     }
7196
7197   copy = dbus_message_copy (message); /* save for tests below */
7198   dbus_message_unref (message);
7199
7200   /* Now pop back the message */
7201   if (!_dbus_message_loader_queue_messages (loader))
7202     _dbus_assert_not_reached ("no memory to queue messages");
7203   
7204   if (_dbus_message_loader_get_is_corrupted (loader))
7205     _dbus_assert_not_reached ("message loader corrupted");
7206   
7207   message = _dbus_message_loader_pop_message (loader);
7208   if (!message)
7209     _dbus_assert_not_reached ("received a NULL message");
7210
7211   if (dbus_message_get_reply_serial (message) != 0x12345678)
7212     _dbus_assert_not_reached ("reply serial fields differ");
7213   
7214   message_iter_test (message);
7215   
7216   dbus_message_unref (message);
7217   _dbus_message_loader_unref (loader);
7218
7219   message = dbus_message_new_method_return (copy);
7220   if (message == NULL)
7221     _dbus_assert_not_reached ("out of memory\n");
7222   dbus_message_unref (copy);
7223
7224   if (!dbus_message_append_args (message,
7225                                  DBUS_TYPE_STRING, "hello",
7226                                  DBUS_TYPE_INVALID))
7227     _dbus_assert_not_reached ("no memory");
7228
7229   if (!dbus_message_has_signature (message, "s"))
7230     _dbus_assert_not_reached ("method return has wrong signature");
7231
7232   dbus_error_init (&error);
7233   if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING,
7234                               &t, DBUS_TYPE_INVALID))
7235     
7236     {
7237       _dbus_warn ("Failed to get expected string arg: %s\n", error.message);
7238       exit (1);
7239     }
7240   dbus_free (t);
7241   
7242   dbus_message_unref (message);
7243   
7244   /* Now load every message in test_data_dir if we have one */
7245   if (test_data_dir == NULL)
7246     return TRUE;
7247
7248   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
7249                                                         (DBusForeachMessageFileFunc)
7250                                                         dbus_internal_do_not_use_try_message_file,
7251                                                         NULL);
7252 }
7253
7254 #endif /* DBUS_BUILD_TESTS */