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