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