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