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