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