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