diff options
| -rw-r--r-- | ChangeLog | 19 | ||||
| -rw-r--r-- | bus/bus.c | 25 | ||||
| -rw-r--r-- | bus/config-parser.c | 19 | ||||
| -rw-r--r-- | bus/dispatch.c | 3 | ||||
| -rw-r--r-- | bus/policy.c | 17 | ||||
| -rw-r--r-- | bus/signals.c | 623 | ||||
| -rw-r--r-- | dbus/dbus-errors.h | 1 | ||||
| -rw-r--r-- | dbus/dbus-message.c | 28 | ||||
| -rw-r--r-- | dbus/dbus-message.h | 2 | ||||
| -rw-r--r-- | tools/dbus-send.c | 8 | 
10 files changed, 689 insertions, 56 deletions
| @@ -1,3 +1,22 @@ +2003-10-09  Havoc Pennington  <hp@redhat.com> + +        Make matching rules theoretically work (add parser). +	 +	* bus/bus.c (bus_context_check_security_policy): fix up to handle +	the case where destination is explicitly specified as bus driver +	and someone else is eavesdropping. +	 +	* bus/policy.c (bus_client_policy_check_can_receive): fix up +	definition of eavesdropping and assertion + +	* tools/dbus-send.c (main): use dbus_message_type_from_string + +	* bus/signals.c (bus_match_rule_parse): implement + +	* dbus/dbus-message.c (dbus_message_type_from_string): new + +	* dbus/dbus-errors.h (DBUS_ERROR_MATCH_RULE_INVALID): add +  2003-10-02  Havoc Pennington  <hp@pobox.com>  	* glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): rename from @@ -872,6 +872,19 @@ bus_context_get_max_match_rules_per_connection (BusContext *context)    return context->limits.max_match_rules_per_connection;  } +/* + * addressed_recipient is the recipient specified in the message. + * + * proposed_recipient is the recipient we're considering sending + * to right this second, and may be an eavesdropper. + * + * sender is the sender of the message. + * + * NULL for proposed_recipient or sender definitely means the bus driver. + * + * NULL for addressed_recipient may mean the bus driver, or may mean + * no destination was specified in the message (e.g. a signal). + */  dbus_bool_t  bus_context_check_security_policy (BusContext     *context,                                     DBusConnection *sender, @@ -883,15 +896,9 @@ bus_context_check_security_policy (BusContext     *context,    BusClientPolicy *sender_policy;    BusClientPolicy *recipient_policy; -  /* NULL sender, proposed_recipient means the bus driver.  NULL -   * addressed_recipient means the message didn't specify an explicit -   * target. If proposed_recipient is NULL, then addressed_recipient -   * is also NULL but is implicitly the bus driver. -   */ - -  _dbus_assert (proposed_recipient == NULL || -                (dbus_message_get_destination (message) == NULL || -                 addressed_recipient != NULL)); +  _dbus_assert (dbus_message_get_destination (message) == NULL || /* Signal */ +                (addressed_recipient != NULL || +                 strcmp (dbus_message_get_destination (message), DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0)); /* Destination specified or is the bus driver */    if (sender != NULL)      { diff --git a/bus/config-parser.c b/bus/config-parser.c index 7b9b962d..3ff3ec50 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -813,21 +813,6 @@ start_busconfig_child (BusConfigParser   *parser,      }  } -static int -message_type_from_string (const char *type_str) -{ -  if (strcmp (type_str, "method_call") == 0) -    return DBUS_MESSAGE_TYPE_METHOD_CALL; -  if (strcmp (type_str, "method_return") == 0) -    return DBUS_MESSAGE_TYPE_METHOD_RETURN; -  else if (strcmp (type_str, "signal") == 0) -    return DBUS_MESSAGE_TYPE_SIGNAL; -  else if (strcmp (type_str, "error") == 0) -    return DBUS_MESSAGE_TYPE_ERROR; -  else -    return DBUS_MESSAGE_TYPE_INVALID; -} -  static dbus_bool_t  append_rule_from_element (BusConfigParser   *parser,                            const char        *element_name, @@ -1027,7 +1012,7 @@ append_rule_from_element (BusConfigParser   *parser,        message_type = DBUS_MESSAGE_TYPE_INVALID;        if (send_type != NULL)          { -          message_type = message_type_from_string (send_type); +          message_type = dbus_message_type_from_string (send_type);            if (message_type == DBUS_MESSAGE_TYPE_INVALID)              {                dbus_set_error (error, DBUS_ERROR_FAILED, @@ -1079,7 +1064,7 @@ append_rule_from_element (BusConfigParser   *parser,        message_type = DBUS_MESSAGE_TYPE_INVALID;        if (receive_type != NULL)          { -          message_type = message_type_from_string (receive_type); +          message_type = dbus_message_type_from_string (receive_type);            if (message_type == DBUS_MESSAGE_TYPE_INVALID)              {                dbus_set_error (error, DBUS_ERROR_FAILED, diff --git a/bus/dispatch.c b/bus/dispatch.c index 606c68ef..e238cb4c 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -920,7 +920,8 @@ check_add_match_all (BusContext     *context,    if (message == NULL)      return TRUE; -  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */ +  /* empty string match rule matches everything */ +  if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "",                                   DBUS_TYPE_INVALID))      {        dbus_message_unref (message); diff --git a/bus/policy.c b/bus/policy.c index 2d462fb6..71137ca9 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -913,6 +913,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,    return allowed;  } +/* See docs on what the args mean on bus_context_check_security_policy() + * comment + */  dbus_bool_t  bus_client_policy_check_can_receive (BusClientPolicy *policy,                                       BusRegistry     *registry, @@ -924,20 +927,10 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,    DBusList *link;    dbus_bool_t allowed;    dbus_bool_t eavesdropping; -   -  /* NULL sender, proposed_recipient means the bus driver.  NULL -   * addressed_recipient means the message didn't specify an explicit -   * target. If proposed_recipient is NULL, then addressed_recipient -   * is also NULL but is implicitly the bus driver. -   */ -  _dbus_assert (proposed_recipient == NULL || -                (dbus_message_get_destination (message) == NULL || -                 addressed_recipient != NULL)); -      eavesdropping = -    (proposed_recipient == NULL || /* explicitly to bus driver */ -     (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */ +    addressed_recipient != proposed_recipient && +    dbus_message_get_destination (message) != NULL;    /* policy->rules is in the order the rules appeared     * in the config file, i.e. last rule that applies wins diff --git a/bus/signals.c b/bus/signals.c index 30d977c3..960d846c 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -52,6 +52,10 @@ bus_match_rule_new (DBusConnection *matches_go_to)    rule->refcount = 1;    rule->matches_go_to = matches_go_to; +#ifndef DBUS_BUILD_TESTS +  _dbus_assert (rule->matches_go_to != NULL); +#endif +      return rule;  } @@ -285,6 +289,285 @@ bus_match_rule_set_path (BusMatchRule *rule,    return TRUE;  } +#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) + +static dbus_bool_t +find_key (const DBusString *str, +          int               start, +          DBusString       *key, +          int              *value_pos, +          DBusError        *error) +{ +  const char *p; +  const char *s; +  const char *key_start; +  const char *key_end; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  s = _dbus_string_get_const_data (str); + +  p = s + start; + +  while (*p && ISWHITE (*p)) +    ++p; + +  key_start = p; + +  while (*p && *p != '=' && !ISWHITE (*p)) +    ++p; + +  key_end = p; + +  while (*p && ISWHITE (*p)) +    ++p; +   +  if (key_start == key_end) +    { +      /* Empty match rules or trailing whitespace are OK */ +      *value_pos = p - s; +      return TRUE; +    } + +  if (*p != '=') +    { +      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                      "Match rule has a key with no subsequent '=' character"); +      return FALSE; +    } +  ++p; +   +  if (!_dbus_string_append_len (key, key_start, key_end - key_start)) +    { +      BUS_SET_OOM (error); +      return FALSE; +    } + +  *value_pos = p - s; +   +  return TRUE; +} + +static dbus_bool_t +find_value (const DBusString *str, +            int               start, +            const char       *key, +            DBusString       *value, +            int              *value_end, +            DBusError        *error) +{ +  const char *p; +  const char *s; +  char quote_char; +  int orig_len; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  orig_len = _dbus_string_get_length (value); +   +  s = _dbus_string_get_const_data (str); + +  p = s + start; + +  quote_char = '\0'; + +  while (*p) +    { +      if (quote_char == '\0') +        { +          switch (*p) +            { +            case '\0': +              goto done; + +            case '\'': +              quote_char = '\''; +              goto next; +               +            case ',': +              ++p; +              goto done; + +            case '\\': +              quote_char = '\\'; +              goto next; +               +            default: +              if (!_dbus_string_append_byte (value, *p)) +                { +                  BUS_SET_OOM (error); +                  goto failed; +                } +            } +        } +      else if (quote_char == '\\') +        { +          /* \ only counts as an escape if escaping a quote mark */ +          if (*p != '\'') +            { +              if (!_dbus_string_append_byte (value, '\\')) +                { +                  BUS_SET_OOM (error); +                  goto failed; +                } +            } + +          if (!_dbus_string_append_byte (value, *p)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +           +          quote_char = '\0'; +        } +      else +        { +          _dbus_assert (quote_char == '\''); + +          if (*p == '\'') +            { +              quote_char = '\0'; +            } +          else +            { +              if (!_dbus_string_append_byte (value, *p)) +                { +                  BUS_SET_OOM (error); +                  goto failed; +                } +            } +        } + +    next: +      ++p; +    } + + done: + +  if (quote_char == '\\') +    { +      if (!_dbus_string_append_byte (value, '\\')) +        { +          BUS_SET_OOM (error); +          goto failed; +        } +    } +  else if (quote_char == '\'') +    { +      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                      "Unbalanced quotation marks in match rule"); +      goto failed; +    } +  else +    _dbus_assert (quote_char == '\0'); + +  /* Zero-length values are allowed */ +   +  *value_end = p - s; +   +  return TRUE; + + failed: +  _DBUS_ASSERT_ERROR_IS_SET (error); +  _dbus_string_set_length (value, orig_len); +  return FALSE; +} + +/* duplicates aren't allowed so the real legitimate max is only 6 or + * so. Leaving extra so we don't have to bother to update it. + */ +#define MAX_RULE_TOKENS 16 + +/* this is slightly too high level to be termed a "token" + * but let's not be pedantic. + */ +typedef struct +{ +  char *key; +  char *value; +} RuleToken; + +static dbus_bool_t +tokenize_rule (const DBusString *rule_text, +               RuleToken         tokens[MAX_RULE_TOKENS], +               DBusError        *error)  +{ +  int i; +  int pos; +  DBusString key; +  DBusString value; +  dbus_bool_t retval; + +  retval = FALSE; +   +  if (!_dbus_string_init (&key)) +    { +      BUS_SET_OOM (error); +      return FALSE; +    } + +  if (!_dbus_string_init (&value)) +    { +      _dbus_string_free (&key); +      BUS_SET_OOM (error); +      return FALSE; +    } + +  i = 0; +  pos = 0; +  while (i < MAX_RULE_TOKENS && +         pos < _dbus_string_get_length (rule_text)) +    { +      _dbus_assert (tokens[i].key == NULL); +      _dbus_assert (tokens[i].value == NULL); + +      if (!find_key (rule_text, pos, &key, &pos, error)) +        goto out; + +      if (_dbus_string_get_length (&key) == 0) +        goto next; +       +      if (!_dbus_string_steal_data (&key, &tokens[i].key)) +        { +          BUS_SET_OOM (error); +          goto out; +        } + +      if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error)) +        goto out; + +      if (!_dbus_string_steal_data (&value, &tokens[i].value)) +        { +          BUS_SET_OOM (error); +          goto out; +        } + +    next: +      ++i; +    } + +  retval = TRUE; +   + out: +  if (!retval) +    { +      i = 0; +      while (tokens[i].key || tokens[i].value) +        { +          dbus_free (tokens[i].key); +          dbus_free (tokens[i].value); +          tokens[i].key = NULL; +          tokens[i].value = NULL; +          ++i; +        } +    } +   +  _dbus_string_free (&key); +  _dbus_string_free (&value); +   +  return retval; +} +  /*   * The format is comma-separated with strings quoted with single quotes   * as for the shell (to escape a literal single quote, use '\''). @@ -299,24 +582,157 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,                        DBusError        *error)  {    BusMatchRule *rule; - +  RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ +  int i; +   +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); +   +  memset (tokens, '\0', sizeof (tokens)); +      rule = bus_match_rule_new (matches_go_to);    if (rule == NULL) -    goto oom; - -  /* FIXME implement for real */ +    { +      BUS_SET_OOM (error); +      goto failed; +    } -  if (!bus_match_rule_set_message_type (rule, -                                        DBUS_MESSAGE_TYPE_SIGNAL)) -    goto oom; +  if (!tokenize_rule (rule_text, tokens, error)) +    goto failed; -  return rule; +  i = 0; +  while (tokens[i].key != NULL) +    { +      const char *key = tokens[i].key; +      const char *value = tokens[i].value; +       +      if (strcmp (key, "type") == 0) +        { +          int t; + +          if (rule->flags & BUS_MATCH_MESSAGE_TYPE) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } +           +          t = dbus_message_type_from_string (value); +           +          if (!bus_match_rule_set_message_type (rule, t)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else if (strcmp (key, "sender") == 0) +        { +          if (rule->flags & BUS_MATCH_SENDER) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } + +          if (!bus_match_rule_set_sender (rule, value)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else if (strcmp (key, "interface") == 0) +        { +          if (rule->flags & BUS_MATCH_INTERFACE) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } + +          if (!bus_match_rule_set_interface (rule, value)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else if (strcmp (key, "member") == 0) +        { +          if (rule->flags & BUS_MATCH_MEMBER) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } + +          if (!bus_match_rule_set_member (rule, value)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else if (strcmp (key, "path") == 0) +        { +          if (rule->flags & BUS_MATCH_PATH) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } + +          if (!bus_match_rule_set_path (rule, value)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else if (strcmp (key, "destination") == 0) +        { +          if (rule->flags & BUS_MATCH_DESTINATION) +            { +              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                              "Key %s specified twice in match rule\n", key); +              goto failed; +            } + +          if (!bus_match_rule_set_destination (rule, value)) +            { +              BUS_SET_OOM (error); +              goto failed; +            } +        } +      else +        { +          dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, +                          "Unknown key \"%s\" in match rule", +                          key); +          goto failed; +        } + +      ++i; +    } +   + +  goto out; - oom: + failed: +  _DBUS_ASSERT_ERROR_IS_SET (error);    if (rule) -    bus_match_rule_unref (rule); -  BUS_SET_OOM (error); -  return NULL; +    { +      bus_match_rule_unref (rule); +      rule = NULL; +    } + + out: +   +  i = 0; +  while (tokens[i].key || tokens[i].value) +    { +      _dbus_assert (i < MAX_RULE_TOKENS); +      dbus_free (tokens[i].key); +      dbus_free (tokens[i].value); +      ++i; +    } +   +  return rule;  }  struct BusMatchmaker @@ -760,6 +1176,186 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,  #ifdef DBUS_BUILD_TESTS  #include "test.h" +#include <stdlib.h> + +static BusMatchRule* +check_parse (dbus_bool_t should_succeed, +             const char *text) +{ +  BusMatchRule *rule; +  DBusString str; +  DBusError error; + +  dbus_error_init (&error); + +  _dbus_string_init_const (&str, text); +   +  rule = bus_match_rule_parse (NULL, &str, &error); +  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) +    { +      dbus_error_free (&error); +      return NULL; +    } + +  if (should_succeed && rule == NULL) +    { +      _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n", +                  error.name, error.message, +                  _dbus_string_get_const_data (&str)); +      exit (1); +    } + +  if (!should_succeed && rule != NULL) +    { +      _dbus_warn ("Failed to fail to parse: \"%s\"\n", +                  _dbus_string_get_const_data (&str)); +      exit (1); +    } + +  dbus_error_free (&error); + +  return rule; +} + +static void +assert_large_rule (BusMatchRule *rule) +{ +  _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); +  _dbus_assert (rule->flags & BUS_MATCH_SENDER); +  _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); +  _dbus_assert (rule->flags & BUS_MATCH_MEMBER); +  _dbus_assert (rule->flags & BUS_MATCH_DESTINATION); +  _dbus_assert (rule->flags & BUS_MATCH_PATH); + +  _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); +  _dbus_assert (rule->interface != NULL); +  _dbus_assert (rule->member != NULL); +  _dbus_assert (rule->sender != NULL); +  _dbus_assert (rule->destination != NULL); +  _dbus_assert (rule->path != NULL); + +  _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0); +  _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0); +  _dbus_assert (strcmp (rule->member, "Foo") == 0); +  _dbus_assert (strcmp (rule->path, "/bar/foo") == 0); +  _dbus_assert (strcmp (rule->destination, ":452345-34") == 0); +} + +static dbus_bool_t +test_parsing (void *data) +{ +  BusMatchRule *rule; + +  rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345-34'"); +  if (rule != NULL) +    { +      assert_large_rule (rule); +      bus_match_rule_unref (rule); +    } + +  /* With extra whitespace and useless quotes */ +  rule = check_parse (TRUE, "    type='signal',  \tsender='org.freedes''ktop.DBusSender',   interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345-34'''''"); +  if (rule != NULL) +    { +      assert_large_rule (rule); +      bus_match_rule_unref (rule); +    } + + +  /* A simple signal connection */ +  rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'"); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); +      _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); +      _dbus_assert (rule->flags & BUS_MATCH_PATH); + +      _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); +      _dbus_assert (rule->interface != NULL); +      _dbus_assert (rule->path != NULL); + +      _dbus_assert (strcmp (rule->interface, "org.Bar") == 0); +      _dbus_assert (strcmp (rule->path, "/foo") == 0); +   +      bus_match_rule_unref (rule); +    } + +  /* Reject duplicates */ +  rule = check_parse (FALSE, "type='signal',type='method_call'"); +  _dbus_assert (rule == NULL); + +  /* Reject broken keys */ +  rule = check_parse (FALSE, "blah='signal'"); +  _dbus_assert (rule == NULL); + +  /* Allow empty rule */ +  rule = check_parse (TRUE, ""); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == 0); +       +      bus_match_rule_unref (rule); +    } + +  /* All-whitespace rule is the same as empty */ +  rule = check_parse (TRUE, "    \t"); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == 0); +       +      bus_match_rule_unref (rule); +    } + +  /* But with non-whitespace chars and no =value, it's not OK */ +  rule = check_parse (FALSE, "type"); +  _dbus_assert (rule == NULL); + +  /* Empty string values are allowed at the moment */ +  rule = check_parse (TRUE, "interface="); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE); +      _dbus_assert (rule->interface); +      _dbus_assert (strlen (rule->interface) == 0); +       +      bus_match_rule_unref (rule); +    } + +  /* Empty string expressed with quotes */ +  rule = check_parse (TRUE, "interface=''"); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE); +      _dbus_assert (rule->interface); +      _dbus_assert (strlen (rule->interface) == 0); +       +      bus_match_rule_unref (rule); +    } + +  /* Check whitespace in a value */ +  rule = check_parse (TRUE, "interface=   "); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE); +      _dbus_assert (rule->interface); +      _dbus_assert (strcmp (rule->interface, "   ") == 0); +       +      bus_match_rule_unref (rule); +    } + +  /* Check whitespace mixed with non-whitespace in a value */ +  rule = check_parse (TRUE, "interface= foo "); +  if (rule != NULL) +    { +      _dbus_assert (rule->flags == BUS_MATCH_INTERFACE); +      _dbus_assert (rule->interface); +      _dbus_assert (strcmp (rule->interface, " foo ") == 0); +       +      bus_match_rule_unref (rule); +    } +   +  return TRUE; +}  dbus_bool_t  bus_signals_test (const DBusString *test_data_dir) @@ -770,6 +1366,9 @@ bus_signals_test (const DBusString *test_data_dir)    bus_matchmaker_ref (matchmaker);    bus_matchmaker_unref (matchmaker);    bus_matchmaker_unref (matchmaker); + +  if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL)) +    _dbus_assert_not_reached ("Parsing match rules test failed");    return TRUE;  } diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index f229188a..b7b601bf 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -73,6 +73,7 @@ struct DBusError  #define DBUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod"  #define DBUS_ERROR_TIMED_OUT                  "org.freedesktop.DBus.Error.TimedOut"  #define DBUS_ERROR_MATCH_RULE_NOT_FOUND       "org.freedesktop.DBus.Error.MatchRuleNotFound" +#define DBUS_ERROR_MATCH_RULE_INVALID         "org.freedesktop.DBus.Error.MatchRuleInvalid"  #define DBUS_ERROR_SPAWN_EXEC_FAILED          "org.freedesktop.DBus.Error.Spawn.ExecFailed"  #define DBUS_ERROR_SPAWN_FORK_FAILED          "org.freedesktop.DBus.Error.Spawn.ForkFailed"  #define DBUS_ERROR_SPAWN_CHILD_EXITED         "org.freedesktop.DBus.Error.Spawn.ChildExited" diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 19457468..38fd3790 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -5416,6 +5416,34 @@ dbus_message_get_data (DBusMessage   *message,    return res;  } +/** + * Utility function to convert a machine-readable (not translated) + * string into a D-BUS message type. + * + * @code + *   "method_call"    -> DBUS_MESSAGE_TYPE_METHOD_CALL + *   "method_return"  -> DBUS_MESSAGE_TYPE_METHOD_RETURN + *   "signal"         -> DBUS_MESSAGE_TYPE_SIGNAL + *   "error"          -> DBUS_MESSAGE_TYPE_ERROR + *   anything else    -> DBUS_MESSAGE_TYPE_INVALID + * @endcode + *  + */ +int +dbus_message_type_from_string (const char *type_str) +{ +  if (strcmp (type_str, "method_call") == 0) +    return DBUS_MESSAGE_TYPE_METHOD_CALL; +  if (strcmp (type_str, "method_return") == 0) +    return DBUS_MESSAGE_TYPE_METHOD_RETURN; +  else if (strcmp (type_str, "signal") == 0) +    return DBUS_MESSAGE_TYPE_SIGNAL; +  else if (strcmp (type_str, "error") == 0) +    return DBUS_MESSAGE_TYPE_ERROR; +  else +    return DBUS_MESSAGE_TYPE_INVALID; +} +  /** @} */  #ifdef DBUS_BUILD_TESTS  #include "dbus-test.h" diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 888fe862..bfaf2f0d 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -275,6 +275,8 @@ dbus_bool_t dbus_message_set_data           (DBusMessage      *message,  void*       dbus_message_get_data           (DBusMessage      *message,                                               dbus_int32_t      slot); +int dbus_message_type_from_string (const char *type_str); +  DBUS_END_DECLS;  #endif /* DBUS_MESSAGE_H */ diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 06a87adb..d0cca2fd 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -86,11 +86,9 @@ main (int argc, char *argv[])    if (type_str != NULL)      { -      if (strcmp (type_str, "method_call") == 0) -        message_type = DBUS_MESSAGE_TYPE_METHOD_CALL; -      else if (strcmp (type_str, "signal") == 0) -        message_type = DBUS_MESSAGE_TYPE_SIGNAL; -      else +      message_type = dbus_message_type_from_string (type_str); +      if (!(message_type == DBUS_MESSAGE_TYPE_METHOD_CALL || +            message_type == DBUS_MESSAGE_TYPE_SIGNAL))          {            fprintf (stderr, "Message type \"%s\" is not supported\n",                     type_str); | 
