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