Home | History | Annotate | Download | only in bus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* signals.c  Bus signal connection implementation
      3  *
      4  * Copyright (C) 2003, 2005  Red Hat, Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #include <config.h>
     25 #include "signals.h"
     26 #include "services.h"
     27 #include "utils.h"
     28 #include <dbus/dbus-marshal-validate.h>
     29 
     30 struct BusMatchRule
     31 {
     32   int refcount;       /**< reference count */
     33 
     34   DBusConnection *matches_go_to; /**< Owner of the rule */
     35 
     36   unsigned int flags; /**< BusMatchFlags */
     37 
     38   int   message_type;
     39   char *interface;
     40   char *member;
     41   char *sender;
     42   char *destination;
     43   char *path;
     44 
     45   unsigned int *arg_lens;
     46   char **args;
     47   int args_len;
     48 };
     49 
     50 #define BUS_MATCH_ARG_IS_PATH  0x8000000u
     51 
     52 BusMatchRule*
     53 bus_match_rule_new (DBusConnection *matches_go_to)
     54 {
     55   BusMatchRule *rule;
     56 
     57   rule = dbus_new0 (BusMatchRule, 1);
     58   if (rule == NULL)
     59     return NULL;
     60 
     61   rule->refcount = 1;
     62   rule->matches_go_to = matches_go_to;
     63 
     64 #ifndef DBUS_BUILD_TESTS
     65   _dbus_assert (rule->matches_go_to != NULL);
     66 #endif
     67 
     68   return rule;
     69 }
     70 
     71 BusMatchRule *
     72 bus_match_rule_ref (BusMatchRule *rule)
     73 {
     74   _dbus_assert (rule->refcount > 0);
     75 
     76   rule->refcount += 1;
     77 
     78   return rule;
     79 }
     80 
     81 void
     82 bus_match_rule_unref (BusMatchRule *rule)
     83 {
     84   _dbus_assert (rule->refcount > 0);
     85 
     86   rule->refcount -= 1;
     87   if (rule->refcount == 0)
     88     {
     89       dbus_free (rule->interface);
     90       dbus_free (rule->member);
     91       dbus_free (rule->sender);
     92       dbus_free (rule->destination);
     93       dbus_free (rule->path);
     94       dbus_free (rule->arg_lens);
     95 
     96       /* can't use dbus_free_string_array() since there
     97        * are embedded NULL
     98        */
     99       if (rule->args)
    100         {
    101           int i;
    102 
    103           i = 0;
    104           while (i < rule->args_len)
    105             {
    106               if (rule->args[i])
    107                 dbus_free (rule->args[i]);
    108               ++i;
    109             }
    110 
    111           dbus_free (rule->args);
    112         }
    113 
    114       dbus_free (rule);
    115     }
    116 }
    117 
    118 #ifdef DBUS_ENABLE_VERBOSE_MODE
    119 /* Note this function does not do escaping, so it's only
    120  * good for debug spew at the moment
    121  */
    122 static char*
    123 match_rule_to_string (BusMatchRule *rule)
    124 {
    125   DBusString str;
    126   char *ret;
    127 
    128   if (!_dbus_string_init (&str))
    129     {
    130       char *s;
    131       while ((s = _dbus_strdup ("nomem")) == NULL)
    132         ; /* only OK for debug spew... */
    133       return s;
    134     }
    135 
    136   if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
    137     {
    138       /* FIXME make type readable */
    139       if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
    140         goto nomem;
    141     }
    142 
    143   if (rule->flags & BUS_MATCH_INTERFACE)
    144     {
    145       if (_dbus_string_get_length (&str) > 0)
    146         {
    147           if (!_dbus_string_append (&str, ","))
    148             goto nomem;
    149         }
    150 
    151       if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
    152         goto nomem;
    153     }
    154 
    155   if (rule->flags & BUS_MATCH_MEMBER)
    156     {
    157       if (_dbus_string_get_length (&str) > 0)
    158         {
    159           if (!_dbus_string_append (&str, ","))
    160             goto nomem;
    161         }
    162 
    163       if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
    164         goto nomem;
    165     }
    166 
    167   if (rule->flags & BUS_MATCH_PATH)
    168     {
    169       if (_dbus_string_get_length (&str) > 0)
    170         {
    171           if (!_dbus_string_append (&str, ","))
    172             goto nomem;
    173         }
    174 
    175       if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
    176         goto nomem;
    177     }
    178 
    179   if (rule->flags & BUS_MATCH_SENDER)
    180     {
    181       if (_dbus_string_get_length (&str) > 0)
    182         {
    183           if (!_dbus_string_append (&str, ","))
    184             goto nomem;
    185         }
    186 
    187       if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
    188         goto nomem;
    189     }
    190 
    191   if (rule->flags & BUS_MATCH_DESTINATION)
    192     {
    193       if (_dbus_string_get_length (&str) > 0)
    194         {
    195           if (!_dbus_string_append (&str, ","))
    196             goto nomem;
    197         }
    198 
    199       if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
    200         goto nomem;
    201     }
    202 
    203   if (rule->flags & BUS_MATCH_ARGS)
    204     {
    205       int i;
    206 
    207       _dbus_assert (rule->args != NULL);
    208 
    209       i = 0;
    210       while (i < rule->args_len)
    211         {
    212           if (rule->args[i] != NULL)
    213             {
    214               dbus_bool_t is_path;
    215 
    216               if (_dbus_string_get_length (&str) > 0)
    217                 {
    218                   if (!_dbus_string_append (&str, ","))
    219                     goto nomem;
    220                 }
    221 
    222               is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
    223 
    224               if (!_dbus_string_append_printf (&str,
    225                                                "arg%d%s='%s'",
    226                                                i, is_path ? "path" : "",
    227                                                rule->args[i]))
    228                 goto nomem;
    229             }
    230 
    231           ++i;
    232         }
    233     }
    234 
    235   if (!_dbus_string_steal_data (&str, &ret))
    236     goto nomem;
    237 
    238   _dbus_string_free (&str);
    239   return ret;
    240 
    241  nomem:
    242   _dbus_string_free (&str);
    243   {
    244     char *s;
    245     while ((s = _dbus_strdup ("nomem")) == NULL)
    246       ;  /* only OK for debug spew... */
    247     return s;
    248   }
    249 }
    250 #endif /* DBUS_ENABLE_VERBOSE_MODE */
    251 
    252 dbus_bool_t
    253 bus_match_rule_set_message_type (BusMatchRule *rule,
    254                                  int           type)
    255 {
    256   rule->flags |= BUS_MATCH_MESSAGE_TYPE;
    257 
    258   rule->message_type = type;
    259 
    260   return TRUE;
    261 }
    262 
    263 dbus_bool_t
    264 bus_match_rule_set_interface (BusMatchRule *rule,
    265                               const char   *interface)
    266 {
    267   char *new;
    268 
    269   _dbus_assert (interface != NULL);
    270 
    271   new = _dbus_strdup (interface);
    272   if (new == NULL)
    273     return FALSE;
    274 
    275   rule->flags |= BUS_MATCH_INTERFACE;
    276   dbus_free (rule->interface);
    277   rule->interface = new;
    278 
    279   return TRUE;
    280 }
    281 
    282 dbus_bool_t
    283 bus_match_rule_set_member (BusMatchRule *rule,
    284                            const char   *member)
    285 {
    286   char *new;
    287 
    288   _dbus_assert (member != NULL);
    289 
    290   new = _dbus_strdup (member);
    291   if (new == NULL)
    292     return FALSE;
    293 
    294   rule->flags |= BUS_MATCH_MEMBER;
    295   dbus_free (rule->member);
    296   rule->member = new;
    297 
    298   return TRUE;
    299 }
    300 
    301 dbus_bool_t
    302 bus_match_rule_set_sender (BusMatchRule *rule,
    303                            const char   *sender)
    304 {
    305   char *new;
    306 
    307   _dbus_assert (sender != NULL);
    308 
    309   new = _dbus_strdup (sender);
    310   if (new == NULL)
    311     return FALSE;
    312 
    313   rule->flags |= BUS_MATCH_SENDER;
    314   dbus_free (rule->sender);
    315   rule->sender = new;
    316 
    317   return TRUE;
    318 }
    319 
    320 dbus_bool_t
    321 bus_match_rule_set_destination (BusMatchRule *rule,
    322                                 const char   *destination)
    323 {
    324   char *new;
    325 
    326   _dbus_assert (destination != NULL);
    327 
    328   new = _dbus_strdup (destination);
    329   if (new == NULL)
    330     return FALSE;
    331 
    332   rule->flags |= BUS_MATCH_DESTINATION;
    333   dbus_free (rule->destination);
    334   rule->destination = new;
    335 
    336   return TRUE;
    337 }
    338 
    339 dbus_bool_t
    340 bus_match_rule_set_path (BusMatchRule *rule,
    341                          const char   *path)
    342 {
    343   char *new;
    344 
    345   _dbus_assert (path != NULL);
    346 
    347   new = _dbus_strdup (path);
    348   if (new == NULL)
    349     return FALSE;
    350 
    351   rule->flags |= BUS_MATCH_PATH;
    352   dbus_free (rule->path);
    353   rule->path = new;
    354 
    355   return TRUE;
    356 }
    357 
    358 dbus_bool_t
    359 bus_match_rule_set_arg (BusMatchRule     *rule,
    360                         int                arg,
    361                         const DBusString *value,
    362                         dbus_bool_t       is_path)
    363 {
    364   int length;
    365   char *new;
    366 
    367   _dbus_assert (value != NULL);
    368 
    369   /* args_len is the number of args not including null termination
    370    * in the char**
    371    */
    372   if (arg >= rule->args_len)
    373     {
    374       unsigned int *new_arg_lens;
    375       char **new_args;
    376       int new_args_len;
    377       int i;
    378 
    379       new_args_len = arg + 1;
    380 
    381       /* add another + 1 here for null termination */
    382       new_args = dbus_realloc (rule->args,
    383                                sizeof (char *) * (new_args_len + 1));
    384       if (new_args == NULL)
    385         return FALSE;
    386 
    387       /* NULL the new slots */
    388       i = rule->args_len;
    389       while (i <= new_args_len) /* <= for null termination */
    390         {
    391           new_args[i] = NULL;
    392           ++i;
    393         }
    394 
    395       rule->args = new_args;
    396 
    397       /* and now add to the lengths */
    398       new_arg_lens = dbus_realloc (rule->arg_lens,
    399                                    sizeof (int) * (new_args_len + 1));
    400 
    401       if (new_arg_lens == NULL)
    402         return FALSE;
    403 
    404       /* zero the new slots */
    405       i = rule->args_len;
    406       while (i <= new_args_len) /* <= for null termination */
    407         {
    408           new_arg_lens[i] = 0;
    409           ++i;
    410         }
    411 
    412       rule->arg_lens = new_arg_lens;
    413       rule->args_len = new_args_len;
    414     }
    415 
    416   length = _dbus_string_get_length (value);
    417   if (!_dbus_string_copy_data (value, &new))
    418     return FALSE;
    419 
    420   rule->flags |= BUS_MATCH_ARGS;
    421 
    422   dbus_free (rule->args[arg]);
    423   rule->arg_lens[arg] = length;
    424   rule->args[arg] = new;
    425 
    426   if (is_path)
    427     rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
    428 
    429   /* NULL termination didn't get busted */
    430   _dbus_assert (rule->args[rule->args_len] == NULL);
    431   _dbus_assert (rule->arg_lens[rule->args_len] == 0);
    432 
    433   return TRUE;
    434 }
    435 
    436 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
    437 
    438 static dbus_bool_t
    439 find_key (const DBusString *str,
    440           int               start,
    441           DBusString       *key,
    442           int              *value_pos,
    443           DBusError        *error)
    444 {
    445   const char *p;
    446   const char *s;
    447   const char *key_start;
    448   const char *key_end;
    449 
    450   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    451 
    452   s = _dbus_string_get_const_data (str);
    453 
    454   p = s + start;
    455 
    456   while (*p && ISWHITE (*p))
    457     ++p;
    458 
    459   key_start = p;
    460 
    461   while (*p && *p != '=' && !ISWHITE (*p))
    462     ++p;
    463 
    464   key_end = p;
    465 
    466   while (*p && ISWHITE (*p))
    467     ++p;
    468 
    469   if (key_start == key_end)
    470     {
    471       /* Empty match rules or trailing whitespace are OK */
    472       *value_pos = p - s;
    473       return TRUE;
    474     }
    475 
    476   if (*p != '=')
    477     {
    478       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    479                       "Match rule has a key with no subsequent '=' character");
    480       return FALSE;
    481     }
    482   ++p;
    483 
    484   if (!_dbus_string_append_len (key, key_start, key_end - key_start))
    485     {
    486       BUS_SET_OOM (error);
    487       return FALSE;
    488     }
    489 
    490   *value_pos = p - s;
    491 
    492   return TRUE;
    493 }
    494 
    495 static dbus_bool_t
    496 find_value (const DBusString *str,
    497             int               start,
    498             const char       *key,
    499             DBusString       *value,
    500             int              *value_end,
    501             DBusError        *error)
    502 {
    503   const char *p;
    504   const char *s;
    505   char quote_char;
    506   int orig_len;
    507 
    508   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    509 
    510   orig_len = _dbus_string_get_length (value);
    511 
    512   s = _dbus_string_get_const_data (str);
    513 
    514   p = s + start;
    515 
    516   quote_char = '\0';
    517 
    518   while (*p)
    519     {
    520       if (quote_char == '\0')
    521         {
    522           switch (*p)
    523             {
    524             case '\0':
    525               goto done;
    526 
    527             case '\'':
    528               quote_char = '\'';
    529               goto next;
    530 
    531             case ',':
    532               ++p;
    533               goto done;
    534 
    535             case '\\':
    536               quote_char = '\\';
    537               goto next;
    538 
    539             default:
    540               if (!_dbus_string_append_byte (value, *p))
    541                 {
    542                   BUS_SET_OOM (error);
    543                   goto failed;
    544                 }
    545             }
    546         }
    547       else if (quote_char == '\\')
    548         {
    549           /* \ only counts as an escape if escaping a quote mark */
    550           if (*p != '\'')
    551             {
    552               if (!_dbus_string_append_byte (value, '\\'))
    553                 {
    554                   BUS_SET_OOM (error);
    555                   goto failed;
    556                 }
    557             }
    558 
    559           if (!_dbus_string_append_byte (value, *p))
    560             {
    561               BUS_SET_OOM (error);
    562               goto failed;
    563             }
    564 
    565           quote_char = '\0';
    566         }
    567       else
    568         {
    569           _dbus_assert (quote_char == '\'');
    570 
    571           if (*p == '\'')
    572             {
    573               quote_char = '\0';
    574             }
    575           else
    576             {
    577               if (!_dbus_string_append_byte (value, *p))
    578                 {
    579                   BUS_SET_OOM (error);
    580                   goto failed;
    581                 }
    582             }
    583         }
    584 
    585     next:
    586       ++p;
    587     }
    588 
    589  done:
    590 
    591   if (quote_char == '\\')
    592     {
    593       if (!_dbus_string_append_byte (value, '\\'))
    594         {
    595           BUS_SET_OOM (error);
    596           goto failed;
    597         }
    598     }
    599   else if (quote_char == '\'')
    600     {
    601       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    602                       "Unbalanced quotation marks in match rule");
    603       goto failed;
    604     }
    605   else
    606     _dbus_assert (quote_char == '\0');
    607 
    608   /* Zero-length values are allowed */
    609 
    610   *value_end = p - s;
    611 
    612   return TRUE;
    613 
    614  failed:
    615   _DBUS_ASSERT_ERROR_IS_SET (error);
    616   _dbus_string_set_length (value, orig_len);
    617   return FALSE;
    618 }
    619 
    620 /* duplicates aren't allowed so the real legitimate max is only 6 or
    621  * so. Leaving extra so we don't have to bother to update it.
    622  * FIXME this is sort of busted now with arg matching, but we let
    623  * you match on up to 10 args for now
    624  */
    625 #define MAX_RULE_TOKENS 16
    626 
    627 /* this is slightly too high level to be termed a "token"
    628  * but let's not be pedantic.
    629  */
    630 typedef struct
    631 {
    632   char *key;
    633   char *value;
    634 } RuleToken;
    635 
    636 static dbus_bool_t
    637 tokenize_rule (const DBusString *rule_text,
    638                RuleToken         tokens[MAX_RULE_TOKENS],
    639                DBusError        *error)
    640 {
    641   int i;
    642   int pos;
    643   DBusString key;
    644   DBusString value;
    645   dbus_bool_t retval;
    646 
    647   retval = FALSE;
    648 
    649   if (!_dbus_string_init (&key))
    650     {
    651       BUS_SET_OOM (error);
    652       return FALSE;
    653     }
    654 
    655   if (!_dbus_string_init (&value))
    656     {
    657       _dbus_string_free (&key);
    658       BUS_SET_OOM (error);
    659       return FALSE;
    660     }
    661 
    662   i = 0;
    663   pos = 0;
    664   while (i < MAX_RULE_TOKENS &&
    665          pos < _dbus_string_get_length (rule_text))
    666     {
    667       _dbus_assert (tokens[i].key == NULL);
    668       _dbus_assert (tokens[i].value == NULL);
    669 
    670       if (!find_key (rule_text, pos, &key, &pos, error))
    671         goto out;
    672 
    673       if (_dbus_string_get_length (&key) == 0)
    674         goto next;
    675 
    676       if (!_dbus_string_steal_data (&key, &tokens[i].key))
    677         {
    678           BUS_SET_OOM (error);
    679           goto out;
    680         }
    681 
    682       if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
    683         goto out;
    684 
    685       if (!_dbus_string_steal_data (&value, &tokens[i].value))
    686         {
    687           BUS_SET_OOM (error);
    688           goto out;
    689         }
    690 
    691     next:
    692       ++i;
    693     }
    694 
    695   retval = TRUE;
    696 
    697  out:
    698   if (!retval)
    699     {
    700       i = 0;
    701       while (tokens[i].key || tokens[i].value)
    702         {
    703           dbus_free (tokens[i].key);
    704           dbus_free (tokens[i].value);
    705           tokens[i].key = NULL;
    706           tokens[i].value = NULL;
    707           ++i;
    708         }
    709     }
    710 
    711   _dbus_string_free (&key);
    712   _dbus_string_free (&value);
    713 
    714   return retval;
    715 }
    716 
    717 static dbus_bool_t
    718 bus_match_rule_parse_arg_match (BusMatchRule     *rule,
    719                                 const char       *key,
    720                                 const DBusString *value,
    721                                 DBusError        *error)
    722 {
    723   dbus_bool_t is_path;
    724   DBusString key_str;
    725   unsigned long arg;
    726   int length;
    727   int end;
    728 
    729   /* For now, arg0='foo' always implies that 'foo' is a
    730    * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing
    731    * if we wanted, which would specify another type, in which case
    732    * arg0='5' would have the 5 parsed as an int rather than string.
    733    */
    734 
    735   /* First we need to parse arg0 = 0, arg27 = 27 */
    736 
    737   _dbus_string_init_const (&key_str, key);
    738   length = _dbus_string_get_length (&key_str);
    739 
    740   if (_dbus_string_get_length (&key_str) < 4)
    741     {
    742       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    743                       "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key);
    744       goto failed;
    745     }
    746 
    747   if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end))
    748     {
    749       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    750                       "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key);
    751       goto failed;
    752     }
    753 
    754   if (end != length &&
    755       ((end + 4) != length ||
    756        !_dbus_string_ends_with_c_str (&key_str, "path")))
    757     {
    758       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    759                       "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key);
    760       goto failed;
    761     }
    762 
    763   is_path = end != length;
    764 
    765   /* If we didn't check this we could allocate a huge amount of RAM */
    766   if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
    767     {
    768       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    769                       "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER);
    770       goto failed;
    771     }
    772 
    773   if ((rule->flags & BUS_MATCH_ARGS) &&
    774       rule->args_len > (int) arg &&
    775       rule->args[arg] != NULL)
    776     {
    777       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    778                       "Argument %d matched more than once in match rule\n", key);
    779       goto failed;
    780     }
    781 
    782   if (!bus_match_rule_set_arg (rule, arg, value, is_path))
    783     {
    784       BUS_SET_OOM (error);
    785       goto failed;
    786     }
    787 
    788   return TRUE;
    789 
    790  failed:
    791   _DBUS_ASSERT_ERROR_IS_SET (error);
    792   return FALSE;
    793 }
    794 
    795 /*
    796  * The format is comma-separated with strings quoted with single quotes
    797  * as for the shell (to escape a literal single quote, use '\'').
    798  *
    799  * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
    800  * path='/bar/foo',destination=':452345.34'
    801  *
    802  */
    803 BusMatchRule*
    804 bus_match_rule_parse (DBusConnection   *matches_go_to,
    805                       const DBusString *rule_text,
    806                       DBusError        *error)
    807 {
    808   BusMatchRule *rule;
    809   RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
    810   int i;
    811 
    812   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    813 
    814   if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
    815     {
    816       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
    817                       "Match rule text is %d bytes, maximum is %d",
    818                       _dbus_string_get_length (rule_text),
    819                       DBUS_MAXIMUM_MATCH_RULE_LENGTH);
    820       return NULL;
    821     }
    822 
    823   memset (tokens, '\0', sizeof (tokens));
    824 
    825   rule = bus_match_rule_new (matches_go_to);
    826   if (rule == NULL)
    827     {
    828       BUS_SET_OOM (error);
    829       goto failed;
    830     }
    831 
    832   if (!tokenize_rule (rule_text, tokens, error))
    833     goto failed;
    834 
    835   i = 0;
    836   while (tokens[i].key != NULL)
    837     {
    838       DBusString tmp_str;
    839       int len;
    840       const char *key = tokens[i].key;
    841       const char *value = tokens[i].value;
    842 
    843       _dbus_string_init_const (&tmp_str, value);
    844       len = _dbus_string_get_length (&tmp_str);
    845 
    846       if (strcmp (key, "type") == 0)
    847         {
    848           int t;
    849 
    850           if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
    851             {
    852               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    853                               "Key %s specified twice in match rule\n", key);
    854               goto failed;
    855             }
    856 
    857           t = dbus_message_type_from_string (value);
    858 
    859           if (t == DBUS_MESSAGE_TYPE_INVALID)
    860             {
    861               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    862                               "Invalid message type (%s) in match rule\n", value);
    863               goto failed;
    864             }
    865 
    866           if (!bus_match_rule_set_message_type (rule, t))
    867             {
    868               BUS_SET_OOM (error);
    869               goto failed;
    870             }
    871         }
    872       else if (strcmp (key, "sender") == 0)
    873         {
    874           if (rule->flags & BUS_MATCH_SENDER)
    875             {
    876               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    877                               "Key %s specified twice in match rule\n", key);
    878               goto failed;
    879             }
    880 
    881           if (!_dbus_validate_bus_name (&tmp_str, 0, len))
    882             {
    883               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    884                               "Sender name '%s' is invalid\n", value);
    885               goto failed;
    886             }
    887 
    888           if (!bus_match_rule_set_sender (rule, value))
    889             {
    890               BUS_SET_OOM (error);
    891               goto failed;
    892             }
    893         }
    894       else if (strcmp (key, "interface") == 0)
    895         {
    896           if (rule->flags & BUS_MATCH_INTERFACE)
    897             {
    898               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    899                               "Key %s specified twice in match rule\n", key);
    900               goto failed;
    901             }
    902 
    903           if (!_dbus_validate_interface (&tmp_str, 0, len))
    904             {
    905               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    906                               "Interface name '%s' is invalid\n", value);
    907               goto failed;
    908             }
    909 
    910           if (!bus_match_rule_set_interface (rule, value))
    911             {
    912               BUS_SET_OOM (error);
    913               goto failed;
    914             }
    915         }
    916       else if (strcmp (key, "member") == 0)
    917         {
    918           if (rule->flags & BUS_MATCH_MEMBER)
    919             {
    920               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    921                               "Key %s specified twice in match rule\n", key);
    922               goto failed;
    923             }
    924 
    925           if (!_dbus_validate_member (&tmp_str, 0, len))
    926             {
    927               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    928                               "Member name '%s' is invalid\n", value);
    929               goto failed;
    930             }
    931 
    932           if (!bus_match_rule_set_member (rule, value))
    933             {
    934               BUS_SET_OOM (error);
    935               goto failed;
    936             }
    937         }
    938       else if (strcmp (key, "path") == 0)
    939         {
    940           if (rule->flags & BUS_MATCH_PATH)
    941             {
    942               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    943                               "Key %s specified twice in match rule\n", key);
    944               goto failed;
    945             }
    946 
    947           if (!_dbus_validate_path (&tmp_str, 0, len))
    948             {
    949               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    950                               "Path '%s' is invalid\n", value);
    951               goto failed;
    952             }
    953 
    954           if (!bus_match_rule_set_path (rule, value))
    955             {
    956               BUS_SET_OOM (error);
    957               goto failed;
    958             }
    959         }
    960       else if (strcmp (key, "destination") == 0)
    961         {
    962           if (rule->flags & BUS_MATCH_DESTINATION)
    963             {
    964               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    965                               "Key %s specified twice in match rule\n", key);
    966               goto failed;
    967             }
    968 
    969           if (!_dbus_validate_bus_name (&tmp_str, 0, len))
    970             {
    971               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    972                               "Destination name '%s' is invalid\n", value);
    973               goto failed;
    974             }
    975 
    976           if (!bus_match_rule_set_destination (rule, value))
    977             {
    978               BUS_SET_OOM (error);
    979               goto failed;
    980             }
    981         }
    982       else if (strncmp (key, "arg", 3) == 0)
    983         {
    984           if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
    985             goto failed;
    986         }
    987       else
    988         {
    989           dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
    990                           "Unknown key \"%s\" in match rule",
    991                           key);
    992           goto failed;
    993         }
    994 
    995       ++i;
    996     }
    997 
    998 
    999   goto out;
   1000 
   1001  failed:
   1002   _DBUS_ASSERT_ERROR_IS_SET (error);
   1003   if (rule)
   1004     {
   1005       bus_match_rule_unref (rule);
   1006       rule = NULL;
   1007     }
   1008 
   1009  out:
   1010 
   1011   i = 0;
   1012   while (tokens[i].key || tokens[i].value)
   1013     {
   1014       _dbus_assert (i < MAX_RULE_TOKENS);
   1015       dbus_free (tokens[i].key);
   1016       dbus_free (tokens[i].value);
   1017       ++i;
   1018     }
   1019 
   1020   return rule;
   1021 }
   1022 
   1023 typedef struct RulePool RulePool;
   1024 struct RulePool
   1025 {
   1026   /* Maps non-NULL interface names to non-NULL (DBusList **)s */
   1027   DBusHashTable *rules_by_iface;
   1028 
   1029   /* List of BusMatchRules which don't specify an interface */
   1030   DBusList *rules_without_iface;
   1031 };
   1032 
   1033 struct BusMatchmaker
   1034 {
   1035   int refcount;
   1036 
   1037   /* Pools of rules, grouped by the type of message they match. 0
   1038    * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
   1039    * type.
   1040    */
   1041   RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
   1042 };
   1043 
   1044 static void
   1045 rule_list_free (DBusList **rules)
   1046 {
   1047   while (*rules != NULL)
   1048     {
   1049       BusMatchRule *rule;
   1050 
   1051       rule = (*rules)->data;
   1052       bus_match_rule_unref (rule);
   1053       _dbus_list_remove_link (rules, *rules);
   1054     }
   1055 }
   1056 
   1057 static void
   1058 rule_list_ptr_free (DBusList **list)
   1059 {
   1060   /* We have to cope with NULL because the hash table frees the "existing"
   1061    * value (which is NULL) when creating a new table entry...
   1062    */
   1063   if (list != NULL)
   1064     {
   1065       rule_list_free (list);
   1066       dbus_free (list);
   1067     }
   1068 }
   1069 
   1070 BusMatchmaker*
   1071 bus_matchmaker_new (void)
   1072 {
   1073   BusMatchmaker *matchmaker;
   1074   int i;
   1075 
   1076   matchmaker = dbus_new0 (BusMatchmaker, 1);
   1077   if (matchmaker == NULL)
   1078     return NULL;
   1079 
   1080   matchmaker->refcount = 1;
   1081 
   1082   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
   1083     {
   1084       RulePool *p = matchmaker->rules_by_type + i;
   1085 
   1086       p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
   1087           dbus_free, (DBusFreeFunction) rule_list_ptr_free);
   1088 
   1089       if (p->rules_by_iface == NULL)
   1090         goto nomem;
   1091     }
   1092 
   1093   return matchmaker;
   1094 
   1095  nomem:
   1096   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
   1097     {
   1098       RulePool *p = matchmaker->rules_by_type + i;
   1099 
   1100       if (p->rules_by_iface == NULL)
   1101         break;
   1102       else
   1103         _dbus_hash_table_unref (p->rules_by_iface);
   1104     }
   1105 
   1106   return NULL;
   1107 }
   1108 
   1109 static DBusList **
   1110 bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
   1111                           int            message_type,
   1112                           const char    *interface,
   1113                           dbus_bool_t    create)
   1114 {
   1115   RulePool *p;
   1116 
   1117   _dbus_assert (message_type >= 0);
   1118   _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
   1119 
   1120   _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
   1121                  message_type,
   1122                  interface != NULL ? interface : "<null>");
   1123 
   1124   p = matchmaker->rules_by_type + message_type;
   1125 
   1126   if (interface == NULL)
   1127     {
   1128       return &p->rules_without_iface;
   1129     }
   1130   else
   1131     {
   1132       DBusList **list;
   1133 
   1134       list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
   1135 
   1136       if (list == NULL && create)
   1137         {
   1138           char *dupped_interface;
   1139 
   1140           list = dbus_new0 (DBusList *, 1);
   1141           if (list == NULL)
   1142             return NULL;
   1143 
   1144           dupped_interface = _dbus_strdup (interface);
   1145           if (dupped_interface == NULL)
   1146             {
   1147               dbus_free (list);
   1148               return NULL;
   1149             }
   1150 
   1151           _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
   1152                          interface);
   1153 
   1154           if (!_dbus_hash_table_insert_string (p->rules_by_iface,
   1155                                                dupped_interface, list))
   1156             {
   1157               dbus_free (list);
   1158               dbus_free (dupped_interface);
   1159               return NULL;
   1160             }
   1161         }
   1162 
   1163       return list;
   1164     }
   1165 }
   1166 
   1167 static void
   1168 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
   1169                          int            message_type,
   1170                          const char    *interface,
   1171                          DBusList     **rules)
   1172 {
   1173   RulePool *p;
   1174 
   1175   if (interface == NULL)
   1176     return;
   1177 
   1178   if (*rules != NULL)
   1179     return;
   1180 
   1181   _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
   1182                  message_type, interface);
   1183 
   1184   p = matchmaker->rules_by_type + message_type;
   1185 
   1186   _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
   1187       == rules);
   1188 
   1189   _dbus_hash_table_remove_string (p->rules_by_iface, interface);
   1190 }
   1191 
   1192 BusMatchmaker *
   1193 bus_matchmaker_ref (BusMatchmaker *matchmaker)
   1194 {
   1195   _dbus_assert (matchmaker->refcount > 0);
   1196 
   1197   matchmaker->refcount += 1;
   1198 
   1199   return matchmaker;
   1200 }
   1201 
   1202 void
   1203 bus_matchmaker_unref (BusMatchmaker *matchmaker)
   1204 {
   1205   _dbus_assert (matchmaker->refcount > 0);
   1206 
   1207   matchmaker->refcount -= 1;
   1208   if (matchmaker->refcount == 0)
   1209     {
   1210       int i;
   1211 
   1212       for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
   1213         {
   1214           RulePool *p = matchmaker->rules_by_type + i;
   1215 
   1216           _dbus_hash_table_unref (p->rules_by_iface);
   1217           rule_list_free (&p->rules_without_iface);
   1218         }
   1219 
   1220       dbus_free (matchmaker);
   1221     }
   1222 }
   1223 
   1224 /* The rule can't be modified after it's added. */
   1225 dbus_bool_t
   1226 bus_matchmaker_add_rule (BusMatchmaker   *matchmaker,
   1227                          BusMatchRule    *rule)
   1228 {
   1229   DBusList **rules;
   1230 
   1231   _dbus_assert (bus_connection_is_active (rule->matches_go_to));
   1232 
   1233   _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
   1234                  rule->message_type,
   1235                  rule->interface != NULL ? rule->interface : "<null>");
   1236 
   1237   rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
   1238                                     rule->interface, TRUE);
   1239 
   1240   if (rules == NULL)
   1241     return FALSE;
   1242 
   1243   if (!_dbus_list_append (rules, rule))
   1244     return FALSE;
   1245 
   1246   if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
   1247     {
   1248       _dbus_list_remove_last (rules, rule);
   1249       bus_matchmaker_gc_rules (matchmaker, rule->message_type,
   1250                                rule->interface, rules);
   1251       return FALSE;
   1252     }
   1253 
   1254   bus_match_rule_ref (rule);
   1255 
   1256 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1257   {
   1258     char *s = match_rule_to_string (rule);
   1259 
   1260     _dbus_verbose ("Added match rule %s to connection %p\n",
   1261                    s, rule->matches_go_to);
   1262     dbus_free (s);
   1263   }
   1264 #endif
   1265 
   1266   return TRUE;
   1267 }
   1268 
   1269 static dbus_bool_t
   1270 match_rule_equal (BusMatchRule *a,
   1271                   BusMatchRule *b)
   1272 {
   1273   if (a->flags != b->flags)
   1274     return FALSE;
   1275 
   1276   if (a->matches_go_to != b->matches_go_to)
   1277     return FALSE;
   1278 
   1279   if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
   1280       a->message_type != b->message_type)
   1281     return FALSE;
   1282 
   1283   if ((a->flags & BUS_MATCH_MEMBER) &&
   1284       strcmp (a->member, b->member) != 0)
   1285     return FALSE;
   1286 
   1287   if ((a->flags & BUS_MATCH_PATH) &&
   1288       strcmp (a->path, b->path) != 0)
   1289     return FALSE;
   1290 
   1291   if ((a->flags & BUS_MATCH_INTERFACE) &&
   1292       strcmp (a->interface, b->interface) != 0)
   1293     return FALSE;
   1294 
   1295   if ((a->flags & BUS_MATCH_SENDER) &&
   1296       strcmp (a->sender, b->sender) != 0)
   1297     return FALSE;
   1298 
   1299   if ((a->flags & BUS_MATCH_DESTINATION) &&
   1300       strcmp (a->destination, b->destination) != 0)
   1301     return FALSE;
   1302 
   1303   if (a->flags & BUS_MATCH_ARGS)
   1304     {
   1305       int i;
   1306 
   1307       if (a->args_len != b->args_len)
   1308         return FALSE;
   1309 
   1310       i = 0;
   1311       while (i < a->args_len)
   1312         {
   1313           int length;
   1314 
   1315           if ((a->args[i] != NULL) != (b->args[i] != NULL))
   1316             return FALSE;
   1317 
   1318           if (a->arg_lens[i] != b->arg_lens[i])
   1319             return FALSE;
   1320 
   1321           length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
   1322 
   1323           if (a->args[i] != NULL)
   1324             {
   1325               _dbus_assert (b->args[i] != NULL);
   1326               if (memcmp (a->args[i], b->args[i], length) != 0)
   1327                 return FALSE;
   1328             }
   1329 
   1330           ++i;
   1331         }
   1332     }
   1333 
   1334   return TRUE;
   1335 }
   1336 
   1337 static void
   1338 bus_matchmaker_remove_rule_link (DBusList       **rules,
   1339                                  DBusList        *link)
   1340 {
   1341   BusMatchRule *rule = link->data;
   1342 
   1343   bus_connection_remove_match_rule (rule->matches_go_to, rule);
   1344   _dbus_list_remove_link (rules, link);
   1345 
   1346 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1347   {
   1348     char *s = match_rule_to_string (rule);
   1349 
   1350     _dbus_verbose ("Removed match rule %s for connection %p\n",
   1351                    s, rule->matches_go_to);
   1352     dbus_free (s);
   1353   }
   1354 #endif
   1355 
   1356   bus_match_rule_unref (rule);
   1357 }
   1358 
   1359 void
   1360 bus_matchmaker_remove_rule (BusMatchmaker   *matchmaker,
   1361                             BusMatchRule    *rule)
   1362 {
   1363   DBusList **rules;
   1364 
   1365   _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
   1366                  rule->message_type,
   1367                  rule->interface != NULL ? rule->interface : "<null>");
   1368 
   1369   bus_connection_remove_match_rule (rule->matches_go_to, rule);
   1370 
   1371   rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
   1372                                     rule->interface, FALSE);
   1373 
   1374   /* We should only be asked to remove a rule by identity right after it was
   1375    * added, so there should be a list for it.
   1376    */
   1377   _dbus_assert (rules != NULL);
   1378 
   1379   _dbus_list_remove (rules, rule);
   1380   bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
   1381       rules);
   1382 
   1383 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1384   {
   1385     char *s = match_rule_to_string (rule);
   1386 
   1387     _dbus_verbose ("Removed match rule %s for connection %p\n",
   1388                    s, rule->matches_go_to);
   1389     dbus_free (s);
   1390   }
   1391 #endif
   1392 
   1393   bus_match_rule_unref (rule);
   1394 }
   1395 
   1396 /* Remove a single rule which is equal to the given rule by value */
   1397 dbus_bool_t
   1398 bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
   1399                                      BusMatchRule    *value,
   1400                                      DBusError       *error)
   1401 {
   1402   DBusList **rules;
   1403   DBusList *link = NULL;
   1404 
   1405   _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
   1406                  value->message_type,
   1407                  value->interface != NULL ? value->interface : "<null>");
   1408 
   1409   rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
   1410       value->interface, FALSE);
   1411 
   1412   if (rules != NULL)
   1413     {
   1414       /* we traverse backward because bus_connection_remove_match_rule()
   1415        * removes the most-recently-added rule
   1416        */
   1417       link = _dbus_list_get_last_link (rules);
   1418       while (link != NULL)
   1419         {
   1420           BusMatchRule *rule;
   1421           DBusList *prev;
   1422 
   1423           rule = link->data;
   1424           prev = _dbus_list_get_prev_link (rules, link);
   1425 
   1426           if (match_rule_equal (rule, value))
   1427             {
   1428               bus_matchmaker_remove_rule_link (rules, link);
   1429               break;
   1430             }
   1431 
   1432           link = prev;
   1433         }
   1434     }
   1435 
   1436   if (link == NULL)
   1437     {
   1438       dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
   1439                       "The given match rule wasn't found and can't be removed");
   1440       return FALSE;
   1441     }
   1442 
   1443   bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
   1444       rules);
   1445 
   1446   return TRUE;
   1447 }
   1448 
   1449 static void
   1450 rule_list_remove_by_connection (DBusList       **rules,
   1451                                 DBusConnection  *connection)
   1452 {
   1453   DBusList *link;
   1454 
   1455   link = _dbus_list_get_first_link (rules);
   1456   while (link != NULL)
   1457     {
   1458       BusMatchRule *rule;
   1459       DBusList *next;
   1460 
   1461       rule = link->data;
   1462       next = _dbus_list_get_next_link (rules, link);
   1463 
   1464       if (rule->matches_go_to == connection)
   1465         {
   1466           bus_matchmaker_remove_rule_link (rules, link);
   1467         }
   1468       else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
   1469                ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
   1470         {
   1471           /* The rule matches to/from a base service, see if it's the
   1472            * one being disconnected, since we know this service name
   1473            * will never be recycled.
   1474            */
   1475           const char *name;
   1476 
   1477           name = bus_connection_get_name (connection);
   1478           _dbus_assert (name != NULL); /* because we're an active connection */
   1479 
   1480           if (((rule->flags & BUS_MATCH_SENDER) &&
   1481                strcmp (rule->sender, name) == 0) ||
   1482               ((rule->flags & BUS_MATCH_DESTINATION) &&
   1483                strcmp (rule->destination, name) == 0))
   1484             {
   1485               bus_matchmaker_remove_rule_link (rules, link);
   1486             }
   1487         }
   1488 
   1489       link = next;
   1490     }
   1491 }
   1492 
   1493 void
   1494 bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
   1495                              DBusConnection  *connection)
   1496 {
   1497   int i;
   1498 
   1499   /* FIXME
   1500    *
   1501    * This scans all match rules on the bus. We could avoid that
   1502    * for the rules belonging to the connection, since we keep
   1503    * a list of those; but for the rules that just refer to
   1504    * the connection we'd need to do something more elaborate.
   1505    */
   1506 
   1507   _dbus_assert (bus_connection_is_active (connection));
   1508 
   1509   _dbus_verbose ("Removing all rules for connection %p\n", connection);
   1510 
   1511   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
   1512     {
   1513       RulePool *p = matchmaker->rules_by_type + i;
   1514       DBusHashIter iter;
   1515 
   1516       rule_list_remove_by_connection (&p->rules_without_iface, connection);
   1517 
   1518       _dbus_hash_iter_init (p->rules_by_iface, &iter);
   1519       while (_dbus_hash_iter_next (&iter))
   1520         {
   1521           DBusList **items = _dbus_hash_iter_get_value (&iter);
   1522 
   1523           rule_list_remove_by_connection (items, connection);
   1524 
   1525           if (*items == NULL)
   1526             _dbus_hash_iter_remove_entry (&iter);
   1527         }
   1528     }
   1529 }
   1530 
   1531 static dbus_bool_t
   1532 connection_is_primary_owner (DBusConnection *connection,
   1533                              const char     *service_name)
   1534 {
   1535   BusService *service;
   1536   DBusString str;
   1537   BusRegistry *registry;
   1538 
   1539   _dbus_assert (connection != NULL);
   1540 
   1541   registry = bus_connection_get_registry (connection);
   1542 
   1543   _dbus_string_init_const (&str, service_name);
   1544   service = bus_registry_lookup (registry, &str);
   1545 
   1546   if (service == NULL)
   1547     return FALSE; /* Service doesn't exist so connection can't own it. */
   1548 
   1549   return bus_service_get_primary_owners_connection (service) == connection;
   1550 }
   1551 
   1552 static dbus_bool_t
   1553 match_rule_matches (BusMatchRule    *rule,
   1554                     DBusConnection  *sender,
   1555                     DBusConnection  *addressed_recipient,
   1556                     DBusMessage     *message,
   1557                     BusMatchFlags    already_matched)
   1558 {
   1559   int flags;
   1560 
   1561   /* All features of the match rule are AND'd together,
   1562    * so FALSE if any of them don't match.
   1563    */
   1564 
   1565   /* sender/addressed_recipient of #NULL may mean bus driver,
   1566    * or for addressed_recipient may mean a message with no
   1567    * specific recipient (i.e. a signal)
   1568    */
   1569 
   1570   /* Don't bother re-matching features we've already checked implicitly. */
   1571   flags = rule->flags & (~already_matched);
   1572 
   1573   if (flags & BUS_MATCH_MESSAGE_TYPE)
   1574     {
   1575       _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
   1576 
   1577       if (rule->message_type != dbus_message_get_type (message))
   1578         return FALSE;
   1579     }
   1580 
   1581   if (flags & BUS_MATCH_INTERFACE)
   1582     {
   1583       const char *iface;
   1584 
   1585       _dbus_assert (rule->interface != NULL);
   1586 
   1587       iface = dbus_message_get_interface (message);
   1588       if (iface == NULL)
   1589         return FALSE;
   1590 
   1591       if (strcmp (iface, rule->interface) != 0)
   1592         return FALSE;
   1593     }
   1594 
   1595   if (flags & BUS_MATCH_MEMBER)
   1596     {
   1597       const char *member;
   1598 
   1599       _dbus_assert (rule->member != NULL);
   1600 
   1601       member = dbus_message_get_member (message);
   1602       if (member == NULL)
   1603         return FALSE;
   1604 
   1605       if (strcmp (member, rule->member) != 0)
   1606         return FALSE;
   1607     }
   1608 
   1609   if (flags & BUS_MATCH_SENDER)
   1610     {
   1611       _dbus_assert (rule->sender != NULL);
   1612 
   1613       if (sender == NULL)
   1614         {
   1615           if (strcmp (rule->sender,
   1616                       DBUS_SERVICE_DBUS) != 0)
   1617             return FALSE;
   1618         }
   1619       else
   1620         {
   1621           if (!connection_is_primary_owner (sender, rule->sender))
   1622             return FALSE;
   1623         }
   1624     }
   1625 
   1626   if (flags & BUS_MATCH_DESTINATION)
   1627     {
   1628       const char *destination;
   1629 
   1630       _dbus_assert (rule->destination != NULL);
   1631 
   1632       destination = dbus_message_get_destination (message);
   1633       if (destination == NULL)
   1634         return FALSE;
   1635 
   1636       if (addressed_recipient == NULL)
   1637         {
   1638           if (strcmp (rule->destination,
   1639                       DBUS_SERVICE_DBUS) != 0)
   1640             return FALSE;
   1641         }
   1642       else
   1643         {
   1644           if (!connection_is_primary_owner (addressed_recipient, rule->destination))
   1645             return FALSE;
   1646         }
   1647     }
   1648 
   1649   if (flags & BUS_MATCH_PATH)
   1650     {
   1651       const char *path;
   1652 
   1653       _dbus_assert (rule->path != NULL);
   1654 
   1655       path = dbus_message_get_path (message);
   1656       if (path == NULL)
   1657         return FALSE;
   1658 
   1659       if (strcmp (path, rule->path) != 0)
   1660         return FALSE;
   1661     }
   1662 
   1663   if (flags & BUS_MATCH_ARGS)
   1664     {
   1665       int i;
   1666       DBusMessageIter iter;
   1667 
   1668       _dbus_assert (rule->args != NULL);
   1669 
   1670       dbus_message_iter_init (message, &iter);
   1671 
   1672       i = 0;
   1673       while (i < rule->args_len)
   1674         {
   1675           int current_type;
   1676           const char *expected_arg;
   1677           int expected_length;
   1678           dbus_bool_t is_path;
   1679 
   1680           expected_arg = rule->args[i];
   1681           expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
   1682           is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
   1683 
   1684           current_type = dbus_message_iter_get_arg_type (&iter);
   1685 
   1686           if (expected_arg != NULL)
   1687             {
   1688               const char *actual_arg;
   1689               int actual_length;
   1690 
   1691               if (current_type != DBUS_TYPE_STRING)
   1692                 return FALSE;
   1693 
   1694               actual_arg = NULL;
   1695               dbus_message_iter_get_basic (&iter, &actual_arg);
   1696               _dbus_assert (actual_arg != NULL);
   1697 
   1698               actual_length = strlen (actual_arg);
   1699 
   1700               if (is_path)
   1701                 {
   1702                   if (actual_length < expected_length &&
   1703                       actual_arg[actual_length - 1] != '/')
   1704                     return FALSE;
   1705 
   1706                   if (expected_length < actual_length &&
   1707                       expected_arg[expected_length - 1] != '/')
   1708                     return FALSE;
   1709 
   1710                   if (memcmp (actual_arg, expected_arg,
   1711                               MIN (actual_length, expected_length)) != 0)
   1712                     return FALSE;
   1713                 }
   1714               else
   1715                 {
   1716                   if (expected_length != actual_length ||
   1717                       memcmp (expected_arg, actual_arg, expected_length) != 0)
   1718                     return FALSE;
   1719                 }
   1720 
   1721             }
   1722 
   1723           if (current_type != DBUS_TYPE_INVALID)
   1724             dbus_message_iter_next (&iter);
   1725 
   1726           ++i;
   1727         }
   1728     }
   1729 
   1730   return TRUE;
   1731 }
   1732 
   1733 static dbus_bool_t
   1734 get_recipients_from_list (DBusList       **rules,
   1735                           DBusConnection  *sender,
   1736                           DBusConnection  *addressed_recipient,
   1737                           DBusMessage     *message,
   1738                           DBusList       **recipients_p)
   1739 {
   1740   DBusList *link;
   1741 
   1742   if (rules == NULL)
   1743     return TRUE;
   1744 
   1745   link = _dbus_list_get_first_link (rules);
   1746   while (link != NULL)
   1747     {
   1748       BusMatchRule *rule;
   1749 
   1750       rule = link->data;
   1751 
   1752 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1753       {
   1754         char *s = match_rule_to_string (rule);
   1755 
   1756         _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
   1757                        s, rule->matches_go_to);
   1758         dbus_free (s);
   1759       }
   1760 #endif
   1761 
   1762       if (match_rule_matches (rule,
   1763                               sender, addressed_recipient, message,
   1764                               BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
   1765         {
   1766           _dbus_verbose ("Rule matched\n");
   1767 
   1768           /* Append to the list if we haven't already */
   1769           if (bus_connection_mark_stamp (rule->matches_go_to))
   1770             {
   1771               if (!_dbus_list_append (recipients_p, rule->matches_go_to))
   1772                 return FALSE;
   1773             }
   1774 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1775           else
   1776             {
   1777               _dbus_verbose ("Connection already receiving this message, so not adding again\n");
   1778             }
   1779 #endif /* DBUS_ENABLE_VERBOSE_MODE */
   1780         }
   1781 
   1782       link = _dbus_list_get_next_link (rules, link);
   1783     }
   1784 
   1785   return TRUE;
   1786 }
   1787 
   1788 dbus_bool_t
   1789 bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
   1790                                BusConnections  *connections,
   1791                                DBusConnection  *sender,
   1792                                DBusConnection  *addressed_recipient,
   1793                                DBusMessage     *message,
   1794                                DBusList       **recipients_p)
   1795 {
   1796   int type;
   1797   const char *interface;
   1798   DBusList **neither, **just_type, **just_iface, **both;
   1799 
   1800   _dbus_assert (*recipients_p == NULL);
   1801 
   1802   /* This avoids sending same message to the same connection twice.
   1803    * Purpose of the stamp instead of a bool is to avoid iterating over
   1804    * all connections resetting the bool each time.
   1805    */
   1806   bus_connections_increment_stamp (connections);
   1807 
   1808   /* addressed_recipient is already receiving the message, don't add to list.
   1809    * NULL addressed_recipient means either bus driver, or this is a signal
   1810    * and thus lacks a specific addressed_recipient.
   1811    */
   1812   if (addressed_recipient != NULL)
   1813     bus_connection_mark_stamp (addressed_recipient);
   1814 
   1815   type = dbus_message_get_type (message);
   1816   interface = dbus_message_get_interface (message);
   1817 
   1818   neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
   1819       NULL, FALSE);
   1820   just_type = just_iface = both = NULL;
   1821 
   1822   if (interface != NULL)
   1823     just_iface = bus_matchmaker_get_rules (matchmaker,
   1824         DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
   1825 
   1826   if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
   1827     {
   1828       just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
   1829 
   1830       if (interface != NULL)
   1831         both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
   1832     }
   1833 
   1834   if (!(get_recipients_from_list (neither, sender, addressed_recipient,
   1835                                   message, recipients_p) &&
   1836         get_recipients_from_list (just_iface, sender, addressed_recipient,
   1837                                   message, recipients_p) &&
   1838         get_recipients_from_list (just_type, sender, addressed_recipient,
   1839                                   message, recipients_p) &&
   1840         get_recipients_from_list (both, sender, addressed_recipient,
   1841                                   message, recipients_p)))
   1842     {
   1843       _dbus_list_clear (recipients_p);
   1844       return FALSE;
   1845     }
   1846 
   1847   return TRUE;
   1848 }
   1849 
   1850 #ifdef DBUS_BUILD_TESTS
   1851 #include "test.h"
   1852 #include <stdlib.h>
   1853 
   1854 static BusMatchRule*
   1855 check_parse (dbus_bool_t should_succeed,
   1856              const char *text)
   1857 {
   1858   BusMatchRule *rule;
   1859   DBusString str;
   1860   DBusError error;
   1861 
   1862   dbus_error_init (&error);
   1863 
   1864   _dbus_string_init_const (&str, text);
   1865 
   1866   rule = bus_match_rule_parse (NULL, &str, &error);
   1867   if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
   1868     {
   1869       dbus_error_free (&error);
   1870       return NULL;
   1871     }
   1872 
   1873   if (should_succeed && rule == NULL)
   1874     {
   1875       _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
   1876                   error.name, error.message,
   1877                   _dbus_string_get_const_data (&str));
   1878       exit (1);
   1879     }
   1880 
   1881   if (!should_succeed && rule != NULL)
   1882     {
   1883       _dbus_warn ("Failed to fail to parse: \"%s\"\n",
   1884                   _dbus_string_get_const_data (&str));
   1885       exit (1);
   1886     }
   1887 
   1888   dbus_error_free (&error);
   1889 
   1890   return rule;
   1891 }
   1892 
   1893 static void
   1894 assert_large_rule (BusMatchRule *rule)
   1895 {
   1896   _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
   1897   _dbus_assert (rule->flags & BUS_MATCH_SENDER);
   1898   _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
   1899   _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
   1900   _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
   1901   _dbus_assert (rule->flags & BUS_MATCH_PATH);
   1902 
   1903   _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
   1904   _dbus_assert (rule->interface != NULL);
   1905   _dbus_assert (rule->member != NULL);
   1906   _dbus_assert (rule->sender != NULL);
   1907   _dbus_assert (rule->destination != NULL);
   1908   _dbus_assert (rule->path != NULL);
   1909 
   1910   _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
   1911   _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
   1912   _dbus_assert (strcmp (rule->member, "Foo") == 0);
   1913   _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
   1914   _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
   1915 }
   1916 
   1917 static dbus_bool_t
   1918 test_parsing (void *data)
   1919 {
   1920   BusMatchRule *rule;
   1921 
   1922   rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
   1923   if (rule != NULL)
   1924     {
   1925       assert_large_rule (rule);
   1926       bus_match_rule_unref (rule);
   1927     }
   1928 
   1929   /* With extra whitespace and useless quotes */
   1930   rule = check_parse (TRUE, "    type='signal',  \tsender='org.freedes''ktop.DBusSender',   interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
   1931   if (rule != NULL)
   1932     {
   1933       assert_large_rule (rule);
   1934       bus_match_rule_unref (rule);
   1935     }
   1936 
   1937 
   1938   /* A simple signal connection */
   1939   rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
   1940   if (rule != NULL)
   1941     {
   1942       _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
   1943       _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
   1944       _dbus_assert (rule->flags & BUS_MATCH_PATH);
   1945 
   1946       _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
   1947       _dbus_assert (rule->interface != NULL);
   1948       _dbus_assert (rule->path != NULL);
   1949 
   1950       _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
   1951       _dbus_assert (strcmp (rule->path, "/foo") == 0);
   1952 
   1953       bus_match_rule_unref (rule);
   1954     }
   1955 
   1956   /* argN */
   1957   rule = check_parse (TRUE, "arg0='foo'");
   1958   if (rule != NULL)
   1959     {
   1960       _dbus_assert (rule->flags == BUS_MATCH_ARGS);
   1961       _dbus_assert (rule->args != NULL);
   1962       _dbus_assert (rule->args_len == 1);
   1963       _dbus_assert (rule->args[0] != NULL);
   1964       _dbus_assert (rule->args[1] == NULL);
   1965       _dbus_assert (strcmp (rule->args[0], "foo") == 0);
   1966 
   1967       bus_match_rule_unref (rule);
   1968     }
   1969 
   1970   rule = check_parse (TRUE, "arg1='foo'");
   1971   if (rule != NULL)
   1972     {
   1973       _dbus_assert (rule->flags == BUS_MATCH_ARGS);
   1974       _dbus_assert (rule->args != NULL);
   1975       _dbus_assert (rule->args_len == 2);
   1976       _dbus_assert (rule->args[0] == NULL);
   1977       _dbus_assert (rule->args[1] != NULL);
   1978       _dbus_assert (rule->args[2] == NULL);
   1979       _dbus_assert (strcmp (rule->args[1], "foo") == 0);
   1980 
   1981       bus_match_rule_unref (rule);
   1982     }
   1983 
   1984   rule = check_parse (TRUE, "arg2='foo'");
   1985   if (rule != NULL)
   1986     {
   1987       _dbus_assert (rule->flags == BUS_MATCH_ARGS);
   1988       _dbus_assert (rule->args != NULL);
   1989       _dbus_assert (rule->args_len == 3);
   1990       _dbus_assert (rule->args[0] == NULL);
   1991       _dbus_assert (rule->args[1] == NULL);
   1992       _dbus_assert (rule->args[2] != NULL);
   1993       _dbus_assert (rule->args[3] == NULL);
   1994       _dbus_assert (strcmp (rule->args[2], "foo") == 0);
   1995 
   1996       bus_match_rule_unref (rule);
   1997     }
   1998 
   1999   rule = check_parse (TRUE, "arg40='foo'");
   2000   if (rule != NULL)
   2001     {
   2002       _dbus_assert (rule->flags == BUS_MATCH_ARGS);
   2003       _dbus_assert (rule->args != NULL);
   2004       _dbus_assert (rule->args_len == 41);
   2005       _dbus_assert (rule->args[0] == NULL);
   2006       _dbus_assert (rule->args[1] == NULL);
   2007       _dbus_assert (rule->args[40] != NULL);
   2008       _dbus_assert (rule->args[41] == NULL);
   2009       _dbus_assert (strcmp (rule->args[40], "foo") == 0);
   2010 
   2011       bus_match_rule_unref (rule);
   2012     }
   2013 
   2014   rule = check_parse (TRUE, "arg63='foo'");
   2015   if (rule != NULL)
   2016     {
   2017       _dbus_assert (rule->flags == BUS_MATCH_ARGS);
   2018       _dbus_assert (rule->args != NULL);
   2019       _dbus_assert (rule->args_len == 64);
   2020       _dbus_assert (rule->args[0] == NULL);
   2021       _dbus_assert (rule->args[1] == NULL);
   2022       _dbus_assert (rule->args[63] != NULL);
   2023       _dbus_assert (rule->args[64] == NULL);
   2024       _dbus_assert (strcmp (rule->args[63], "foo") == 0);
   2025 
   2026       bus_match_rule_unref (rule);
   2027     }
   2028 
   2029   /* Too-large argN */
   2030   rule = check_parse (FALSE, "arg300='foo'");
   2031   _dbus_assert (rule == NULL);
   2032   rule = check_parse (FALSE, "arg64='foo'");
   2033   _dbus_assert (rule == NULL);
   2034 
   2035   /* No N in argN */
   2036   rule = check_parse (FALSE, "arg='foo'");
   2037   _dbus_assert (rule == NULL);
   2038   rule = check_parse (FALSE, "argv='foo'");
   2039   _dbus_assert (rule == NULL);
   2040   rule = check_parse (FALSE, "arg3junk='foo'");
   2041   _dbus_assert (rule == NULL);
   2042   rule = check_parse (FALSE, "argument='foo'");
   2043   _dbus_assert (rule == NULL);
   2044 
   2045   /* Reject duplicates */
   2046   rule = check_parse (FALSE, "type='signal',type='method_call'");
   2047   _dbus_assert (rule == NULL);
   2048 
   2049   /* Duplicates with the argN code */
   2050   rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
   2051   _dbus_assert (rule == NULL);
   2052   rule = check_parse (FALSE, "arg3='foo',arg3='bar'");
   2053   _dbus_assert (rule == NULL);
   2054   rule = check_parse (FALSE, "arg30='foo',arg30='bar'");
   2055   _dbus_assert (rule == NULL);
   2056 
   2057   /* Reject broken keys */
   2058   rule = check_parse (FALSE, "blah='signal'");
   2059   _dbus_assert (rule == NULL);
   2060 
   2061   /* Reject broken values */
   2062   rule = check_parse (FALSE, "type='chouin'");
   2063   _dbus_assert (rule == NULL);
   2064   rule = check_parse (FALSE, "interface='abc@def++'");
   2065   _dbus_assert (rule == NULL);
   2066   rule = check_parse (FALSE, "service='youpi'");
   2067   _dbus_assert (rule == NULL);
   2068 
   2069   /* Allow empty rule */
   2070   rule = check_parse (TRUE, "");
   2071   if (rule != NULL)
   2072     {
   2073       _dbus_assert (rule->flags == 0);
   2074 
   2075       bus_match_rule_unref (rule);
   2076     }
   2077 
   2078   /* All-whitespace rule is the same as empty */
   2079   rule = check_parse (TRUE, "    \t");
   2080   if (rule != NULL)
   2081     {
   2082       _dbus_assert (rule->flags == 0);
   2083 
   2084       bus_match_rule_unref (rule);
   2085     }
   2086 
   2087   /* But with non-whitespace chars and no =value, it's not OK */
   2088   rule = check_parse (FALSE, "type");
   2089   _dbus_assert (rule == NULL);
   2090 
   2091   return TRUE;
   2092 }
   2093 
   2094 static struct {
   2095   const char *first;
   2096   const char *second;
   2097 } equality_tests[] = {
   2098   { "type='signal'", "type='signal'" },
   2099   { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" },
   2100   { "type='signal',member='bar'", "member='bar',type='signal'" },
   2101   { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" },
   2102   { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" },
   2103   { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" },
   2104   { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" },
   2105   { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" },
   2106   { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
   2107   { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
   2108   { "arg3='fool'", "arg3='fool'" },
   2109   { "member='food'", "member='food'" }
   2110 };
   2111 
   2112 static void
   2113 test_equality (void)
   2114 {
   2115   int i;
   2116 
   2117   i = 0;
   2118   while (i < _DBUS_N_ELEMENTS (equality_tests))
   2119     {
   2120       BusMatchRule *first;
   2121       BusMatchRule *second;
   2122       int j;
   2123 
   2124       first = check_parse (TRUE, equality_tests[i].first);
   2125       _dbus_assert (first != NULL);
   2126       second = check_parse (TRUE, equality_tests[i].second);
   2127       _dbus_assert (second != NULL);
   2128 
   2129       if (!match_rule_equal (first, second))
   2130         {
   2131           _dbus_warn ("rule %s and %s should have been equal\n",
   2132                       equality_tests[i].first,
   2133                       equality_tests[i].second);
   2134           exit (1);
   2135         }
   2136 
   2137       bus_match_rule_unref (second);
   2138 
   2139       /* Check that the rule is not equal to any of the
   2140        * others besides its pair match
   2141        */
   2142       j = 0;
   2143       while (j < _DBUS_N_ELEMENTS (equality_tests))
   2144         {
   2145           if (i != j)
   2146             {
   2147               second = check_parse (TRUE, equality_tests[j].second);
   2148 
   2149               if (match_rule_equal (first, second))
   2150                 {
   2151                   _dbus_warn ("rule %s and %s should not have been equal\n",
   2152                               equality_tests[i].first,
   2153                               equality_tests[j].second);
   2154                   exit (1);
   2155                 }
   2156 
   2157               bus_match_rule_unref (second);
   2158             }
   2159 
   2160           ++j;
   2161         }
   2162 
   2163       bus_match_rule_unref (first);
   2164 
   2165       ++i;
   2166     }
   2167 }
   2168 
   2169 static const char*
   2170 should_match_message_1[] = {
   2171   "type='signal'",
   2172   "member='Frobated'",
   2173   "arg0='foobar'",
   2174   "type='signal',member='Frobated'",
   2175   "type='signal',member='Frobated',arg0='foobar'",
   2176   "member='Frobated',arg0='foobar'",
   2177   "type='signal',arg0='foobar'",
   2178   NULL
   2179 };
   2180 
   2181 static const char*
   2182 should_not_match_message_1[] = {
   2183   "type='method_call'",
   2184   "type='error'",
   2185   "type='method_return'",
   2186   "type='signal',member='Oopsed'",
   2187   "arg0='blah'",
   2188   "arg1='foobar'",
   2189   "arg2='foobar'",
   2190   "arg3='foobar'",
   2191   "arg0='3'",
   2192   "arg1='3'",
   2193   "arg0='foobar',arg1='abcdef'",
   2194   "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
   2195   "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
   2196   NULL
   2197 };
   2198 
   2199 static void
   2200 check_matches (dbus_bool_t  expected_to_match,
   2201                int          number,
   2202                DBusMessage *message,
   2203                const char  *rule_text)
   2204 {
   2205   BusMatchRule *rule;
   2206   dbus_bool_t matched;
   2207 
   2208   rule = check_parse (TRUE, rule_text);
   2209   _dbus_assert (rule != NULL);
   2210 
   2211   /* We can't test sender/destination rules since we pass NULL here */
   2212   matched = match_rule_matches (rule, NULL, NULL, message, 0);
   2213 
   2214   if (matched != expected_to_match)
   2215     {
   2216       _dbus_warn ("Expected rule %s to %s message %d, failed\n",
   2217                   rule_text, expected_to_match ?
   2218                   "match" : "not match", number);
   2219       exit (1);
   2220     }
   2221 
   2222   bus_match_rule_unref (rule);
   2223 }
   2224 
   2225 static void
   2226 check_matching (DBusMessage *message,
   2227                 int          number,
   2228                 const char **should_match,
   2229                 const char **should_not_match)
   2230 {
   2231   int i;
   2232 
   2233   i = 0;
   2234   while (should_match[i] != NULL)
   2235     {
   2236       check_matches (TRUE, number, message, should_match[i]);
   2237       ++i;
   2238     }
   2239 
   2240   i = 0;
   2241   while (should_not_match[i] != NULL)
   2242     {
   2243       check_matches (FALSE, number, message, should_not_match[i]);
   2244       ++i;
   2245     }
   2246 }
   2247 
   2248 static void
   2249 test_matching (void)
   2250 {
   2251   DBusMessage *message1;
   2252   const char *v_STRING;
   2253   dbus_int32_t v_INT32;
   2254 
   2255   message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
   2256   _dbus_assert (message1 != NULL);
   2257   if (!dbus_message_set_member (message1, "Frobated"))
   2258     _dbus_assert_not_reached ("oom");
   2259 
   2260   v_STRING = "foobar";
   2261   v_INT32 = 3;
   2262   if (!dbus_message_append_args (message1,
   2263                                  DBUS_TYPE_STRING, &v_STRING,
   2264                                  DBUS_TYPE_INT32, &v_INT32,
   2265                                  NULL))
   2266     _dbus_assert_not_reached ("oom");
   2267 
   2268   check_matching (message1, 1,
   2269                   should_match_message_1,
   2270                   should_not_match_message_1);
   2271 
   2272   dbus_message_unref (message1);
   2273 }
   2274 
   2275 dbus_bool_t
   2276 bus_signals_test (const DBusString *test_data_dir)
   2277 {
   2278   BusMatchmaker *matchmaker;
   2279 
   2280   matchmaker = bus_matchmaker_new ();
   2281   bus_matchmaker_ref (matchmaker);
   2282   bus_matchmaker_unref (matchmaker);
   2283   bus_matchmaker_unref (matchmaker);
   2284 
   2285   if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
   2286     _dbus_assert_not_reached ("Parsing match rules test failed");
   2287 
   2288   test_equality ();
   2289 
   2290   test_matching ();
   2291 
   2292   return TRUE;
   2293 }
   2294 
   2295 #endif /* DBUS_BUILD_TESTS */
   2296 
   2297