Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      2 /* dbus-address.c  Server address parser.
      3  *
      4  * Copyright (C) 2003  CodeFactory AB
      5  * Copyright (C) 2004,2005  Red Hat, Inc.
      6  *
      7  * Licensed under the Academic Free License version 2.1
      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 <config.h>
     26 #include "dbus-address.h"
     27 #include "dbus-internals.h"
     28 #include "dbus-list.h"
     29 #include "dbus-string.h"
     30 #include "dbus-protocol.h"
     31 
     32 /**
     33  * @defgroup DBusAddressInternals Address parsing
     34  * @ingroup  DBusInternals
     35  * @brief Implementation of parsing addresses of D-Bus servers.
     36  *
     37  * @{
     38  */
     39 
     40 /**
     41  * Internals of DBusAddressEntry
     42  */
     43 struct DBusAddressEntry
     44 {
     45   DBusString method; /**< The address type (unix, tcp, etc.) */
     46 
     47   DBusList *keys;    /**< List of keys */
     48   DBusList *values;  /**< List of values */
     49 };
     50 
     51 
     52 /**
     53  *
     54  * Sets #DBUS_ERROR_BAD_ADDRESS.
     55  * If address_problem_type and address_problem_field are not #NULL,
     56  * sets an error message about how the field is no good. Otherwise, sets
     57  * address_problem_other as the error message.
     58  *
     59  * @param error the error to set
     60  * @param address_problem_type the address type of the bad address or #NULL
     61  * @param address_problem_field the missing field of the bad address or #NULL
     62  * @param address_problem_other any other error message or #NULL
     63  */
     64 void
     65 _dbus_set_bad_address (DBusError  *error,
     66                        const char *address_problem_type,
     67                        const char *address_problem_field,
     68                        const char *address_problem_other)
     69 {
     70   if (address_problem_type != NULL)
     71     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
     72                     "Server address of type %s was missing argument %s",
     73                     address_problem_type, address_problem_field);
     74   else
     75     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
     76                     "Could not parse server address: %s",
     77                     address_problem_other);
     78 }
     79 
     80 /**
     81  * #TRUE if the byte need not be escaped when found in a dbus address.
     82  * All other bytes are required to be escaped in a valid address.
     83  */
     84 #define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b)        \
     85          (((b) >= 'a' && (b) <= 'z') ||                 \
     86           ((b) >= 'A' && (b) <= 'Z') ||                 \
     87           ((b) >= '0' && (b) <= '9') ||                 \
     88           (b) == '-' ||                                 \
     89           (b) == '_' ||                                 \
     90           (b) == '/' ||                                 \
     91           (b) == '\\' ||                                \
     92           (b) == '.')
     93 
     94 /**
     95  * Appends an escaped version of one string to another string,
     96  * using the D-Bus address escaping mechanism
     97  *
     98  * @param escaped the string to append to
     99  * @param unescaped the string to escape
    100  * @returns #FALSE if no memory
    101  */
    102 dbus_bool_t
    103 _dbus_address_append_escaped (DBusString       *escaped,
    104                               const DBusString *unescaped)
    105 {
    106   const char *p;
    107   const char *end;
    108   dbus_bool_t ret;
    109   int orig_len;
    110 
    111   ret = FALSE;
    112 
    113   orig_len = _dbus_string_get_length (escaped);
    114   p = _dbus_string_get_const_data (unescaped);
    115   end = p + _dbus_string_get_length (unescaped);
    116   while (p != end)
    117     {
    118       if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
    119         {
    120           if (!_dbus_string_append_byte (escaped, *p))
    121             goto out;
    122         }
    123       else
    124         {
    125           if (!_dbus_string_append_byte (escaped, '%'))
    126             goto out;
    127           if (!_dbus_string_append_byte_as_hex (escaped, *p))
    128             goto out;
    129         }
    130 
    131       ++p;
    132     }
    133 
    134   ret = TRUE;
    135 
    136  out:
    137   if (!ret)
    138     _dbus_string_set_length (escaped, orig_len);
    139   return ret;
    140 }
    141 
    142 /** @} */ /* End of internals */
    143 
    144 static void
    145 dbus_address_entry_free (DBusAddressEntry *entry)
    146 {
    147   DBusList *link;
    148 
    149   _dbus_string_free (&entry->method);
    150 
    151   link = _dbus_list_get_first_link (&entry->keys);
    152   while (link != NULL)
    153     {
    154       _dbus_string_free (link->data);
    155       dbus_free (link->data);
    156 
    157       link = _dbus_list_get_next_link (&entry->keys, link);
    158     }
    159   _dbus_list_clear (&entry->keys);
    160 
    161   link = _dbus_list_get_first_link (&entry->values);
    162   while (link != NULL)
    163     {
    164       _dbus_string_free (link->data);
    165       dbus_free (link->data);
    166 
    167       link = _dbus_list_get_next_link (&entry->values, link);
    168     }
    169   _dbus_list_clear (&entry->values);
    170 
    171   dbus_free (entry);
    172 }
    173 
    174 /**
    175  * @defgroup DBusAddress Address parsing
    176  * @ingroup  DBus
    177  * @brief Parsing addresses of D-Bus servers.
    178  *
    179  * @{
    180  */
    181 
    182 /**
    183  * Frees a #NULL-terminated array of address entries.
    184  *
    185  * @param entries the array.
    186  */
    187 void
    188 dbus_address_entries_free (DBusAddressEntry **entries)
    189 {
    190   int i;
    191 
    192   for (i = 0; entries[i] != NULL; i++)
    193     dbus_address_entry_free (entries[i]);
    194   dbus_free (entries);
    195 }
    196 
    197 static DBusAddressEntry *
    198 create_entry (void)
    199 {
    200   DBusAddressEntry *entry;
    201 
    202   entry = dbus_new0 (DBusAddressEntry, 1);
    203 
    204   if (entry == NULL)
    205     return NULL;
    206 
    207   if (!_dbus_string_init (&entry->method))
    208     {
    209       dbus_free (entry);
    210       return NULL;
    211     }
    212 
    213   return entry;
    214 }
    215 
    216 /**
    217  * Returns the method string of an address entry.  For example, given
    218  * the address entry "tcp:host=example.com" it would return the string
    219  * "tcp"
    220  *
    221  * @param entry the entry.
    222  * @returns a string describing the method. This string
    223  * must not be freed.
    224  */
    225 const char *
    226 dbus_address_entry_get_method (DBusAddressEntry *entry)
    227 {
    228   return _dbus_string_get_const_data (&entry->method);
    229 }
    230 
    231 /**
    232  * Returns a value from a key of an entry. For example,
    233  * given the address "tcp:host=example.com,port=8073" if you asked
    234  * for the key "host" you would get the value "example.com"
    235  *
    236  * The returned value is already unescaped.
    237  *
    238  * @param entry the entry.
    239  * @param key the key.
    240  * @returns the key value. This string must not be freed.
    241  */
    242 const char *
    243 dbus_address_entry_get_value (DBusAddressEntry *entry,
    244 			      const char       *key)
    245 {
    246   DBusList *values, *keys;
    247 
    248   keys = _dbus_list_get_first_link (&entry->keys);
    249   values = _dbus_list_get_first_link (&entry->values);
    250 
    251   while (keys != NULL)
    252     {
    253       _dbus_assert (values != NULL);
    254 
    255       if (_dbus_string_equal_c_str (keys->data, key))
    256         return _dbus_string_get_const_data (values->data);
    257 
    258       keys = _dbus_list_get_next_link (&entry->keys, keys);
    259       values = _dbus_list_get_next_link (&entry->values, values);
    260     }
    261 
    262   return NULL;
    263 }
    264 
    265 static dbus_bool_t
    266 append_unescaped_value (DBusString       *unescaped,
    267                         const DBusString *escaped,
    268                         int               escaped_start,
    269                         int               escaped_len,
    270                         DBusError        *error)
    271 {
    272   const char *p;
    273   const char *end;
    274   dbus_bool_t ret;
    275 
    276   ret = FALSE;
    277 
    278   p = _dbus_string_get_const_data (escaped) + escaped_start;
    279   end = p + escaped_len;
    280   while (p != end)
    281     {
    282       if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p))
    283         {
    284           if (!_dbus_string_append_byte (unescaped, *p))
    285             goto out;
    286         }
    287       else if (*p == '%')
    288         {
    289           /* Efficiency is king */
    290           char buf[3];
    291           DBusString hex;
    292           int hex_end;
    293 
    294           ++p;
    295 
    296           if ((p + 2) > end)
    297             {
    298               dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
    299                               "In D-Bus address, percent character was not followed by two hex digits");
    300               goto out;
    301             }
    302 
    303           buf[0] = *p;
    304           ++p;
    305           buf[1] = *p;
    306           buf[2] = '\0';
    307 
    308           _dbus_string_init_const (&hex, buf);
    309 
    310           if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
    311                                         unescaped,
    312                                         _dbus_string_get_length (unescaped)))
    313             goto out;
    314 
    315           if (hex_end != 2)
    316             {
    317               dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
    318                               "In D-Bus address, percent character was followed by characters other than hex digits");
    319               goto out;
    320             }
    321         }
    322       else
    323         {
    324           /* Error, should have been escaped */
    325           dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
    326                           "In D-Bus address, character '%c' should have been escaped\n",
    327                           *p);
    328           goto out;
    329         }
    330 
    331       ++p;
    332     }
    333 
    334   ret = TRUE;
    335 
    336  out:
    337   if (!ret && error && !dbus_error_is_set (error))
    338     _DBUS_SET_OOM (error);
    339 
    340   _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
    341 
    342   return ret;
    343 }
    344 
    345 /**
    346  * Parses an address string of the form:
    347  *
    348  * method:key=value,key=value;method:key=value
    349  *
    350  * See the D-Bus specification for complete docs on the format.
    351  *
    352  * When connecting to an address, the first address entries
    353  * in the semicolon-separated list should be tried first.
    354  *
    355  * @param address the address.
    356  * @param entry return location to an array of entries.
    357  * @param array_len return location for array length.
    358  * @param error address where an error can be returned.
    359  * @returns #TRUE on success, #FALSE otherwise.
    360  */
    361 dbus_bool_t
    362 dbus_parse_address (const char         *address,
    363 		    DBusAddressEntry ***entry,
    364 		    int                *array_len,
    365                     DBusError          *error)
    366 {
    367   DBusString str;
    368   int pos, end_pos, len, i;
    369   DBusList *entries, *link;
    370   DBusAddressEntry **entry_array;
    371 
    372   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    373 
    374   _dbus_string_init_const (&str, address);
    375 
    376   entries = NULL;
    377   pos = 0;
    378   len = _dbus_string_get_length (&str);
    379 
    380   while (pos < len)
    381     {
    382       DBusAddressEntry *entry;
    383 
    384       int found_pos;
    385 
    386       entry = create_entry ();
    387       if (!entry)
    388 	{
    389 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    390 
    391 	  goto error;
    392 	}
    393 
    394       /* Append the entry */
    395       if (!_dbus_list_append (&entries, entry))
    396 	{
    397 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    398 	  dbus_address_entry_free (entry);
    399 	  goto error;
    400 	}
    401 
    402       /* Look for a semi-colon */
    403       if (!_dbus_string_find (&str, pos, ";", &end_pos))
    404 	end_pos = len;
    405 
    406       /* Look for the colon : */
    407       if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
    408 	{
    409 	  dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
    410 	  goto error;
    411 	}
    412 
    413       if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
    414 	{
    415 	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    416 	  goto error;
    417 	}
    418 
    419       pos = found_pos + 1;
    420 
    421       while (pos < end_pos)
    422 	{
    423 	  int comma_pos, equals_pos;
    424 
    425 	  if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
    426 	    comma_pos = end_pos;
    427 
    428 	  if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
    429 	      equals_pos == pos || equals_pos + 1 == comma_pos)
    430 	    {
    431 	      dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
    432                               "'=' character not found or has no value following it");
    433               goto error;
    434 	    }
    435 	  else
    436 	    {
    437 	      DBusString *key;
    438 	      DBusString *value;
    439 
    440 	      key = dbus_new0 (DBusString, 1);
    441 
    442 	      if (!key)
    443 		{
    444 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    445 		  goto error;
    446 		}
    447 
    448 	      value = dbus_new0 (DBusString, 1);
    449 	      if (!value)
    450 		{
    451 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    452 		  dbus_free (key);
    453 		  goto error;
    454 		}
    455 
    456 	      if (!_dbus_string_init (key))
    457 		{
    458 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    459 		  dbus_free (key);
    460 		  dbus_free (value);
    461 
    462 		  goto error;
    463 		}
    464 
    465 	      if (!_dbus_string_init (value))
    466 		{
    467 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    468 		  _dbus_string_free (key);
    469 
    470 		  dbus_free (key);
    471 		  dbus_free (value);
    472 		  goto error;
    473 		}
    474 
    475 	      if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
    476 		{
    477 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    478 		  _dbus_string_free (key);
    479 		  _dbus_string_free (value);
    480 
    481 		  dbus_free (key);
    482 		  dbus_free (value);
    483 		  goto error;
    484 		}
    485 
    486 	      if (!append_unescaped_value (value, &str, equals_pos + 1,
    487                                            comma_pos - equals_pos - 1, error))
    488 		{
    489                   _dbus_assert (error == NULL || dbus_error_is_set (error));
    490 		  _dbus_string_free (key);
    491 		  _dbus_string_free (value);
    492 
    493 		  dbus_free (key);
    494 		  dbus_free (value);
    495 		  goto error;
    496 		}
    497 
    498 	      if (!_dbus_list_append (&entry->keys, key))
    499 		{
    500 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    501 		  _dbus_string_free (key);
    502 		  _dbus_string_free (value);
    503 
    504 		  dbus_free (key);
    505 		  dbus_free (value);
    506 		  goto error;
    507 		}
    508 
    509 	      if (!_dbus_list_append (&entry->values, value))
    510 		{
    511 		  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    512 		  _dbus_string_free (value);
    513 
    514 		  dbus_free (value);
    515 		  goto error;
    516 		}
    517 	    }
    518 
    519 	  pos = comma_pos + 1;
    520 	}
    521 
    522       pos = end_pos + 1;
    523     }
    524 
    525   *array_len = _dbus_list_get_length (&entries);
    526 
    527   entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
    528 
    529   if (!entry_array)
    530     {
    531       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    532 
    533       goto error;
    534     }
    535 
    536   entry_array [*array_len] = NULL;
    537 
    538   link = _dbus_list_get_first_link (&entries);
    539   i = 0;
    540   while (link != NULL)
    541     {
    542       entry_array[i] = link->data;
    543       i++;
    544       link = _dbus_list_get_next_link (&entries, link);
    545     }
    546 
    547   _dbus_list_clear (&entries);
    548   *entry = entry_array;
    549 
    550   return TRUE;
    551 
    552  error:
    553 
    554   link = _dbus_list_get_first_link (&entries);
    555   while (link != NULL)
    556     {
    557       dbus_address_entry_free (link->data);
    558       link = _dbus_list_get_next_link (&entries, link);
    559     }
    560 
    561   _dbus_list_clear (&entries);
    562 
    563   return FALSE;
    564 
    565 }
    566 
    567 /**
    568  * Escapes the given string as a value in a key=value pair
    569  * for a D-Bus address.
    570  *
    571  * @param value the unescaped value
    572  * @returns newly-allocated escaped value or #NULL if no memory
    573  */
    574 char*
    575 dbus_address_escape_value (const char *value)
    576 {
    577   DBusString escaped;
    578   DBusString unescaped;
    579   char *ret;
    580 
    581   ret = NULL;
    582 
    583   _dbus_string_init_const (&unescaped, value);
    584 
    585   if (!_dbus_string_init (&escaped))
    586     return NULL;
    587 
    588   if (!_dbus_address_append_escaped (&escaped, &unescaped))
    589     goto out;
    590 
    591   if (!_dbus_string_steal_data (&escaped, &ret))
    592     goto out;
    593 
    594  out:
    595   _dbus_string_free (&escaped);
    596   return ret;
    597 }
    598 
    599 /**
    600  * Unescapes the given string as a value in a key=value pair
    601  * for a D-Bus address. Note that dbus_address_entry_get_value()
    602  * returns an already-unescaped value.
    603  *
    604  * @param value the escaped value
    605  * @param error error to set if the unescaping fails
    606  * @returns newly-allocated unescaped value or #NULL if no memory
    607  */
    608 char*
    609 dbus_address_unescape_value (const char *value,
    610                              DBusError  *error)
    611 {
    612   DBusString unescaped;
    613   DBusString escaped;
    614   char *ret;
    615 
    616   ret = NULL;
    617 
    618   _dbus_string_init_const (&escaped, value);
    619 
    620   if (!_dbus_string_init (&unescaped))
    621     return NULL;
    622 
    623   if (!append_unescaped_value (&unescaped, &escaped,
    624                                0, _dbus_string_get_length (&escaped),
    625                                error))
    626     goto out;
    627 
    628   if (!_dbus_string_steal_data (&unescaped, &ret))
    629     goto out;
    630 
    631  out:
    632   if (ret == NULL && error && !dbus_error_is_set (error))
    633     _DBUS_SET_OOM (error);
    634 
    635   _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
    636 
    637   _dbus_string_free (&unescaped);
    638   return ret;
    639 }
    640 
    641 /** @} */ /* End of public API */
    642 
    643 #ifdef DBUS_BUILD_TESTS
    644 
    645 #ifndef DOXYGEN_SHOULD_SKIP_THIS
    646 
    647 #include "dbus-test.h"
    648 #include <stdlib.h>
    649 
    650 typedef struct
    651 {
    652   const char *escaped;
    653   const char *unescaped;
    654 } EscapeTest;
    655 
    656 static const EscapeTest escape_tests[] = {
    657   { "abcde", "abcde" },
    658   { "", "" },
    659   { "%20%20", "  " },
    660   { "%24", "$" },
    661   { "%25", "%" },
    662   { "abc%24", "abc$" },
    663   { "%24abc", "$abc" },
    664   { "abc%24abc", "abc$abc" },
    665   { "/", "/" },
    666   { "-", "-" },
    667   { "_", "_" },
    668   { "A", "A" },
    669   { "I", "I" },
    670   { "Z", "Z" },
    671   { "a", "a" },
    672   { "i", "i" },
    673   { "z", "z" }
    674 };
    675 
    676 static const char* invalid_escaped_values[] = {
    677   "%a",
    678   "%q",
    679   "%az",
    680   "%%",
    681   "%$$",
    682   "abc%a",
    683   "%axyz",
    684   "%",
    685   "$",
    686   " ",
    687   "*"
    688 };
    689 
    690 dbus_bool_t
    691 _dbus_address_test (void)
    692 {
    693   DBusAddressEntry **entries;
    694   int len;
    695   DBusError error;
    696   int i;
    697 
    698   dbus_error_init (&error);
    699 
    700   i = 0;
    701   while (i < _DBUS_N_ELEMENTS (escape_tests))
    702     {
    703       const EscapeTest *test = &escape_tests[i];
    704       char *escaped;
    705       char *unescaped;
    706 
    707       escaped = dbus_address_escape_value (test->unescaped);
    708       if (escaped == NULL)
    709         _dbus_assert_not_reached ("oom");
    710 
    711       if (strcmp (escaped, test->escaped) != 0)
    712         {
    713           _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n",
    714                       test->unescaped, escaped, test->escaped);
    715           exit (1);
    716         }
    717       dbus_free (escaped);
    718 
    719       unescaped = dbus_address_unescape_value (test->escaped, &error);
    720       if (unescaped == NULL)
    721         {
    722           _dbus_warn ("Failed to unescape '%s': %s\n",
    723                       test->escaped, error.message);
    724           dbus_error_free (&error);
    725           exit (1);
    726         }
    727 
    728       if (strcmp (unescaped, test->unescaped) != 0)
    729         {
    730           _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n",
    731                       test->escaped, unescaped, test->unescaped);
    732           exit (1);
    733         }
    734       dbus_free (unescaped);
    735 
    736       ++i;
    737     }
    738 
    739   i = 0;
    740   while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
    741     {
    742       char *unescaped;
    743 
    744       unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
    745                                                &error);
    746       if (unescaped != NULL)
    747         {
    748           _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n",
    749                       invalid_escaped_values[i], unescaped);
    750           dbus_free (unescaped);
    751           exit (1);
    752         }
    753 
    754       _dbus_assert (dbus_error_is_set (&error));
    755       dbus_error_free (&error);
    756 
    757       ++i;
    758     }
    759 
    760   if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
    761 			   &entries, &len, &error))
    762     _dbus_assert_not_reached ("could not parse address");
    763   _dbus_assert (len == 2);
    764   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
    765   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
    766   _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
    767 
    768   dbus_address_entries_free (entries);
    769 
    770   /* Different possible errors */
    771   if (dbus_parse_address ("foo", &entries, &len, &error))
    772     _dbus_assert_not_reached ("Parsed incorrect address.");
    773   else
    774     dbus_error_free (&error);
    775 
    776   if (dbus_parse_address ("foo:bar", &entries, &len, &error))
    777     _dbus_assert_not_reached ("Parsed incorrect address.");
    778   else
    779     dbus_error_free (&error);
    780 
    781   if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
    782     _dbus_assert_not_reached ("Parsed incorrect address.");
    783   else
    784     dbus_error_free (&error);
    785 
    786   if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
    787     _dbus_assert_not_reached ("Parsed incorrect address.");
    788   else
    789     dbus_error_free (&error);
    790 
    791   if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
    792     _dbus_assert_not_reached ("Parsed incorrect address.");
    793   else
    794     dbus_error_free (&error);
    795 
    796   if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
    797     _dbus_assert_not_reached ("Parsed incorrect address.");
    798   else
    799     dbus_error_free (&error);
    800 
    801   if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
    802     _dbus_assert_not_reached ("Parsed incorrect address.");
    803   else
    804     dbus_error_free (&error);
    805 
    806   if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
    807     _dbus_assert_not_reached ("Parsed incorrect address.");
    808   else
    809     dbus_error_free (&error);
    810 
    811   return TRUE;
    812 }
    813 
    814 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
    815 
    816 #endif
    817