/**
 * Opens a debug pipe transport, used in the test suite.
 *
 * @param entry the address entry to try opening as debug-pipe
 * @param transport_p return location for the opened transport
 * @param error error to be set
 * @returns result of the attempt
 */
DBusTransportOpenResult
_dbus_transport_open_debug_pipe (DBusAddressEntry  *entry,
                                 DBusTransport    **transport_p,
                                 DBusError         *error)
{
    const char *method;

    method = dbus_address_entry_get_method (entry);
    _dbus_assert (method != NULL);

    if (strcmp (method, "debug-pipe") == 0)
    {
        const char *name = dbus_address_entry_get_value (entry, "name");

        if (name == NULL)
        {
            _dbus_set_bad_address (error, "debug-pipe", "name",
                                   NULL);
            return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }

        *transport_p = _dbus_transport_debug_pipe_new (name, error);

        if (*transport_p == NULL)
        {
            _DBUS_ASSERT_ERROR_IS_SET (error);
            return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
        }
        else
        {
            _DBUS_ASSERT_ERROR_IS_CLEAR (error);
            return DBUS_TRANSPORT_OPEN_OK;
        }
    }
    else
    {
        _DBUS_ASSERT_ERROR_IS_CLEAR (error);
        return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    }
}
/**
 * Try to open a new transport for the given address entry.  (This
 * opens a client-side-of-the-connection transport.)
 * 
 * @param entry the address entry
 * @param error location to store reason for failure.
 * @returns new transport of #NULL on failure.
 */
DBusTransport*
_dbus_transport_open (DBusAddressEntry *entry,
                      DBusError        *error)
{
  DBusTransport *transport;
  const char *address_problem_type;
  const char *address_problem_field;
  const char *address_problem_other;
  const char *method;
  const char *expected_guid_orig;
  char *expected_guid;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  transport = NULL;
  address_problem_type = NULL;
  address_problem_field = NULL;
  address_problem_other = NULL;
  expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
  expected_guid = _dbus_strdup (expected_guid_orig);

  if (expected_guid_orig != NULL && expected_guid == NULL)
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }
  
  method = dbus_address_entry_get_method (entry);
  _dbus_assert (method != NULL);
      
  if (strcmp (method, "unix") == 0)
    {
      const char *path = dbus_address_entry_get_value (entry, "path");
      const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
      const char *abstract = dbus_address_entry_get_value (entry, "abstract");
          
      if (tmpdir != NULL)
        {
          address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
          goto bad_address;
        }
          
      if (path == NULL && abstract == NULL)
        {
          address_problem_type = "unix";
          address_problem_field = "path or abstract";  
          goto bad_address;
        }

      if (path != NULL && abstract != NULL)
        {
          address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address";
          goto bad_address;
        }

      if (path)
        transport = _dbus_transport_new_for_domain_socket (path, FALSE,
                                                           error);
      else
        transport = _dbus_transport_new_for_domain_socket (abstract, TRUE,
                                                           error);
    }
  else if (strcmp (method, "tcp") == 0)
    {
      const char *host = dbus_address_entry_get_value (entry, "host");
      const char *port = dbus_address_entry_get_value (entry, "port");
      DBusString  str;
      long lport;
      dbus_bool_t sresult;
          
      if (port == NULL)
        {
          address_problem_type = "tcp";
          address_problem_field = "port";
          goto bad_address;
        }

      _dbus_string_init_const (&str, port);
      sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
      _dbus_string_free (&str);
          
      if (sresult == FALSE || lport <= 0 || lport > 65535)
        {
          address_problem_other = "Port is not an integer between 0 and 65535";
          goto bad_address;
        }
          
      transport = _dbus_transport_new_for_tcp_socket (host, lport, error);
    }
#ifdef DBUS_BUILD_TESTS
  else if (strcmp (method, "debug-pipe") == 0)
    {
      const char *name = dbus_address_entry_get_value (entry, "name");

      if (name == NULL)
        {
          address_problem_type = "debug-pipe";
          address_problem_field = "name";
          goto bad_address;
        }
          
      transport = _dbus_transport_debug_pipe_new (name, error);
    }
#endif
  else
    {
      address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
      goto bad_address;
    }

  if (transport == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_free (expected_guid);
    }
  else
    {
      transport->expected_guid = expected_guid;
    }
  
  return transport;
  
 bad_address:
  dbus_free (expected_guid);
  
  if (address_problem_type != NULL)
    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                    "Address of type %s was missing argument %s",
                    address_problem_type, address_problem_field);
  else
    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                    "Could not parse address: %s",
                    address_problem_other);

  return NULL;
}