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