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