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