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