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