Merge branch 'dbus-1.10'
[platform/upstream/dbus.git] / bus / signals.c
index 902066f..6b7a464 100644 (file)
@@ -22,6 +22,9 @@
  */
 
 #include <config.h>
+
+#include <string.h>
+
 #include "signals.h"
 #include "services.h"
 #include "utils.h"
@@ -119,9 +122,44 @@ bus_match_rule_unref (BusMatchRule *rule)
 }
 
 #if defined(DBUS_ENABLE_VERBOSE_MODE) || defined(DBUS_ENABLE_STATS)
-/* Note this function does not do escaping, so it's only
- * good for debug spew at the moment
- */
+static dbus_bool_t
+append_key_and_escaped_value (DBusString *str, const char *token, const char *value)
+{
+  const char *p = value;
+
+  if (!_dbus_string_append_printf (str, "%s='", token))
+    return FALSE;
+
+  while (*p != '\0')
+    {
+      const char *next = strchr (p, '\'');
+
+      if (next)
+        {
+          if (!_dbus_string_append_printf (str, "%.*s", (int) (next - p), p))
+            return FALSE;
+          /* Horrible escape sequence: single quote cannot be escaped inside
+           * a single quoted string. So we close the single quote, escape the
+           * single quote, and reopen a single quote.
+           */
+          if (!_dbus_string_append_printf (str, "'\\''"))
+            return FALSE;
+          p = next + 1;
+        }
+      else
+        {
+          if (!_dbus_string_append_printf (str, "%s", p))
+            return FALSE;
+          break;
+        }
+    }
+
+  if (!_dbus_string_append_byte (str, '\''))
+    return FALSE;
+
+  return TRUE;
+}
+
 /* returns NULL if no memory */
 static char*
 match_rule_to_string (BusMatchRule *rule)
@@ -136,7 +174,7 @@ match_rule_to_string (BusMatchRule *rule)
   
   if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
     {
-      if (!_dbus_string_append_printf (&str, "type='%s'",
+      if (!append_key_and_escaped_value (&str, "type",
             dbus_message_type_to_string (rule->message_type)))
         goto nomem;
     }
@@ -149,7 +187,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
       
-      if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
+      if (!append_key_and_escaped_value (&str, "interface", rule->interface))
         goto nomem;
     }
 
@@ -161,7 +199,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
       
-      if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
+      if (!append_key_and_escaped_value (&str, "member", rule->member))
         goto nomem;
     }
 
@@ -173,7 +211,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
       
-      if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
+      if (!append_key_and_escaped_value (&str, "path", rule->path))
         goto nomem;
     }
 
@@ -185,7 +223,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
 
-      if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
+      if (!append_key_and_escaped_value (&str, "path_namespace", rule->path))
         goto nomem;
     }
 
@@ -197,7 +235,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
       
-      if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
+      if (!append_key_and_escaped_value (&str, "sender", rule->sender))
         goto nomem;
     }
 
@@ -209,7 +247,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
       
-      if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
+      if (!append_key_and_escaped_value (&str, "destination", rule->destination))
         goto nomem;
     }
 
@@ -221,7 +259,7 @@ match_rule_to_string (BusMatchRule *rule)
             goto nomem;
         }
 
-      if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
+      if (!append_key_and_escaped_value (&str, "eavesdrop",
             (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
             "true" : "false"))
         goto nomem;
@@ -250,11 +288,12 @@ match_rule_to_string (BusMatchRule *rule)
               is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
               
               if (!_dbus_string_append_printf (&str,
-                                               "arg%d%s='%s'",
+                                               "arg%d%s",
                                                i,
                                                is_path ? "path" :
-                                               is_namespace ? "namespace" : "",
-                                               rule->args[i]))
+                                               is_namespace ? "namespace" : ""))
+                goto nomem;
+              if (!append_key_and_escaped_value (&str, "", rule->args[i]))
                 goto nomem;
             }
           
@@ -372,6 +411,15 @@ bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
 }
 
 dbus_bool_t
+bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule)
+{
+  if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+dbus_bool_t
 bus_match_rule_set_path (BusMatchRule *rule,
                          const char   *path,
                          dbus_bool_t   is_namespace)
@@ -800,7 +848,8 @@ bus_match_rule_parse_arg_match (BusMatchRule     *rule,
 
   if (end != length)
     {
-      if ((end + strlen ("path")) == length &&
+      int len1 = strlen ("path");
+      if ((end + len1) == length &&
           _dbus_string_ends_with_c_str (&key_str, "path"))
         {
           is_path = TRUE;
@@ -822,7 +871,7 @@ bus_match_rule_parse_arg_match (BusMatchRule     *rule,
       else
         {
           dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
-              "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
+              "Key '%s' in match rule contains junk after argument number (%lu). Only 'arg%lupath' (for example) or 'arg0namespace' are valid", key, arg, arg);
           goto failed;
         }
     }
@@ -840,7 +889,7 @@ bus_match_rule_parse_arg_match (BusMatchRule     *rule,
       rule->args[arg] != NULL)
     {
       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
-                      "Argument %d matched more than once in match rule\n", key);
+                      "Argument %s matched more than once in match rule\n", key);
       goto failed;
     }
   
@@ -1838,9 +1887,18 @@ match_rule_matches (BusMatchRule    *rule,
         return FALSE;
 
       if (addressed_recipient == NULL)
-        {          
-          if (strcmp (rule->destination,
-                      DBUS_SERVICE_DBUS) != 0)
+        {
+          /* If the message is going to be delivered to the dbus-daemon
+           * itself, its destination will be "org.freedesktop.DBus",
+           * which we again match against the rule (see bus_dispatch()
+           * in bus/dispatch.c, which checks for o.fd.DBus first).
+           *
+           * If we are monitoring and we don't know who is going to receive
+           * the message (for instance because they haven't been activated yet),
+           * assume they will own the requested destination name and no other,
+           * and match the rule's destination against that.
+           */
+          if (strcmp (rule->destination, destination) != 0)
             return FALSE;
         }
       else
@@ -2143,7 +2201,7 @@ check_parse (dbus_bool_t should_succeed,
 
   if (should_succeed && rule == NULL)
     {
-      _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
+      _dbus_warn ("Failed to parse: %s: %s: \"%s\"",
                   error.name, error.message,
                   _dbus_string_get_const_data (&str));
       exit (1);
@@ -2151,7 +2209,7 @@ check_parse (dbus_bool_t should_succeed,
 
   if (!should_succeed && rule != NULL)
     {
-      _dbus_warn ("Failed to fail to parse: \"%s\"\n",
+      _dbus_warn ("Failed to fail to parse: \"%s\"",
                   _dbus_string_get_const_data (&str));
       exit (1);
     }
@@ -2300,7 +2358,7 @@ test_parsing (void *data)
   rule = check_parse (TRUE, "arg7path='/foo'");
   if (rule != NULL)
     {
-      _dbus_assert (rule->flags = BUS_MATCH_ARGS);
+      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
       _dbus_assert (rule->args != NULL);
       _dbus_assert (rule->args_len == 8);
       _dbus_assert (rule->args[7] != NULL);
@@ -2462,7 +2520,12 @@ static struct {
   { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
   { "arg3='fool'", "arg3='fool'" },
   { "arg0namespace='fool'", "arg0namespace='fool'" },
-  { "member='food'", "member='food'" }
+  { "member='food'", "member='food'" },
+  { "member=escape", "member='escape'" },
+  { "member=icecream", "member=ice'cream'" },
+  { "arg0='comma,type=comma',type=signal", "type=signal,arg0='comma,type=comma'" },
+  { "arg0=escap\\e", "arg0='escap\\e'" },
+  { "arg0=Time: 8 o\\'clock", "arg0='Time: 8 o'\\''clock'" },
 };
 
 static void
@@ -2475,6 +2538,8 @@ test_equality (void)
     {
       BusMatchRule *first;
       BusMatchRule *second;
+      char *first_str, *second_str;
+      BusMatchRule *first_reparsed, *second_reparsed;
       int j;
       
       first = check_parse (TRUE, equality_tests[i].first);
@@ -2484,12 +2549,29 @@ test_equality (void)
 
       if (!match_rule_equal (first, second))
         {
-          _dbus_warn ("rule %s and %s should have been equal\n",
+          _dbus_warn ("rule %s and %s should have been equal",
                       equality_tests[i].first,
                       equality_tests[i].second);
           exit (1);
         }
 
+      /* Check match_rule_to_string */
+      first_str = match_rule_to_string (first);
+      _dbus_assert (first_str != NULL);
+      second_str = match_rule_to_string (second);
+      _dbus_assert (second_str != NULL);
+      _dbus_assert (strcmp (first_str, second_str) == 0);
+      first_reparsed = check_parse (TRUE, first_str);
+      _dbus_assert (first_reparsed != NULL);
+      second_reparsed = check_parse (TRUE, second_str);
+      _dbus_assert (second_reparsed != NULL);
+      _dbus_assert (match_rule_equal (first, first_reparsed));
+      _dbus_assert (match_rule_equal (second, second_reparsed));
+      bus_match_rule_unref (first_reparsed);
+      bus_match_rule_unref (second_reparsed);
+      dbus_free (first_str);
+      dbus_free (second_str);
+
       bus_match_rule_unref (second);
 
       /* Check that the rule is not equal to any of the
@@ -2501,10 +2583,11 @@ test_equality (void)
           if (i != j)
             {
               second = check_parse (TRUE, equality_tests[j].second);
+              _dbus_assert (second != NULL);
 
               if (match_rule_equal (first, second))
                 {
-                  _dbus_warn ("rule %s and %s should not have been equal\n",
+                  _dbus_warn ("rule %s and %s should not have been equal",
                               equality_tests[i].first,
                               equality_tests[j].second);
                   exit (1);
@@ -2614,7 +2697,7 @@ check_matches (dbus_bool_t  expected_to_match,
 
   if (matched != expected_to_match)
     {
-      _dbus_warn ("Expected rule %s to %s message %d, failed\n",
+      _dbus_warn ("Expected rule %s to %s message %d, failed",
                   rule_text, expected_to_match ?
                   "match" : "not match", number);
       exit (1);
@@ -2743,7 +2826,7 @@ test_path_match (int type,
   if (matched != should_match)
     {
       _dbus_warn ("Expected rule %s to %s message "
-                  "with first arg %s of type '%c', failed\n",
+                  "with first arg %s of type '%c', failed",
                   rule_text,
                   should_match ? "match" : "not match",
                   path,