2003-01-29 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-message.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c  DBusMessage object
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  * Copyright (C) 2002, 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-internals.h"
26 #include "dbus-marshal.h"
27 #include "dbus-message.h"
28 #include "dbus-message-internal.h"
29 #include "dbus-memory.h"
30 #include "dbus-list.h"
31 #include "dbus-message-builder.h"
32 #include <string.h>
33
34 /**
35  * @defgroup DBusMessageInternals DBusMessage implementation details
36  * @ingroup DBusInternals
37  * @brief DBusMessage private implementation details.
38  *
39  * The guts of DBusMessage and its methods.
40  *
41  * @{
42  */
43
44 enum
45 {
46   FIELD_HEADER_LENGTH,
47   FIELD_BODY_LENGTH,
48   FIELD_CLIENT_SERIAL,
49   FIELD_NAME,
50   FIELD_SERVICE,
51   FIELD_SENDER,
52   FIELD_REPLY_SERIAL,
53
54   FIELD_LAST
55 };
56
57 static dbus_bool_t field_is_named[FIELD_LAST] =
58 {
59   FALSE, /* FIELD_HEADER_LENGTH */
60   FALSE, /* FIELD_BODY_LENGTH */
61   FALSE, /* FIELD_CLIENT_SERIAL */
62   TRUE,  /* FIELD_NAME */
63   TRUE,  /* FIELD_SERVICE */
64   TRUE,  /* FIELD_SENDER */
65   TRUE   /* FIELD_REPLY_SERIAL */
66 };
67
68 typedef struct
69 {
70   int offset; /**< Offset to start of field (location of name of field
71                * for named fields)
72                */
73 } HeaderField;
74
75 /**
76  * @brief Internals of DBusMessage
77  * 
78  * Object representing a message received from or to be sent to
79  * another application. This is an opaque object, all members
80  * are private.
81  */
82 struct DBusMessage
83 {
84   int refcount; /**< Reference count */
85
86   DBusString header; /**< Header network data, stored
87                       * separately from body so we can
88                       * independently realloc it.
89                       */
90
91   HeaderField header_fields[FIELD_LAST]; /**< Track the location
92                                            * of each field in "header"
93                                            */
94   
95   DBusString body;   /**< Body network data. */
96
97   char byte_order; /**< Message byte order. */
98
99   DBusCounter *size_counter; /**< Counter for the size of the message, or #NULL */
100   long size_counter_delta;   /**< Size we incremented the size counter by. */
101   
102   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
103 };
104
105 /**
106  * @brief Internals of DBusMessageIter
107  * 
108  * Object representing a position in a message. All fields are internal.
109  */
110 struct DBusMessageIter
111 {
112   int refcount; /**< Reference count */
113
114   int pos; /**< Current position in the string */
115   
116   DBusMessage *message; /**< Message used */
117 };
118
119 /**
120  * Gets the data to be sent over the network for this message.
121  * The header and then the body should be written out.
122  * This function is guaranteed to always return the same
123  * data once a message is locked (with _dbus_message_lock()).
124  *
125  * @param message the message.
126  * @param header return location for message header data.
127  * @param body return location for message body data.
128  */
129 void
130 _dbus_message_get_network_data (DBusMessage          *message,
131                                 const DBusString    **header,
132                                 const DBusString    **body)
133 {
134   _dbus_assert (message->locked);
135   
136   *header = &message->header;
137   *body = &message->body;
138 }
139
140 static void
141 adjust_field_offsets (DBusMessage *message,
142                       int          offsets_after,
143                       int          delta)
144 {
145   int i;
146
147   if (delta == 0)
148     return;
149   
150   i = 0;
151   while (i < FIELD_LAST)
152     {
153       if (message->header_fields[i].offset > offsets_after)
154         message->header_fields[i].offset += delta;
155
156       ++i;
157     }
158 }
159
160 static const char*
161 get_string_field (DBusMessage *message,
162                   int          field,
163                   int         *len)
164 {
165   int offset = message->header_fields[field].offset;
166   const char *data;
167   
168   if (offset < 0)
169     return NULL;
170
171   /* offset points to string length, string data follows it */
172   /* FIXME _dbus_demarshal_const_string() that returned
173    * a reference to the string plus its len might be nice.
174    */
175   
176   if (len)
177     *len = _dbus_demarshal_uint32 (&message->header,
178                                    message->byte_order,
179                                    offset,
180                                    NULL);
181
182   _dbus_string_get_const_data (&message->header,
183                                &data);
184   
185   return data + (offset + 4); 
186 }
187
188 static dbus_int32_t
189 get_int_field (DBusMessage *message,
190                      int          field)
191 {
192   int offset = message->header_fields[field].offset;
193   
194   if (offset < 0)
195     return -1; /* useless if -1 is a valid value of course */
196
197   return _dbus_demarshal_int32 (&message->header,
198                                 message->byte_order,
199                                 offset,
200                                 NULL);
201 }
202
203 static dbus_bool_t
204 append_int_field (DBusMessage *message,
205                   int          field,
206                   const char  *name,
207                   int          value)
208 {
209   int orig_len;
210
211   _dbus_assert (!message->locked);
212   
213   orig_len = _dbus_string_get_length (&message->header);
214   
215   if (!_dbus_string_align_length (&message->header, 4))
216     goto failed;  
217   
218   if (!_dbus_string_append_len (&message->header, name, 4))
219     goto failed;
220
221   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
222     goto failed;
223
224   if (!_dbus_string_align_length (&message->header, 4))
225     goto failed;
226   
227   message->header_fields[FIELD_REPLY_SERIAL].offset =
228     _dbus_string_get_length (&message->header);
229   
230   if (!_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER,
231                             value))
232     goto failed;
233
234   return TRUE;
235   
236  failed:
237   message->header_fields[field].offset = -1;
238   _dbus_string_set_length (&message->header, orig_len);
239   return FALSE;
240 }
241
242 static dbus_bool_t
243 append_string_field (DBusMessage *message,
244                      int          field,
245                      const char  *name,
246                      const char  *value)
247 {
248   int orig_len;
249
250   _dbus_assert (!message->locked);
251   
252   orig_len = _dbus_string_get_length (&message->header);
253
254   if (!_dbus_string_align_length (&message->header, 4))
255     goto failed;
256   
257   if (!_dbus_string_append_len (&message->header, name, 4))
258     goto failed;
259   
260   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
261     goto failed;
262
263   if (!_dbus_string_align_length (&message->header, 4))
264     goto failed;
265   
266   message->header_fields[field].offset =
267     _dbus_string_get_length (&message->header);
268   
269   if (!_dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER,
270                              value))
271     goto failed;
272
273   return TRUE;
274   
275  failed:
276   message->header_fields[field].offset = -1;
277   _dbus_string_set_length (&message->header, orig_len);
278   return FALSE;
279 }
280
281 static void
282 delete_int_field (DBusMessage *message,
283                   int          field)
284 {
285   int offset = message->header_fields[field].offset;
286
287   _dbus_assert (!message->locked);
288   _dbus_assert (field_is_named[field]);
289   
290   if (offset < 0)
291     return;  
292
293   /* The field typecode and name take up 8 bytes */
294   _dbus_string_delete (&message->header,
295                        offset - 8,
296                        12);
297
298   message->header_fields[field].offset = -1;
299   
300   adjust_field_offsets (message,
301                         offset - 8,
302                         - 12);
303 }
304
305 static void
306 delete_string_field (DBusMessage *message,
307                      int          field)
308 {
309   int offset = message->header_fields[field].offset;
310   int len;
311   int delete_len;
312   
313   _dbus_assert (!message->locked);
314   _dbus_assert (field_is_named[field]);
315   
316   if (offset < 0)
317     return;
318
319   get_string_field (message, field, &len);
320   
321   /* The field typecode and name take up 8 bytes, and the nul
322    * termination is 1 bytes, string length integer is 4 bytes
323    */
324   delete_len = 8 + 4 + 1 + len;
325   
326   _dbus_string_delete (&message->header,
327                        offset - 8,
328                        delete_len);
329
330   message->header_fields[field].offset = -1;
331   
332   adjust_field_offsets (message,
333                         offset - 8,
334                         - delete_len);
335 }
336
337 static dbus_bool_t
338 set_int_field (DBusMessage *message,
339                int          field,
340                int          value)
341 {
342   int offset = message->header_fields[field].offset;
343
344   _dbus_assert (!message->locked);
345   
346   if (offset < 0)
347     {
348       /* need to append the field */
349
350       switch (field)
351         {
352         case FIELD_REPLY_SERIAL:
353           return append_int_field (message, field,
354                                    DBUS_HEADER_FIELD_REPLY,
355                                    value);
356         default:
357           _dbus_assert_not_reached ("appending an int field we don't support appending");
358           return FALSE;
359         }
360     }
361   else
362     {
363       _dbus_marshal_set_int32 (&message->header,
364                                message->byte_order,
365                                offset, value);
366
367       return TRUE;
368     }
369 }
370
371 static dbus_bool_t
372 set_string_field (DBusMessage *message,
373                   int          field,
374                   const char  *value)
375 {
376   int offset = message->header_fields[field].offset;
377
378   _dbus_assert (!message->locked);
379   _dbus_assert (value != NULL);
380   
381   if (offset < 0)
382     {      
383       /* need to append the field */
384
385       switch (field)
386         {
387         case FIELD_SENDER:
388           return append_string_field (message, field,
389                                       DBUS_HEADER_FIELD_SENDER,
390                                       value);
391         default:
392           _dbus_assert_not_reached ("appending a string field we don't support appending");
393           return FALSE;
394         }
395     }
396   else
397     {
398       DBusString v;
399       int old_len;
400       int new_len;
401       
402       old_len = _dbus_string_get_length (&message->header);
403
404       _dbus_string_init_const_len (&v, value,
405                                    strlen (value) + 1); /* include nul */
406       if (!_dbus_marshal_set_string (&message->header,
407                                      message->byte_order,
408                                      offset, &v))
409         return FALSE;
410       
411       new_len = _dbus_string_get_length (&message->header);
412
413       adjust_field_offsets (message,
414                             offset,
415                             new_len - old_len);
416
417       return TRUE;
418     }
419 }
420
421 /**
422  * Sets the client serial of a message. 
423  * This can only be done once on a message.
424  *
425  * @todo client_serial should be called simply
426  * "serial"; it's in outgoing messages for both
427  * the client and the server, it's only client-specific
428  * in the message bus case. It's more like origin_serial
429  * or something.
430  * 
431  * @param message the message
432  * @param client_serial the client serial
433  */
434 void
435 _dbus_message_set_client_serial (DBusMessage  *message,
436                                  dbus_int32_t  client_serial)
437 {
438   _dbus_assert (!message->locked);
439   _dbus_assert (_dbus_message_get_client_serial (message) < 0);
440
441   set_int_field (message, FIELD_CLIENT_SERIAL,
442                  client_serial);
443 }
444
445 /**
446  * Sets the reply serial of a message (the client serial
447  * of the message this is a reply to).
448  *
449  * @param message the message
450  * @param reply_serial the client serial
451  * @returns #FALSE if not enough memory
452  */
453 dbus_bool_t
454 _dbus_message_set_reply_serial (DBusMessage  *message,
455                                 dbus_int32_t  reply_serial)
456 {
457   _dbus_assert (!message->locked);
458
459   return set_int_field (message, FIELD_REPLY_SERIAL,
460                         reply_serial);
461 }
462
463 /**
464  * Returns the client serial of a message or
465  * -1 if none has been specified.
466  *
467  * @todo see note in _dbus_message_set_client_serial()
468  * about how client_serial is a misnomer
469  *
470  * @todo this function should be public, after renaming it.
471  *
472  * @param message the message
473  * @returns the client serial
474  */
475 dbus_int32_t
476 _dbus_message_get_client_serial (DBusMessage *message)
477 {
478   return get_int_field (message, FIELD_CLIENT_SERIAL);
479 }
480
481 /**
482  * Returns the serial that the message is
483  * a reply to or -1 if none.
484  *
485  * @param message the message
486  * @returns the reply serial
487  */
488 dbus_int32_t
489 _dbus_message_get_reply_serial  (DBusMessage *message)
490 {
491   return get_int_field (message, FIELD_REPLY_SERIAL);
492 }
493
494 /**
495  * Adds a counter to be incremented immediately with the
496  * size of this message, and decremented by the size
497  * of this message when this message if finalized.
498  *
499  * @param message the message
500  * @param counter the counter
501  */
502 void
503 _dbus_message_add_size_counter (DBusMessage *message,
504                                 DBusCounter *counter)
505 {
506   _dbus_assert (message->size_counter == NULL); /* If this fails we may need to keep a list of
507                                                  * counters instead of just one
508                                                  */
509
510   message->size_counter = counter;
511   _dbus_counter_ref (message->size_counter);
512
513   /* When we can change message size, we may want to
514    * update this each time we do so, or we may want to
515    * just KISS like this.
516    */
517   message->size_counter_delta =
518     _dbus_string_get_length (&message->header) +
519     _dbus_string_get_length (&message->body);
520
521   _dbus_verbose ("message has size %ld\n",
522                  message->size_counter_delta);
523   
524   _dbus_counter_adjust (message->size_counter, message->size_counter_delta);
525 }
526
527 static dbus_bool_t
528 dbus_message_create_header (DBusMessage *message,
529                             const char  *service,
530                             const char  *name)
531 {
532   if (!_dbus_string_append_byte (&message->header, DBUS_COMPILER_BYTE_ORDER))
533     return FALSE;
534   
535   if (!_dbus_string_append_len (&message->header, "\0\0\0", 3))
536     return FALSE;
537
538   message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
539   if (!_dbus_marshal_int32 (&message->header, message->byte_order, 0))
540     return FALSE;
541
542   message->header_fields[FIELD_BODY_LENGTH].offset = 8;
543   if (!_dbus_marshal_int32 (&message->header, message->byte_order, 0))
544     return FALSE;
545
546   message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
547   if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
548     return FALSE;
549   
550   /* Marshal message service */
551   if (service != NULL)
552     {
553       if (!append_string_field (message,
554                                 FIELD_SERVICE,
555                                 DBUS_HEADER_FIELD_SERVICE,
556                                 service))
557         return FALSE;
558     }
559
560   _dbus_assert (name != NULL);
561   if (!append_string_field (message,
562                             FIELD_NAME,
563                             DBUS_HEADER_FIELD_NAME,
564                             name))
565     return FALSE;
566
567   return TRUE;
568 }
569
570 /**
571  * Locks a message. Allows checking that applications don't keep a
572  * reference to a message in the outgoing queue and change it
573  * underneath us. Messages are locked when they enter the outgoing
574  * queue (dbus_connection_send_message()), and the library complains
575  * if the message is modified while locked.
576  *
577  * @param message the message to lock.
578  */
579 void
580 _dbus_message_lock (DBusMessage  *message)
581 {
582   if (!message->locked)
583     {
584       /* Fill in our lengths */
585       set_int_field (message,
586                      FIELD_HEADER_LENGTH,
587                      _dbus_string_get_length (&message->header));
588
589       set_int_field (message,
590                      FIELD_BODY_LENGTH,
591                      _dbus_string_get_length (&message->body));
592
593       message->locked = TRUE;
594     }
595 }
596
597 /** @} */
598
599 /**
600  * @defgroup DBusMessage DBusMessage
601  * @ingroup  DBus
602  * @brief Message to be sent or received over a DBusConnection.
603  *
604  * A DBusMessage is the most basic unit of communication over a
605  * DBusConnection. A DBusConnection represents a stream of messages
606  * received from a remote application, and a stream of messages
607  * sent to a remote application.
608  *
609  * @{
610  */
611
612 /**
613  * @typedef DBusMessage
614  *
615  * Opaque data type representing a message received from or to be
616  * sent to another application.
617  */
618
619 static DBusMessage*
620 dbus_message_new_empty_header (void)
621 {
622   DBusMessage *message;
623   int i;
624   
625   message = dbus_new0 (DBusMessage, 1);
626   if (message == NULL)
627     return NULL;
628   
629   message->refcount = 1;
630   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
631   
632   i = 0;
633   while (i < FIELD_LAST)
634     {
635       message->header_fields[i].offset = -1;
636       ++i;
637     }
638   
639   if (!_dbus_string_init (&message->header, _DBUS_INT_MAX))
640     {
641       dbus_free (message);
642       return NULL;
643     }
644   
645   if (!_dbus_string_init (&message->body, _DBUS_INT_MAX))
646     {
647       _dbus_string_free (&message->header);
648       dbus_free (message);
649       return NULL;
650     }
651   
652   return message;
653 }
654
655
656 /**
657  * Constructs a new message. Returns #NULL if memory
658  * can't be allocated for the message.
659  *
660  * @todo use DBusString internally to store service and name.
661  *
662  * @param service service that the message should be sent to
663  * @param name name of the message
664  * @returns a new DBusMessage, free with dbus_message_unref()
665  * @see dbus_message_unref()
666  */
667 DBusMessage*
668 dbus_message_new (const char *service,
669                   const char *name)
670 {
671   DBusMessage *message;
672
673   message = dbus_message_new_empty_header ();
674   if (message == NULL)
675     return NULL;
676   
677   if (!dbus_message_create_header (message, service, name))
678     {
679       dbus_message_unref (message);
680       return NULL;
681     }
682   
683   return message;
684 }
685
686 /**
687  * Constructs a message that is a reply to some other
688  * message. Returns #NULL if memory can't be allocated
689  * for the message.
690  *
691  * @param name the name of the message
692  * @param original_message the message which the created
693  * message is a reply to.
694  * @returns a new DBusMessage, free with dbus_message_unref()
695  * @see dbus_message_new(), dbus_message_unref()
696  */ 
697 DBusMessage*
698 dbus_message_new_reply (const char  *name,
699                         DBusMessage *original_message)
700 {
701   DBusMessage *message;
702   const char *sender;
703
704   sender = get_string_field (original_message,
705                              FIELD_SENDER, NULL);
706
707   _dbus_assert (sender != NULL);
708   
709   message = dbus_message_new (sender, name);
710   
711   if (message == NULL)
712     return NULL;
713
714   if (!_dbus_message_set_reply_serial (message,
715                                        _dbus_message_get_client_serial (original_message)))
716     {
717       dbus_message_unref (message);
718       return NULL;
719     }
720
721   return message;
722 }
723
724 DBusMessage *
725 dbus_message_new_from_message (const DBusMessage *message)
726 {
727   DBusMessage *retval;
728   int i;
729   
730   retval = dbus_new0 (DBusMessage, 1);
731   if (retval == NULL)
732     return NULL;
733   
734   retval->refcount = 1;
735   retval->byte_order = message->byte_order;
736
737   if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
738     {
739       dbus_free (retval);
740       return NULL;
741     }
742   
743   if (!_dbus_string_init (&retval->body, _DBUS_INT_MAX))
744     {
745       _dbus_string_free (&retval->header);
746       dbus_free (retval);
747       return NULL;
748     }
749
750   if (!_dbus_string_copy (&message->header, 0,
751                           &retval->header, 0))
752     {
753       _dbus_string_free (&retval->header);
754       _dbus_string_free (&retval->body);
755       dbus_free (retval);
756
757       return NULL;
758     }
759
760   if (!_dbus_string_copy (&message->body, 0,
761                           &retval->body, 0))
762     {
763       _dbus_string_free (&retval->header);
764       _dbus_string_free (&retval->body);
765       dbus_free (retval);
766
767       return NULL;
768     }
769
770   for (i = 0; i < FIELD_LAST; i++)
771     {
772       retval->header_fields[i].offset = message->header_fields[i].offset;
773     }
774   
775   return retval;
776 }
777
778
779 /**
780  * Increments the reference count of a DBusMessage.
781  *
782  * @param message The message
783  * @see dbus_message_unref
784  */
785 void
786 dbus_message_ref (DBusMessage *message)
787 {
788   _dbus_assert (message->refcount > 0);
789   
790   message->refcount += 1;
791 }
792
793 /**
794  * Decrements the reference count of a DBusMessage.
795  *
796  * @param message The message
797  * @see dbus_message_ref
798  */
799 void
800 dbus_message_unref (DBusMessage *message)
801 {
802   _dbus_assert (message->refcount > 0);
803
804   message->refcount -= 1;
805   if (message->refcount == 0)
806     {
807       if (message->size_counter != NULL)
808         {
809           _dbus_counter_adjust (message->size_counter,
810                                 - message->size_counter_delta);
811           _dbus_counter_unref (message->size_counter);
812         }
813       
814       _dbus_string_free (&message->header);
815       _dbus_string_free (&message->body);
816       
817       dbus_free (message);
818     }
819 }
820
821 /**
822  * Gets the name of a message.
823  *
824  * @param message the message
825  * @returns the message name (should not be freed)
826  */
827 const char*
828 dbus_message_get_name (DBusMessage *message)
829 {
830   return get_string_field (message, FIELD_NAME, NULL);
831 }
832
833 /**
834  * Gets the destination service of a message.
835  *
836  * @param message the message
837  * @returns the message destination service (should not be freed)
838  */
839 const char*
840 dbus_message_get_service (DBusMessage *message)
841 {
842   return get_string_field (message, FIELD_SERVICE, NULL);
843 }
844
845 /**
846  * Appends fields to a message given a variable argument
847  * list. The variable argument list should contain the type
848  * of the field followed by the value to add.
849  * The list is terminated with 0.
850  *
851  * @param message the message
852  * @param first_field_type type of the first field
853  * @param ... value of first field, list of additional type-value pairs
854  * @returns #TRUE on success
855  */
856 dbus_bool_t
857 dbus_message_append_fields (DBusMessage *message,
858                             int first_field_type,
859                             ...)
860 {
861   dbus_bool_t retval;
862   va_list var_args;
863
864   va_start (var_args, first_field_type);
865   retval = dbus_message_append_fields_valist (message,
866                                               first_field_type,
867                                               var_args);
868   va_end (var_args);
869
870   return retval;
871 }
872
873 /**
874  * This function takes a va_list for use by language bindings
875  *
876  * @see dbus_message_append_fields.  
877  * @param message the message
878  * @param first_field_type type of first field
879  * @param var_args value of first field, then list of type/value pairs
880  * @returns #TRUE on success
881  */
882 dbus_bool_t
883 dbus_message_append_fields_valist (DBusMessage *message,
884                                    int          first_field_type,
885                                    va_list      var_args)
886 {
887   int type, old_len;
888
889   old_len = _dbus_string_get_length (&message->body);
890   
891   type = first_field_type;
892
893   while (type != 0)
894     {
895       switch (type)
896         {
897         case DBUS_TYPE_INT32:
898           if (!dbus_message_append_int32 (message, va_arg (var_args, dbus_int32_t)))
899             goto enomem;
900           break;
901         case DBUS_TYPE_UINT32:
902           if (!dbus_message_append_uint32 (message, va_arg (var_args, dbus_uint32_t)))
903             goto enomem;            
904           break;
905         case DBUS_TYPE_DOUBLE:
906           if (!dbus_message_append_double (message, va_arg (var_args, double)))
907             goto enomem;
908           break;
909         case DBUS_TYPE_STRING:
910           if (!dbus_message_append_string (message, va_arg (var_args, const char *)))
911             goto enomem;
912           break;
913         case DBUS_TYPE_BYTE_ARRAY:
914           {
915             int len;
916             unsigned char *data;
917
918             data = va_arg (var_args, unsigned char *);
919             len = va_arg (var_args, int);
920
921             if (!dbus_message_append_byte_array (message, data, len))
922               goto enomem;
923           }
924           break;
925         case DBUS_TYPE_STRING_ARRAY:
926           {
927             int len;
928             const char **data;
929             
930             data = va_arg (var_args, const char **);
931             len = va_arg (var_args, int);
932
933             if (!dbus_message_append_string_array (message, data, len))
934               goto enomem;
935           }
936           break;
937           
938         default:
939           _dbus_warn ("Unknown field type %d\n", type);
940         }
941
942       type = va_arg (var_args, int);
943     }
944
945   return TRUE;
946
947  enomem:
948   _dbus_string_set_length (&message->body, old_len);
949   return FALSE;
950 }
951
952 /**
953  * Appends a 32 bit signed integer to the message.
954  *
955  * @param message the message
956  * @param value the integer value
957  * @returns #TRUE on success
958  */
959 dbus_bool_t
960 dbus_message_append_int32 (DBusMessage  *message,
961                            dbus_int32_t  value)
962 {
963   _dbus_assert (!message->locked);
964
965   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
966     {
967       _dbus_string_shorten (&message->body, 1);
968       return FALSE;
969     }
970   
971   return _dbus_marshal_int32 (&message->body,
972                               DBUS_COMPILER_BYTE_ORDER, value);
973 }
974
975 /**
976  * Appends a 32 bit unsigned integer to the message.
977  *
978  * @param message the message
979  * @param value the integer value
980  * @returns #TRUE on success
981  */
982 dbus_bool_t
983 dbus_message_append_uint32 (DBusMessage   *message,
984                             dbus_uint32_t  value)
985 {
986   _dbus_assert (!message->locked);
987
988   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UINT32))
989     {
990       _dbus_string_shorten (&message->body, 1);
991       return FALSE;
992     }
993   
994   return _dbus_marshal_uint32 (&message->body,
995                                DBUS_COMPILER_BYTE_ORDER, value);
996 }
997
998 /**
999  * Appends a double value to the message.
1000  *
1001  * @param message the message
1002  * @param value the double value
1003  * @returns #TRUE on success
1004  */
1005 dbus_bool_t
1006 dbus_message_append_double (DBusMessage *message,
1007                             double       value)
1008 {
1009   _dbus_assert (!message->locked);
1010
1011   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_DOUBLE))
1012     {
1013       _dbus_string_shorten (&message->body, 1);
1014       return FALSE;
1015     }
1016   
1017   return _dbus_marshal_double (&message->body,
1018                                DBUS_COMPILER_BYTE_ORDER, value);
1019 }
1020
1021 /**
1022  * Appends a UTF-8 string to the message.
1023  *
1024  * @param message the message
1025  * @param value the string
1026  * @returns #TRUE on success
1027  */
1028 dbus_bool_t
1029 dbus_message_append_string (DBusMessage *message,
1030                             const char  *value)
1031 {
1032   _dbus_assert (!message->locked);
1033
1034   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING))
1035     {
1036       _dbus_string_shorten (&message->body, 1);
1037       return FALSE;
1038     }
1039   
1040   return _dbus_marshal_string (&message->body,
1041                                DBUS_COMPILER_BYTE_ORDER, value);
1042 }
1043
1044 /**
1045  * Appends a byte array to the message.
1046  *
1047  * @param message the message
1048  * @param value the array
1049  * @param len the length of the array
1050  * @returns #TRUE on success
1051  */
1052 dbus_bool_t
1053 dbus_message_append_byte_array (DBusMessage         *message,
1054                                 unsigned const char *value,
1055                                 int                 len)
1056 {
1057   _dbus_assert (!message->locked);
1058
1059   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_BYTE_ARRAY))
1060     {
1061       _dbus_string_shorten (&message->body, 1);
1062       return FALSE;
1063     }
1064   
1065   return _dbus_marshal_byte_array (&message->body,
1066                                    DBUS_COMPILER_BYTE_ORDER, value, len);
1067 }
1068
1069 /**
1070  * Appends a string array to the message.
1071  *
1072  * @param message the message
1073  * @param value the array
1074  * @param len the length of the array
1075  * @returns #TRUE on success
1076  */
1077 dbus_bool_t
1078 dbus_message_append_string_array (DBusMessage *message,
1079                                   const char **value,
1080                                   int          len)
1081 {
1082   _dbus_assert (!message->locked);
1083
1084   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING_ARRAY))
1085     {
1086       _dbus_string_shorten (&message->body, 1);
1087       return FALSE;
1088     }
1089   
1090   return _dbus_marshal_string_array (&message->body,
1091                                      DBUS_COMPILER_BYTE_ORDER, value, len);
1092 }
1093
1094 /**
1095  * Gets fields from a message given a variable argument list.
1096  * The variable argument list should contain the type of the
1097  * field followed by a pointer to where the value should be
1098  * stored. The list is terminated with 0.
1099  *
1100  *  @todo rename get_args to avoid confusion with header fields
1101  * 
1102  * @param message the message
1103  * @param first_field_type the first field type
1104  * @param ... location for first field value, then list of type-location pairs
1105  * @returns result code
1106  */
1107 DBusResultCode
1108 dbus_message_get_fields (DBusMessage *message,
1109                          int          first_field_type,
1110                          ...)
1111 {
1112   DBusResultCode retval;
1113   va_list var_args;
1114
1115   va_start (var_args, first_field_type);
1116   retval = dbus_message_get_fields_valist (message, first_field_type, var_args);
1117   va_end (var_args);
1118
1119   return retval;
1120 }
1121
1122 /**
1123  * This function takes a va_list for use by language bindings
1124  *
1125  * @todo this function (or some lower-level non-convenience function)
1126  * needs better error handling; should allow the application to
1127  * distinguish between out of memory, and bad data from the remote
1128  * app. It also needs to not leak a bunch of args when it gets
1129  * to the arg that's bad, as that would be a security hole
1130  * (allow one app to force another to leak memory)
1131  *
1132  * @todo We need to free the field data when an error occurs.
1133  *
1134  * @todo rename get_args_valist to avoid confusion with header fields
1135  *
1136  * @see dbus_message_get_fields
1137  * @param message the message
1138  * @param first_field_type type of the first field
1139  * @param var_args return location for first field, followed by list of type/location pairs
1140  * @returns result code
1141  */
1142 DBusResultCode
1143 dbus_message_get_fields_valist (DBusMessage *message,
1144                                 int          first_field_type,
1145                                 va_list      var_args)
1146 {
1147   int spec_type, msg_type, i;
1148   DBusMessageIter *iter;
1149
1150   iter = dbus_message_get_fields_iter (message);
1151
1152   if (iter == NULL)
1153     return DBUS_RESULT_NO_MEMORY;
1154   
1155   spec_type = first_field_type;
1156   i = 0;
1157   
1158   while (spec_type != 0)
1159     {
1160       msg_type = dbus_message_iter_get_field_type (iter);      
1161       
1162       if (msg_type != spec_type)
1163         {
1164           _dbus_verbose ("Field %d is specified to be of type \"%s\", but "
1165                          "is actually of type \"%s\"\n", i,
1166                          _dbus_type_to_string (spec_type),
1167                          _dbus_type_to_string (msg_type));
1168           dbus_message_iter_unref (iter);
1169
1170           return DBUS_RESULT_INVALID_FIELDS;
1171         }
1172
1173       switch (spec_type)
1174         {
1175         case DBUS_TYPE_INT32:
1176           {
1177             dbus_int32_t *ptr;
1178
1179             ptr = va_arg (var_args, dbus_int32_t *);
1180
1181             *ptr = dbus_message_iter_get_int32 (iter);
1182             break;
1183           }
1184         case DBUS_TYPE_UINT32:
1185           {
1186             dbus_uint32_t *ptr;
1187
1188             ptr = va_arg (var_args, dbus_uint32_t *);
1189
1190             *ptr = dbus_message_iter_get_uint32 (iter);
1191             break;
1192           }
1193
1194         case DBUS_TYPE_DOUBLE:
1195           {
1196             double *ptr;
1197
1198             ptr = va_arg (var_args, double *);
1199
1200             *ptr = dbus_message_iter_get_double (iter);
1201             break;
1202           }
1203
1204         case DBUS_TYPE_STRING:
1205           {
1206             char **ptr;
1207
1208             ptr = va_arg (var_args, char **);
1209
1210             *ptr = dbus_message_iter_get_string (iter);
1211
1212             if (!*ptr)
1213               return DBUS_RESULT_NO_MEMORY;
1214             
1215             break;
1216           }
1217
1218         case DBUS_TYPE_BYTE_ARRAY:
1219           {
1220             unsigned char **ptr;
1221             int *len;
1222
1223             ptr = va_arg (var_args, unsigned char **);
1224             len = va_arg (var_args, int *);
1225
1226             *ptr = dbus_message_iter_get_byte_array (iter, len);
1227
1228             if (!*ptr)
1229               return DBUS_RESULT_NO_MEMORY;
1230             
1231             break;
1232           }
1233         case DBUS_TYPE_STRING_ARRAY:
1234           {
1235             char ***ptr;
1236             int *len;
1237
1238             ptr = va_arg (var_args, char ***);
1239             len = va_arg (var_args, int *);
1240
1241             *ptr = dbus_message_iter_get_string_array (iter, len);
1242             
1243             if (!*ptr)
1244               return DBUS_RESULT_NO_MEMORY;
1245             
1246             break;
1247           }
1248         default:          
1249           _dbus_warn ("Unknown field type %d\n", spec_type);
1250         }
1251       
1252       spec_type = va_arg (var_args, int);
1253       if (spec_type != 0 && !dbus_message_iter_next (iter))
1254         {
1255           _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n");
1256
1257           dbus_message_iter_unref (iter);  
1258           return DBUS_RESULT_INVALID_FIELDS;
1259         }
1260       i++;
1261     }
1262
1263   dbus_message_iter_unref (iter);
1264   return DBUS_RESULT_SUCCESS;
1265 }
1266
1267 /**
1268  * Returns a DBusMessageIter representing the fields of the
1269  * message passed in.
1270  *
1271  * @todo IMO the message iter should follow the GtkTextIter pattern,
1272  * a static object with a "stamp" value used to detect invalid
1273  * iter uses (uninitialized or after changing the message).
1274  * ref/unref is kind of annoying to deal with, and slower too.
1275  * This implies not ref'ing the message from the iter.
1276  *
1277  * @todo rename get_args_iter to avoid confusion with header fields
1278  * 
1279  * @param message the message
1280  * @returns a new iter.
1281  */
1282 DBusMessageIter *
1283 dbus_message_get_fields_iter (DBusMessage *message)
1284 {
1285   DBusMessageIter *iter;
1286   
1287   iter = dbus_new (DBusMessageIter, 1);
1288
1289   dbus_message_ref (message);
1290   
1291   iter->refcount = 1;
1292   iter->message = message;
1293   iter->pos = 0;
1294
1295   return iter;
1296 }
1297
1298 /**
1299  * Increments the reference count of a DBusMessageIter.
1300  *
1301  * @param iter the message iter
1302  * @see dbus_message_iter_unref
1303  */
1304 void
1305 dbus_message_iter_ref (DBusMessageIter *iter)
1306 {
1307   _dbus_assert (iter->refcount > 0);
1308   
1309   iter->refcount += 1;
1310 }
1311
1312 /**
1313  * Decrements the reference count of a DBusMessageIter.
1314  *
1315  * @param iter The message iter
1316  * @see dbus_message_iter_ref
1317  */
1318 void
1319 dbus_message_iter_unref (DBusMessageIter *iter)
1320 {
1321   _dbus_assert (iter->refcount > 0);
1322
1323   iter->refcount -= 1;
1324
1325   if (iter->refcount == 0)
1326     {
1327       dbus_message_unref (iter->message);
1328
1329       dbus_free (iter);
1330     }
1331 }
1332
1333 /**
1334  * Checks if an iterator has any more fields.
1335  *
1336  * @param iter the message iter
1337  * @returns #TRUE if there are more fields
1338  * following
1339  */
1340 dbus_bool_t
1341 dbus_message_iter_has_next (DBusMessageIter *iter)
1342 {
1343   int end_pos;
1344   
1345   if (!_dbus_marshal_get_field_end_pos (&iter->message->body,
1346                                         iter->message->byte_order,
1347                                         iter->pos, &end_pos))
1348     return FALSE;
1349   
1350   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1351     return FALSE;
1352   
1353   return TRUE;  
1354 }
1355
1356 /**
1357  * Moves the iterator to the next field.
1358  *
1359  * @param iter The message iter
1360  * @returns #TRUE if the iterator was moved to the next field
1361  */
1362 dbus_bool_t
1363 dbus_message_iter_next (DBusMessageIter *iter)
1364 {
1365   int end_pos;
1366   
1367   if (!_dbus_marshal_get_field_end_pos (&iter->message->body, iter->message->byte_order,
1368                                         iter->pos, &end_pos))
1369     return FALSE;
1370
1371   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1372     return FALSE;
1373
1374   iter->pos = end_pos;
1375
1376   return TRUE;
1377 }
1378
1379 /**
1380  * Returns the field type of the field that the
1381  * message iterator points at.
1382  *
1383  * @param iter the message iter
1384  * @returns the field type
1385  */
1386 int
1387 dbus_message_iter_get_field_type (DBusMessageIter *iter)
1388 {
1389   const char *data;
1390
1391   if (iter->pos >= _dbus_string_get_length (&iter->message->body))
1392     return DBUS_TYPE_INVALID;
1393
1394   _dbus_string_get_const_data_len (&iter->message->body, &data, iter->pos, 1);
1395
1396   if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_STRING_ARRAY)
1397     return *data;
1398
1399   return DBUS_TYPE_INVALID;
1400 }
1401
1402 /**
1403  * Returns the string value that an iterator may point to.
1404  * Note that you need to check that the iterator points to
1405  * a string value before using this function.
1406  *
1407  * @see dbus_message_iter_get_field_type
1408  * @param iter the message iter
1409  * @returns the string
1410  */
1411 char *
1412 dbus_message_iter_get_string (DBusMessageIter *iter)
1413 {
1414   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING);
1415
1416   return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
1417                                  iter->pos + 1, NULL);
1418 }
1419
1420 /**
1421  * Returns the 32 bit signed integer value that an iterator may point to.
1422  * Note that you need to check that the iterator points to
1423  * a string value before using this function.
1424  *
1425  * @see dbus_message_iter_get_field_type
1426  * @param iter the message iter
1427  * @returns the integer
1428  */
1429 int
1430 dbus_message_iter_get_int32 (DBusMessageIter *iter)
1431 {
1432   return _dbus_demarshal_int32 (&iter->message->body, iter->message->byte_order,
1433                                 iter->pos + 1, NULL);
1434 }
1435
1436 /**
1437  * Returns the 32 bit unsigned integer value that an iterator may point to.
1438  * Note that you need to check that the iterator points to
1439  * a string value before using this function.
1440  *
1441  * @see dbus_message_iter_get_field_type
1442  * @param iter the message iter
1443  * @returns the integer
1444  */
1445 int
1446 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
1447 {
1448   return _dbus_demarshal_uint32 (&iter->message->body, iter->message->byte_order,
1449                                  iter->pos + 1, NULL);
1450 }
1451
1452 /**
1453  * Returns the double value that an iterator may point to.
1454  * Note that you need to check that the iterator points to
1455  * a string value before using this function.
1456  *
1457  * @see dbus_message_iter_get_field_type
1458  * @param iter the message iter
1459  * @returns the double
1460  */
1461 double
1462 dbus_message_iter_get_double (DBusMessageIter *iter)
1463 {
1464   return _dbus_demarshal_double (&iter->message->body, iter->message->byte_order,
1465                                  iter->pos + 1, NULL);
1466 }
1467
1468 /**
1469  * Returns the byte array that the iterator may point to.
1470  * Note that you need to check that the iterator points
1471  * to a byte array prior to using this function.
1472  *
1473  * @todo this function should probably take "unsigned char **" as
1474  * an out param argument, and return boolean or result code.
1475  *
1476  * @param iter the iterator
1477  * @param len return location for length of byte array
1478  * @returns the byte array
1479  */
1480 unsigned char *
1481 dbus_message_iter_get_byte_array (DBusMessageIter *iter,
1482                                   int             *len)
1483 {
1484   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_BYTE_ARRAY);
1485
1486   return _dbus_demarshal_byte_array (&iter->message->body, iter->message->byte_order,
1487                                      iter->pos + 1, NULL, len);
1488 }
1489
1490 /**
1491  * Returns the string array that the iterator may point to.
1492  * Note that you need to check that the iterator points
1493  * to a byte array prior to using this function.
1494  *
1495  * @todo this function should probably take "char **" as
1496  * an out param argument, and return boolean or result code.
1497  *
1498  * @param iter the iterator
1499  * @param len return location for length of byte array
1500  * @returns the byte array
1501  */
1502 char **
1503 dbus_message_iter_get_string_array (DBusMessageIter *iter,
1504                                     int             *len)
1505 {
1506   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING_ARRAY);
1507
1508   return _dbus_demarshal_string_array (&iter->message->body, iter->message->byte_order,
1509                                        iter->pos + 1, NULL, len);
1510 }
1511
1512 /**
1513  * Sets the message sender.
1514  *
1515  * @todo implement #NULL sender to unset
1516  *
1517  * @param message the message
1518  * @param sender the sender
1519  * @returns #FALSE if not enough memory
1520  */
1521 dbus_bool_t
1522 dbus_message_set_sender (DBusMessage  *message,
1523                          const char   *sender)
1524 {
1525   _dbus_assert (!message->locked);
1526
1527   if (sender == NULL)
1528     {
1529       delete_string_field (message, FIELD_SENDER);
1530       return TRUE;
1531     }
1532   else
1533     {
1534       return set_string_field (message,
1535                                FIELD_SENDER,
1536                                sender);
1537     }
1538 }
1539
1540 /**
1541  * Gets the service which originated this message,
1542  * or #NULL if unknown or inapplicable.
1543  *
1544  * @param message the message
1545  * @returns the service name or #NULL
1546  */
1547 const char*
1548 dbus_message_get_sender (DBusMessage *message)
1549 {
1550   return get_string_field (message, FIELD_SENDER, NULL);
1551 }
1552
1553 /** @} */
1554
1555 /**
1556  * @addtogroup DBusMessageInternals
1557  *
1558  * @{
1559  */
1560 /**
1561  * @typedef DBusMessageLoader
1562  *
1563  * The DBusMessageLoader object encapsulates the process of converting
1564  * a byte stream into a series of DBusMessage. It buffers the incoming
1565  * bytes as efficiently as possible, and generates a queue of
1566  * messages. DBusMessageLoader is typically used as part of a
1567  * DBusTransport implementation. The DBusTransport then hands off
1568  * the loaded messages to a DBusConnection, making the messages
1569  * visible to the application.
1570  * 
1571  */
1572
1573 /**
1574  * Implementation details of DBusMessageLoader.
1575  * All members are private.
1576  */
1577 struct DBusMessageLoader
1578 {
1579   int refcount;        /**< Reference count. */
1580
1581   DBusString data;     /**< Buffered data */
1582   
1583   DBusList *messages;  /**< Complete messages. */
1584
1585   long max_message_size; /**< Maximum size of a message */
1586   
1587   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
1588
1589   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
1590 };
1591
1592 /**
1593  * The initial buffer size of the message loader.
1594  * 
1595  * @todo this should be based on min header size plus some average
1596  * body size, or something. Or rather, the min header size only, if we
1597  * want to try to read only the header, store that in a DBusMessage,
1598  * then read only the body and store that, etc., depends on
1599  * how we optimize _dbus_message_loader_get_buffer() and what
1600  * the exact message format is.
1601  */
1602 #define INITIAL_LOADER_DATA_LEN 32
1603
1604 /**
1605  * Creates a new message loader. Returns #NULL if memory can't
1606  * be allocated.
1607  *
1608  * @returns new loader, or #NULL.
1609  */
1610 DBusMessageLoader*
1611 _dbus_message_loader_new (void)
1612 {
1613   DBusMessageLoader *loader;
1614
1615   loader = dbus_new0 (DBusMessageLoader, 1);
1616   if (loader == NULL)
1617     return NULL;
1618   
1619   loader->refcount = 1;
1620
1621   /* Try to cap message size at something that won't *totally* hose
1622    * the system if we have a couple of them.
1623    */
1624   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
1625   
1626   if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX))
1627     {
1628       dbus_free (loader);
1629       return NULL;
1630     }
1631
1632   /* preallocate the buffer for speed, ignore failure */
1633   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
1634   _dbus_string_set_length (&loader->data, 0);
1635   
1636   return loader;
1637 }
1638
1639 /**
1640  * Increments the reference count of the loader.
1641  *
1642  * @param loader the loader.
1643  */
1644 void
1645 _dbus_message_loader_ref (DBusMessageLoader *loader)
1646 {
1647   loader->refcount += 1;
1648 }
1649
1650 /**
1651  * Decrements the reference count of the loader and finalizes the
1652  * loader when the count reaches zero.
1653  *
1654  * @param loader the loader.
1655  */
1656 void
1657 _dbus_message_loader_unref (DBusMessageLoader *loader)
1658 {
1659   loader->refcount -= 1;
1660   if (loader->refcount == 0)
1661     {
1662       _dbus_list_foreach (&loader->messages,
1663                           (DBusForeachFunction) dbus_message_unref,
1664                           NULL);
1665       _dbus_list_clear (&loader->messages);
1666       _dbus_string_free (&loader->data);
1667       dbus_free (loader);
1668     }
1669 }
1670
1671 /**
1672  * Gets the buffer to use for reading data from the network.  Network
1673  * data is read directly into an allocated buffer, which is then used
1674  * in the DBusMessage, to avoid as many extra memcpy's as possible.
1675  * The buffer must always be returned immediately using
1676  * _dbus_message_loader_return_buffer(), even if no bytes are
1677  * successfully read.
1678  *
1679  * @todo this function can be a lot more clever. For example
1680  * it can probably always return a buffer size to read exactly
1681  * the body of the next message, thus avoiding any memory wastage
1682  * or reallocs.
1683  * 
1684  * @param loader the message loader.
1685  * @param buffer the buffer
1686  */
1687 void
1688 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
1689                                  DBusString        **buffer)
1690 {
1691   _dbus_assert (!loader->buffer_outstanding);
1692
1693   *buffer = &loader->data;
1694   
1695   loader->buffer_outstanding = TRUE;
1696 }
1697
1698 /**
1699  * The smallest header size that can occur. 
1700  * (It won't be valid)
1701  */
1702 #define DBUS_MINIMUM_HEADER_SIZE 16
1703
1704 /** Pack four characters as in "abcd" into a uint32 */
1705 #define FOUR_CHARS_TO_UINT32(a, b, c, d)                \
1706                       ((((dbus_uint32_t)a) << 24) |     \
1707                        (((dbus_uint32_t)b) << 16) |     \
1708                        (((dbus_uint32_t)c) << 8)  |     \
1709                        ((dbus_uint32_t)d))
1710
1711 /** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
1712 #define DBUS_HEADER_FIELD_NAME_AS_UINT32    \
1713   FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
1714
1715 /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
1716 #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
1717   FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
1718
1719 /** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
1720 #define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \
1721   FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
1722
1723 /** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
1724 #define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \
1725   FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
1726
1727
1728 /* FIXME should be using DBusString for the stuff we demarshal.  char*
1729  * evil. Also, out of memory handling here seems suboptimal.
1730  * Should probably report it as a distinct error from "corrupt message,"
1731  * so we can postpone parsing this message. Also, we aren't
1732  * checking for demarshal failure everywhere.
1733  */
1734 static dbus_bool_t
1735 decode_header_data (DBusString   *data,
1736                     int           header_len,
1737                     int           byte_order,
1738                     HeaderField   fields[FIELD_LAST])
1739 {
1740   const char *field;
1741   int pos, new_pos;
1742   int i;
1743   
1744   if (header_len < 16)
1745     return FALSE;
1746
1747   i = 0;
1748   while (i < FIELD_LAST)
1749     {
1750       fields[i].offset = -1;
1751       ++i;
1752     }
1753   
1754   fields[FIELD_HEADER_LENGTH].offset = 4;
1755   fields[FIELD_BODY_LENGTH].offset = 8;   
1756   fields[FIELD_CLIENT_SERIAL].offset = 12;
1757   
1758   /* Now handle the fields */
1759   pos = 16;
1760   while (pos < header_len)
1761     {
1762       pos = _DBUS_ALIGN_VALUE (pos, 4);
1763       
1764       if ((pos + 4) > header_len)
1765         return FALSE;      
1766       
1767       _dbus_string_get_const_data_len (data, &field, pos, 4);
1768       pos += 4;
1769
1770       _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
1771
1772       /* I believe FROM_BE is right, but if not we'll find out
1773        * I guess. ;-)
1774        */
1775       switch (DBUS_UINT32_FROM_BE (*(int*)field))
1776         {
1777         case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
1778           if (fields[FIELD_SERVICE].offset >= 0)
1779             {
1780               _dbus_verbose ("%s field provided twice\n",
1781                              DBUS_HEADER_FIELD_SERVICE);
1782               return FALSE;
1783             }
1784           
1785           fields[FIELD_SERVICE].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1786           _dbus_verbose ("Found service name at offset %d\n",
1787                          fields[FIELD_SERVICE].offset);
1788           break;
1789
1790         case DBUS_HEADER_FIELD_NAME_AS_UINT32:
1791           if (fields[FIELD_NAME].offset >= 0)
1792             {
1793               _dbus_verbose ("%s field provided twice\n",
1794                              DBUS_HEADER_FIELD_NAME);
1795               return FALSE;
1796             }
1797           
1798           fields[FIELD_NAME].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1799
1800           _dbus_verbose ("Found message name at offset %d\n",
1801                          fields[FIELD_NAME].offset);
1802           break;
1803         case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
1804           if (fields[FIELD_SENDER].offset >= 0)
1805             {
1806               _dbus_verbose ("%s field provided twice\n",
1807                              DBUS_HEADER_FIELD_SENDER);
1808               return FALSE;
1809             }
1810           
1811           fields[FIELD_SENDER].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1812
1813           _dbus_verbose ("Found sender name at offset %d\n",
1814                          fields[FIELD_NAME].offset);
1815           break;
1816           
1817         case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
1818           if (fields[FIELD_REPLY_SERIAL].offset >= 0)
1819             {
1820               _dbus_verbose ("%s field provided twice\n",
1821                              DBUS_HEADER_FIELD_REPLY);
1822               return FALSE;
1823             }
1824           
1825           fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1826
1827           _dbus_verbose ("Found reply serial at offset %d\n",
1828                          fields[FIELD_REPLY_SERIAL].offset);
1829           break;
1830
1831         default:
1832           _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n",
1833                          field[0], field[1], field[2], field[3]);
1834         }
1835
1836       /* This function has to validate the fields */
1837       if (!_dbus_marshal_get_field_end_pos (data, byte_order, pos, &new_pos))
1838         return FALSE;
1839
1840       if (new_pos > header_len)
1841         return FALSE;
1842       
1843       pos = new_pos;
1844     }
1845   
1846   return TRUE;
1847 }
1848
1849 /**
1850  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
1851  * indicating to the loader how many bytes of the buffer were filled
1852  * in. This function must always be called, even if no bytes were
1853  * successfully read.
1854  *
1855  * @param loader the loader.
1856  * @param buffer the buffer.
1857  * @param bytes_read number of bytes that were read into the buffer.
1858  */
1859 void
1860 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
1861                                     DBusString         *buffer,
1862                                     int                 bytes_read)
1863 {
1864   _dbus_assert (loader->buffer_outstanding);
1865   _dbus_assert (buffer == &loader->data);
1866
1867   loader->buffer_outstanding = FALSE;
1868
1869   if (loader->corrupted)
1870     return;
1871
1872   while (_dbus_string_get_length (&loader->data) >= 16)
1873     {
1874       DBusMessage *message;      
1875       const char *header_data;
1876       int byte_order, header_len, body_len;
1877       
1878       _dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
1879
1880       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
1881       
1882       byte_order = header_data[0];
1883
1884       if (byte_order != DBUS_LITTLE_ENDIAN &&
1885           byte_order != DBUS_BIG_ENDIAN)
1886         {
1887           _dbus_verbose ("Message with bad byte order '%c' received\n",
1888                          byte_order);
1889           loader->corrupted = TRUE;
1890           return;
1891         }
1892
1893       header_len = _dbus_unpack_int32 (byte_order, header_data + 4);
1894       body_len = _dbus_unpack_int32 (byte_order, header_data + 8);
1895
1896       if (header_len + body_len > loader->max_message_size)
1897         {
1898           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
1899                          header_len, body_len, loader->max_message_size);
1900           loader->corrupted = TRUE;
1901           return;
1902         }
1903
1904       if (_dbus_string_get_length (&loader->data) >= header_len + body_len)
1905         {
1906           HeaderField fields[FIELD_LAST];
1907           int i;
1908           
1909           /* FIXME right now if this doesn't have enough memory, the
1910            * loader becomes corrupted. Instead we should just not
1911            * parse this message for now.
1912            */
1913           if (!decode_header_data (&loader->data, header_len, byte_order,
1914                                    fields))
1915             {
1916               loader->corrupted = TRUE;
1917               return;
1918             }
1919
1920           message = dbus_message_new_empty_header ();
1921           if (message == NULL)
1922             break; /* ugh, postpone this I guess. */
1923
1924           /* Copy in the offsets we found */
1925           i = 0;
1926           while (i < FIELD_LAST)
1927             {
1928               message->header_fields[i] = fields[i];
1929               ++i;
1930             }
1931           
1932           if (!_dbus_list_append (&loader->messages, message))
1933             {
1934               dbus_message_unref (message);
1935               break;
1936             }
1937
1938           _dbus_assert (_dbus_string_get_length (&message->header) == 0);
1939           _dbus_assert (_dbus_string_get_length (&message->body) == 0);
1940
1941           _dbus_assert (_dbus_string_get_length (&loader->data) >=
1942                         (header_len + body_len));
1943           
1944           if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
1945             {
1946               _dbus_list_remove_last (&loader->messages, message);
1947               dbus_message_unref (message);
1948               break;
1949             }
1950           
1951           if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
1952             {
1953               dbus_bool_t result;
1954
1955               /* put the header back, we'll try again later */
1956               result = _dbus_string_copy_len (&message->header, 0, header_len,
1957                                               &loader->data, 0);
1958               _dbus_assert (result); /* because DBusString never reallocs smaller */
1959
1960               _dbus_list_remove_last (&loader->messages, message);
1961               dbus_message_unref (message);
1962               break;
1963             }
1964
1965           _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
1966           _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
1967
1968           _dbus_verbose ("Loaded message %p\n", message);
1969         }
1970       else
1971         break;
1972     }
1973 }
1974
1975 /**
1976  * Pops a loaded message (passing ownership of the message
1977  * to the caller). Returns #NULL if no messages have been
1978  * loaded.
1979  *
1980  * @param loader the loader.
1981  * @returns the next message, or #NULL if none.
1982  */
1983 DBusMessage*
1984 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
1985 {
1986   return _dbus_list_pop_first (&loader->messages);
1987 }
1988
1989
1990 /**
1991  * Checks whether the loader is confused due to bad data.
1992  * If messages are received that are invalid, the
1993  * loader gets confused and gives up permanently.
1994  * This state is called "corrupted."
1995  *
1996  * @param loader the loader
1997  * @returns #TRUE if the loader is hosed.
1998  */
1999 dbus_bool_t
2000 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
2001 {
2002   return loader->corrupted;
2003 }
2004
2005 /**
2006  * Sets the maximum size message we allow.
2007  *
2008  * @param loader the loader
2009  * @param size the max message size in bytes
2010  */
2011 void
2012 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
2013                                            long                size)
2014 {
2015   loader->max_message_size = size;
2016 }
2017
2018 /**
2019  * Gets the maximum allowed message size in bytes.
2020  *
2021  * @param loader the loader
2022  * @returns max size in bytes
2023  */
2024 long
2025 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
2026 {
2027   return loader->max_message_size;
2028 }
2029
2030 /** @} */
2031 #ifdef DBUS_BUILD_TESTS
2032 #include "dbus-test.h"
2033 #include <stdio.h>
2034
2035 static void
2036 message_iter_test (DBusMessage *message)
2037 {
2038   DBusMessageIter *iter;
2039   char *str;
2040   
2041   iter = dbus_message_get_fields_iter (message);
2042
2043   /* String tests */
2044   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_STRING)
2045     _dbus_assert_not_reached ("Field type isn't string");
2046
2047   str = dbus_message_iter_get_string (iter);
2048   if (strcmp (str, "Test string") != 0)
2049     _dbus_assert_not_reached ("Strings differ");
2050   dbus_free (str);
2051
2052   if (!dbus_message_iter_next (iter))
2053     _dbus_assert_not_reached ("Reached end of fields");
2054
2055   /* Signed integer tests */
2056   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_INT32)
2057     _dbus_assert_not_reached ("Field type isn't int32");
2058
2059   if (dbus_message_iter_get_int32 (iter) != -0x12345678)
2060     _dbus_assert_not_reached ("Signed integers differ");
2061
2062   if (!dbus_message_iter_next (iter))
2063     _dbus_assert_not_reached ("Reached end of fields");
2064   
2065   /* Unsigned integer tests */
2066   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_UINT32)
2067     _dbus_assert_not_reached ("Field type isn't int32");
2068
2069   if (dbus_message_iter_get_int32 (iter) != 0xedd1e)
2070     _dbus_assert_not_reached ("Unsigned integers differ");
2071
2072   if (!dbus_message_iter_next (iter))
2073     _dbus_assert_not_reached ("Reached end of fields");
2074
2075   /* Double tests */
2076   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_DOUBLE)
2077     _dbus_assert_not_reached ("Field type isn't double");
2078
2079   if (dbus_message_iter_get_double (iter) != 3.14159)
2080     _dbus_assert_not_reached ("Doubles differ");
2081
2082   if (dbus_message_iter_next (iter))
2083     _dbus_assert_not_reached ("Didn't reach end of fields");
2084   
2085   dbus_message_iter_unref (iter);
2086 }
2087
2088 static dbus_bool_t
2089 check_message_handling (DBusMessage *message)
2090 {
2091   DBusMessageIter *iter;
2092   int type;
2093   dbus_bool_t retval;
2094   dbus_int32_t client_serial;
2095   
2096   retval = FALSE;
2097   iter = NULL;
2098   
2099   client_serial = _dbus_message_get_client_serial (message);
2100
2101   /* can't use set_client_serial due to the assertions at the start of it */
2102   set_int_field (message, FIELD_CLIENT_SERIAL,
2103                  client_serial);
2104
2105   if (client_serial != _dbus_message_get_client_serial (message))
2106     {
2107       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
2108       goto failed;
2109     }
2110   
2111   /* If we implement message_set_field (message, n, value)
2112    * then we would want to test it here
2113    */
2114   
2115   iter = dbus_message_get_fields_iter (message);
2116   while ((type = dbus_message_iter_get_field_type (iter)) != DBUS_TYPE_INVALID)
2117     {
2118       switch (type)
2119         {
2120         case DBUS_TYPE_STRING:
2121           {
2122             char *str;
2123             str = dbus_message_iter_get_string (iter);
2124             dbus_free (str);
2125           }
2126           break;
2127         }
2128       
2129       if (!dbus_message_iter_next (iter))
2130         break;
2131     }
2132
2133   retval = TRUE;
2134   
2135  failed:
2136   if (iter)
2137     dbus_message_iter_unref (iter);
2138
2139   return retval;
2140 }
2141
2142 static dbus_bool_t
2143 check_have_valid_message (DBusMessageLoader *loader)
2144 {
2145   DBusMessage *message;
2146   dbus_bool_t retval;
2147
2148   message = NULL;
2149   retval = FALSE;
2150   
2151   if (_dbus_message_loader_get_is_corrupted (loader))
2152     {
2153       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
2154       goto failed;
2155     }
2156   
2157   message = _dbus_message_loader_pop_message (loader);
2158   if (message == NULL)
2159     {
2160       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
2161       goto failed;
2162     }
2163   
2164   if (_dbus_string_get_length (&loader->data) > 0)
2165     {
2166       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
2167       goto failed;
2168     }
2169
2170   /* Verify that we're able to properly deal with the message.
2171    * For example, this would detect improper handling of messages
2172    * in nonstandard byte order.
2173    */
2174   if (!check_message_handling (message))
2175     goto failed;  
2176   
2177   retval = TRUE;
2178
2179  failed:
2180   if (message)
2181     dbus_message_unref (message);
2182   return retval;
2183 }
2184
2185 static dbus_bool_t
2186 check_invalid_message (DBusMessageLoader *loader)
2187 {
2188   dbus_bool_t retval;
2189
2190   retval = FALSE;
2191   
2192   if (!_dbus_message_loader_get_is_corrupted (loader))
2193     {
2194       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
2195       goto failed;
2196     }
2197
2198   retval = TRUE;
2199
2200  failed:
2201   return retval;
2202 }
2203
2204 static dbus_bool_t
2205 check_incomplete_message (DBusMessageLoader *loader)
2206 {
2207   DBusMessage *message;
2208   dbus_bool_t retval;
2209
2210   message = NULL;
2211   retval = FALSE;
2212   
2213   if (_dbus_message_loader_get_is_corrupted (loader))
2214     {
2215       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
2216       goto failed;
2217     }
2218   
2219   message = _dbus_message_loader_pop_message (loader);
2220   if (message != NULL)
2221     {
2222       _dbus_warn ("loaded message that was expected to be incomplete\n");
2223       goto failed;
2224     }
2225
2226   retval = TRUE;
2227
2228  failed:
2229   if (message)
2230     dbus_message_unref (message);
2231   return retval;
2232 }
2233
2234 typedef enum
2235 {
2236   MESSAGE_VALID,
2237   MESSAGE_INVALID,
2238   MESSAGE_INCOMPLETE
2239 } ExpectedMessageValidity;
2240
2241 static dbus_bool_t
2242 check_loader_results (DBusMessageLoader      *loader,
2243                       ExpectedMessageValidity validity)
2244 {
2245   switch (validity)
2246     {
2247     case MESSAGE_VALID:
2248       return check_have_valid_message (loader);
2249     case MESSAGE_INVALID:
2250       return check_invalid_message (loader);
2251     case MESSAGE_INCOMPLETE:
2252       return check_incomplete_message (loader);
2253     }
2254
2255   _dbus_assert_not_reached ("bad ExpectedMessageValidity");
2256   return FALSE;
2257 }
2258
2259 static dbus_bool_t
2260 try_message (const DBusString       *filename,
2261              ExpectedMessageValidity validity)
2262 {
2263   DBusString data;
2264   DBusMessageLoader *loader;
2265   dbus_bool_t retval;
2266   int len;
2267   int i;
2268   const char *filename_c;
2269
2270   _dbus_string_get_const_data (filename, &filename_c);
2271   
2272   if (!_dbus_string_ends_with_c_str (filename, ".message"))
2273     {
2274       _dbus_verbose ("Skipping non-.message file %s\n",
2275                      filename_c);
2276       return TRUE;
2277     }
2278
2279   {
2280     const char *s;
2281     _dbus_string_get_const_data (filename, &s);
2282     printf ("    %s\n", s);
2283   }
2284   
2285   _dbus_verbose (" expecting %s\n",
2286                  validity == MESSAGE_VALID ? "valid" :
2287                  (validity == MESSAGE_INVALID ? "invalid" : "incomplete"));
2288
2289   loader = NULL;
2290   retval = FALSE;
2291   
2292   if (!_dbus_string_init (&data, _DBUS_INT_MAX))
2293     _dbus_assert_not_reached ("could not allocate string\n");
2294   
2295   if (!_dbus_message_data_load (&data, filename))
2296     {
2297       const char *s;      
2298       _dbus_string_get_const_data (filename, &s);
2299       _dbus_warn ("Could not load message file %s\n", s);
2300       goto failed;
2301     }
2302
2303   /* Write the data one byte at a time */
2304   
2305   loader = _dbus_message_loader_new ();
2306
2307   len = _dbus_string_get_length (&data);
2308   for (i = 0; i < len; i++)
2309     {
2310       DBusString *buffer;
2311
2312       _dbus_message_loader_get_buffer (loader, &buffer);
2313       _dbus_string_append_byte (buffer,
2314                                 _dbus_string_get_byte (&data, i));
2315       _dbus_message_loader_return_buffer (loader, buffer, 1);
2316     }
2317   
2318   if (!check_loader_results (loader, validity))
2319     goto failed;
2320
2321   _dbus_message_loader_unref (loader);
2322   loader = NULL;
2323
2324   /* Write the data all at once */
2325   
2326   loader = _dbus_message_loader_new ();
2327
2328   {
2329     DBusString *buffer;
2330     
2331     _dbus_message_loader_get_buffer (loader, &buffer);
2332     _dbus_string_copy (&data, 0, buffer,
2333                        _dbus_string_get_length (buffer));
2334     _dbus_message_loader_return_buffer (loader, buffer, 1);
2335   }
2336   
2337   if (!check_loader_results (loader, validity))
2338     goto failed;
2339
2340   _dbus_message_loader_unref (loader);
2341   loader = NULL;  
2342
2343   /* Write the data 2 bytes at a time */
2344   
2345   loader = _dbus_message_loader_new ();
2346
2347   len = _dbus_string_get_length (&data);
2348   for (i = 0; i < len; i += 2)
2349     {
2350       DBusString *buffer;
2351
2352       _dbus_message_loader_get_buffer (loader, &buffer);
2353       _dbus_string_append_byte (buffer,
2354                                 _dbus_string_get_byte (&data, i));
2355       if ((i+1) < len)
2356         _dbus_string_append_byte (buffer,
2357                                   _dbus_string_get_byte (&data, i+1));
2358       _dbus_message_loader_return_buffer (loader, buffer, 1);
2359     }
2360   
2361   if (!check_loader_results (loader, validity))
2362     goto failed;
2363
2364   _dbus_message_loader_unref (loader);
2365   loader = NULL;
2366   
2367   retval = TRUE;
2368   
2369  failed:
2370   if (!retval)
2371     {
2372       const char *s;
2373
2374       if (_dbus_string_get_length (&data) > 0)
2375         _dbus_verbose_bytes_of_string (&data, 0,
2376                                        _dbus_string_get_length (&data));
2377       
2378       _dbus_string_get_const_data (filename, &s);
2379       _dbus_warn ("Failed message loader test on %s\n",
2380                   s);
2381     }
2382   
2383   if (loader)
2384     _dbus_message_loader_unref (loader);
2385   _dbus_string_free (&data);
2386   
2387   return retval;
2388 }
2389
2390 static dbus_bool_t
2391 process_test_subdir (const DBusString       *test_base_dir,
2392                      const char             *subdir,
2393                      ExpectedMessageValidity validity)
2394 {
2395   DBusString test_directory;
2396   DBusString filename;
2397   DBusDirIter *dir;
2398   dbus_bool_t retval;
2399   DBusResultCode result;
2400
2401   retval = FALSE;
2402   dir = NULL;
2403   
2404   if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
2405     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2406
2407   _dbus_string_init_const (&filename, subdir);
2408   
2409   if (!_dbus_string_copy (test_base_dir, 0,
2410                           &test_directory, 0))
2411     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2412   
2413   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
2414     _dbus_assert_not_reached ("could't allocate full path");
2415
2416   _dbus_string_free (&filename);
2417   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
2418     _dbus_assert_not_reached ("didn't allocate filename string\n");
2419   
2420   dir = _dbus_directory_open (&test_directory, &result);
2421   if (dir == NULL)
2422     {
2423       const char *s;
2424       _dbus_string_get_const_data (&test_directory, &s);
2425       _dbus_warn ("Could not open %s: %s\n", s,
2426                   dbus_result_to_string (result));
2427       goto failed;
2428     }
2429
2430   printf ("Testing:\n");
2431   
2432   result = DBUS_RESULT_SUCCESS;
2433   while (_dbus_directory_get_next_file (dir, &filename, &result))
2434     {
2435       DBusString full_path;
2436
2437       if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
2438         _dbus_assert_not_reached ("couldn't init string");
2439
2440       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2441         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2442
2443       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2444         _dbus_assert_not_reached ("couldn't concat file to dir");
2445       
2446       if (!try_message (&full_path, validity))
2447         {
2448           _dbus_string_free (&full_path);
2449           goto failed;
2450         }
2451       else
2452         _dbus_string_free (&full_path);
2453     }
2454
2455   if (result != DBUS_RESULT_SUCCESS)
2456     {
2457       const char *s;
2458       _dbus_string_get_const_data (&test_directory, &s);
2459       _dbus_warn ("Could not get next file in %s: %s\n",
2460                   s, dbus_result_to_string (result));
2461       goto failed;
2462     }
2463     
2464   retval = TRUE;
2465   
2466  failed:
2467
2468   if (dir)
2469     _dbus_directory_close (dir);
2470   _dbus_string_free (&test_directory);
2471   _dbus_string_free (&filename);
2472
2473   return retval;
2474 }
2475                      
2476
2477 /**
2478  * @ingroup DBusMessageInternals
2479  * Unit test for DBusMessage.
2480  *
2481  * @returns #TRUE on success.
2482  */
2483 dbus_bool_t
2484 _dbus_message_test (const char *test_data_dir)
2485 {
2486   DBusMessage *message;
2487   DBusMessageLoader *loader;
2488   int i;
2489   const char *data;
2490   dbus_int32_t our_int;
2491   char *our_str;
2492   double our_double;
2493   DBusString test_directory;
2494   dbus_bool_t retval;
2495   
2496   /* Test the vararg functions */
2497   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2498   _dbus_message_set_client_serial (message, 1);
2499   dbus_message_append_fields (message,
2500                               DBUS_TYPE_INT32, -0x12345678,
2501                               DBUS_TYPE_STRING, "Test string",
2502                               DBUS_TYPE_DOUBLE, 3.14159,
2503                               0);
2504   _dbus_verbose_bytes_of_string (&message->header, 0,
2505                                  _dbus_string_get_length (&message->header));
2506   _dbus_verbose_bytes_of_string (&message->body, 0,
2507                                  _dbus_string_get_length (&message->body));
2508   
2509   if (dbus_message_get_fields (message,
2510                                DBUS_TYPE_INT32, &our_int,
2511                                DBUS_TYPE_STRING, &our_str,
2512                                DBUS_TYPE_DOUBLE, &our_double,
2513                                0) != DBUS_RESULT_SUCCESS)
2514     _dbus_assert_not_reached ("Could not get fields");
2515
2516   if (our_int != -0x12345678)
2517     _dbus_assert_not_reached ("integers differ!");
2518
2519   if (our_double != 3.14159)
2520     _dbus_assert_not_reached ("doubles differ!");
2521
2522   if (strcmp (our_str, "Test string") != 0)
2523     _dbus_assert_not_reached ("strings differ!");
2524
2525   dbus_free (our_str);
2526   dbus_message_unref (message);
2527   
2528   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2529   _dbus_message_set_client_serial (message, 1);
2530   _dbus_message_set_reply_serial (message, 0x12345678);
2531
2532   dbus_message_append_string (message, "Test string");
2533   dbus_message_append_int32 (message, -0x12345678);
2534   dbus_message_append_uint32 (message, 0xedd1e);
2535   dbus_message_append_double (message, 3.14159);
2536
2537   message_iter_test (message);
2538
2539   /* Message loader test */
2540   _dbus_message_lock (message);
2541   loader = _dbus_message_loader_new ();
2542
2543   /* Write the header data one byte at a time */
2544   _dbus_string_get_const_data (&message->header, &data);
2545   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
2546     {
2547       DBusString *buffer;
2548
2549       _dbus_message_loader_get_buffer (loader, &buffer);
2550       _dbus_string_append_byte (buffer, data[i]);
2551       _dbus_message_loader_return_buffer (loader, buffer, 1);
2552     }
2553
2554   /* Write the body data one byte at a time */
2555   _dbus_string_get_const_data (&message->body, &data);
2556   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
2557     {
2558       DBusString *buffer;
2559
2560       _dbus_message_loader_get_buffer (loader, &buffer);
2561       _dbus_string_append_byte (buffer, data[i]);
2562       _dbus_message_loader_return_buffer (loader, buffer, 1);
2563     }
2564
2565   dbus_message_unref (message);
2566
2567   /* Now pop back the message */
2568   if (_dbus_message_loader_get_is_corrupted (loader))
2569     _dbus_assert_not_reached ("message loader corrupted");
2570   
2571   message = _dbus_message_loader_pop_message (loader);
2572   if (!message)
2573     _dbus_assert_not_reached ("received a NULL message");
2574
2575   if (_dbus_message_get_reply_serial (message) != 0x12345678)
2576     _dbus_assert_not_reached ("reply serial fields differ");
2577   
2578   message_iter_test (message);
2579   
2580   dbus_message_unref (message);
2581   _dbus_message_loader_unref (loader);
2582
2583   /* Now load every message in test_data_dir if we have one */
2584   if (test_data_dir == NULL)
2585     return TRUE;
2586
2587   retval = FALSE;
2588   
2589   _dbus_string_init_const (&test_directory, test_data_dir);
2590
2591   if (!process_test_subdir (&test_directory, "valid-messages",
2592                             MESSAGE_VALID))
2593     goto failed;
2594   if (!process_test_subdir (&test_directory, "invalid-messages",
2595                             MESSAGE_INVALID))
2596     goto failed;
2597   
2598   if (!process_test_subdir (&test_directory, "incomplete-messages",
2599                             MESSAGE_INCOMPLETE))
2600     goto failed;
2601
2602   retval = TRUE;
2603   
2604  failed:
2605
2606   _dbus_string_free (&test_directory);
2607   
2608   return retval;
2609 }
2610
2611 #endif /* DBUS_BUILD_TESTS */