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