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