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