1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* signals.c Bus signal connection implementation
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 int refcount; /**< reference count */
31 DBusConnection *matches_go_to; /**< Owner of the rule */
33 unsigned int flags; /**< BusMatchFlags */
44 bus_match_rule_new (DBusConnection *matches_go_to)
48 rule = dbus_new0 (BusMatchRule, 1);
53 rule->matches_go_to = matches_go_to;
55 #ifndef DBUS_BUILD_TESTS
56 _dbus_assert (rule->matches_go_to != NULL);
63 bus_match_rule_ref (BusMatchRule *rule)
65 _dbus_assert (rule->refcount > 0);
73 bus_match_rule_unref (BusMatchRule *rule)
75 _dbus_assert (rule->refcount > 0);
78 if (rule->refcount == 0)
80 dbus_free (rule->interface);
81 dbus_free (rule->member);
82 dbus_free (rule->sender);
83 dbus_free (rule->destination);
84 dbus_free (rule->path);
89 #ifdef DBUS_ENABLE_VERBOSE_MODE
91 match_rule_to_string (BusMatchRule *rule)
96 if (!_dbus_string_init (&str))
99 while ((s = _dbus_strdup ("nomem")) == NULL)
100 ; /* only OK for debug spew... */
104 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
106 /* FIXME make type readable */
107 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
111 if (rule->flags & BUS_MATCH_INTERFACE)
113 if (_dbus_string_get_length (&str) > 0)
115 if (!_dbus_string_append (&str, ","))
119 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
123 if (rule->flags & BUS_MATCH_MEMBER)
125 if (_dbus_string_get_length (&str) > 0)
127 if (!_dbus_string_append (&str, ","))
131 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
135 if (rule->flags & BUS_MATCH_PATH)
137 if (_dbus_string_get_length (&str) > 0)
139 if (!_dbus_string_append (&str, ","))
143 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
147 if (rule->flags & BUS_MATCH_SENDER)
149 if (_dbus_string_get_length (&str) > 0)
151 if (!_dbus_string_append (&str, ","))
155 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
159 if (rule->flags & BUS_MATCH_DESTINATION)
161 if (_dbus_string_get_length (&str) > 0)
163 if (!_dbus_string_append (&str, ","))
167 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
171 if (!_dbus_string_steal_data (&str, &ret))
174 _dbus_string_free (&str);
178 _dbus_string_free (&str);
181 while ((s = _dbus_strdup ("nomem")) == NULL)
182 ; /* only OK for debug spew... */
186 #endif /* DBUS_ENABLE_VERBOSE_MODE */
189 bus_match_rule_set_message_type (BusMatchRule *rule,
192 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
194 rule->message_type = type;
200 bus_match_rule_set_interface (BusMatchRule *rule,
201 const char *interface)
205 _dbus_assert (interface != NULL);
207 new = _dbus_strdup (interface);
211 rule->flags |= BUS_MATCH_INTERFACE;
212 dbus_free (rule->interface);
213 rule->interface = new;
219 bus_match_rule_set_member (BusMatchRule *rule,
224 _dbus_assert (member != NULL);
226 new = _dbus_strdup (member);
230 rule->flags |= BUS_MATCH_MEMBER;
231 dbus_free (rule->member);
238 bus_match_rule_set_sender (BusMatchRule *rule,
243 _dbus_assert (sender != NULL);
245 new = _dbus_strdup (sender);
249 rule->flags |= BUS_MATCH_SENDER;
250 dbus_free (rule->sender);
257 bus_match_rule_set_destination (BusMatchRule *rule,
258 const char *destination)
262 _dbus_assert (destination != NULL);
264 new = _dbus_strdup (destination);
268 rule->flags |= BUS_MATCH_DESTINATION;
269 dbus_free (rule->destination);
270 rule->destination = new;
276 bus_match_rule_set_path (BusMatchRule *rule,
281 _dbus_assert (path != NULL);
283 new = _dbus_strdup (path);
287 rule->flags |= BUS_MATCH_PATH;
288 dbus_free (rule->path);
294 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
297 find_key (const DBusString *str,
305 const char *key_start;
308 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
310 s = _dbus_string_get_const_data (str);
314 while (*p && ISWHITE (*p))
319 while (*p && *p != '=' && !ISWHITE (*p))
324 while (*p && ISWHITE (*p))
327 if (key_start == key_end)
329 /* Empty match rules or trailing whitespace are OK */
336 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
337 "Match rule has a key with no subsequent '=' character");
342 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
354 find_value (const DBusString *str,
366 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
368 orig_len = _dbus_string_get_length (value);
370 s = _dbus_string_get_const_data (str);
378 if (quote_char == '\0')
398 if (!_dbus_string_append_byte (value, *p))
405 else if (quote_char == '\\')
407 /* \ only counts as an escape if escaping a quote mark */
410 if (!_dbus_string_append_byte (value, '\\'))
417 if (!_dbus_string_append_byte (value, *p))
427 _dbus_assert (quote_char == '\'');
435 if (!_dbus_string_append_byte (value, *p))
449 if (quote_char == '\\')
451 if (!_dbus_string_append_byte (value, '\\'))
457 else if (quote_char == '\'')
459 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
460 "Unbalanced quotation marks in match rule");
464 _dbus_assert (quote_char == '\0');
466 /* Zero-length values are allowed */
473 _DBUS_ASSERT_ERROR_IS_SET (error);
474 _dbus_string_set_length (value, orig_len);
478 /* duplicates aren't allowed so the real legitimate max is only 6 or
479 * so. Leaving extra so we don't have to bother to update it.
481 #define MAX_RULE_TOKENS 16
483 /* this is slightly too high level to be termed a "token"
484 * but let's not be pedantic.
493 tokenize_rule (const DBusString *rule_text,
494 RuleToken tokens[MAX_RULE_TOKENS],
505 if (!_dbus_string_init (&key))
511 if (!_dbus_string_init (&value))
513 _dbus_string_free (&key);
520 while (i < MAX_RULE_TOKENS &&
521 pos < _dbus_string_get_length (rule_text))
523 _dbus_assert (tokens[i].key == NULL);
524 _dbus_assert (tokens[i].value == NULL);
526 if (!find_key (rule_text, pos, &key, &pos, error))
529 if (_dbus_string_get_length (&key) == 0)
532 if (!_dbus_string_steal_data (&key, &tokens[i].key))
538 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
541 if (!_dbus_string_steal_data (&value, &tokens[i].value))
557 while (tokens[i].key || tokens[i].value)
559 dbus_free (tokens[i].key);
560 dbus_free (tokens[i].value);
561 tokens[i].key = NULL;
562 tokens[i].value = NULL;
567 _dbus_string_free (&key);
568 _dbus_string_free (&value);
574 * The format is comma-separated with strings quoted with single quotes
575 * as for the shell (to escape a literal single quote, use '\'').
577 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
578 * path='/bar/foo',destination=':452345-34'
582 bus_match_rule_parse (DBusConnection *matches_go_to,
583 const DBusString *rule_text,
587 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
590 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
592 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
594 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
595 "Match rule text is %d bytes, maximum is %d",
596 _dbus_string_get_length (rule_text),
597 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
601 memset (tokens, '\0', sizeof (tokens));
603 rule = bus_match_rule_new (matches_go_to);
610 if (!tokenize_rule (rule_text, tokens, error))
614 while (tokens[i].key != NULL)
616 const char *key = tokens[i].key;
617 const char *value = tokens[i].value;
619 if (strcmp (key, "type") == 0)
623 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
625 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
626 "Key %s specified twice in match rule\n", key);
630 t = dbus_message_type_from_string (value);
632 if (!bus_match_rule_set_message_type (rule, t))
638 else if (strcmp (key, "sender") == 0)
640 if (rule->flags & BUS_MATCH_SENDER)
642 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
643 "Key %s specified twice in match rule\n", key);
647 if (!bus_match_rule_set_sender (rule, value))
653 else if (strcmp (key, "interface") == 0)
655 if (rule->flags & BUS_MATCH_INTERFACE)
657 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
658 "Key %s specified twice in match rule\n", key);
662 if (!bus_match_rule_set_interface (rule, value))
668 else if (strcmp (key, "member") == 0)
670 if (rule->flags & BUS_MATCH_MEMBER)
672 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
673 "Key %s specified twice in match rule\n", key);
677 if (!bus_match_rule_set_member (rule, value))
683 else if (strcmp (key, "path") == 0)
685 if (rule->flags & BUS_MATCH_PATH)
687 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
688 "Key %s specified twice in match rule\n", key);
692 if (!bus_match_rule_set_path (rule, value))
698 else if (strcmp (key, "destination") == 0)
700 if (rule->flags & BUS_MATCH_DESTINATION)
702 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
703 "Key %s specified twice in match rule\n", key);
707 if (!bus_match_rule_set_destination (rule, value))
715 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
716 "Unknown key \"%s\" in match rule",
728 _DBUS_ASSERT_ERROR_IS_SET (error);
731 bus_match_rule_unref (rule);
738 while (tokens[i].key || tokens[i].value)
740 _dbus_assert (i < MAX_RULE_TOKENS);
741 dbus_free (tokens[i].key);
742 dbus_free (tokens[i].value);
757 bus_matchmaker_new (void)
759 BusMatchmaker *matchmaker;
761 matchmaker = dbus_new0 (BusMatchmaker, 1);
762 if (matchmaker == NULL)
765 matchmaker->refcount = 1;
771 bus_matchmaker_ref (BusMatchmaker *matchmaker)
773 _dbus_assert (matchmaker->refcount > 0);
775 matchmaker->refcount += 1;
781 bus_matchmaker_unref (BusMatchmaker *matchmaker)
783 _dbus_assert (matchmaker->refcount > 0);
785 matchmaker->refcount -= 1;
786 if (matchmaker->refcount == 0)
788 while (matchmaker->all_rules != NULL)
792 rule = matchmaker->all_rules->data;
793 bus_match_rule_unref (rule);
794 _dbus_list_remove_link (&matchmaker->all_rules,
795 matchmaker->all_rules);
798 dbus_free (matchmaker);
802 /* The rule can't be modified after it's added. */
804 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
807 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
809 if (!_dbus_list_append (&matchmaker->all_rules, rule))
812 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
814 _dbus_list_remove_last (&matchmaker->all_rules, rule);
818 bus_match_rule_ref (rule);
820 #ifdef DBUS_ENABLE_VERBOSE_MODE
822 char *s = match_rule_to_string (rule);
824 _dbus_verbose ("Added match rule %s to connection %p\n",
825 s, rule->matches_go_to);
834 match_rule_equal (BusMatchRule *a,
837 if (a->flags != b->flags)
840 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
841 a->message_type != b->message_type)
844 if ((a->flags & BUS_MATCH_MEMBER) &&
845 strcmp (a->member, b->member) != 0)
848 if ((a->flags & BUS_MATCH_PATH) &&
849 strcmp (a->path, b->path) != 0)
852 if ((a->flags & BUS_MATCH_INTERFACE) &&
853 strcmp (a->interface, b->interface) != 0)
856 if ((a->flags & BUS_MATCH_SENDER) &&
857 strcmp (a->sender, b->sender) != 0)
860 if ((a->flags & BUS_MATCH_DESTINATION) &&
861 strcmp (a->destination, b->destination) != 0)
868 bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
871 BusMatchRule *rule = link->data;
873 bus_connection_remove_match_rule (rule->matches_go_to, rule);
874 _dbus_list_remove_link (&matchmaker->all_rules, link);
876 #ifdef DBUS_ENABLE_VERBOSE_MODE
878 char *s = match_rule_to_string (rule);
880 _dbus_verbose ("Removed match rule %s for connection %p\n",
881 s, rule->matches_go_to);
886 bus_match_rule_unref (rule);
890 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
893 bus_connection_remove_match_rule (rule->matches_go_to, rule);
894 _dbus_list_remove (&matchmaker->all_rules, rule);
896 #ifdef DBUS_ENABLE_VERBOSE_MODE
898 char *s = match_rule_to_string (rule);
900 _dbus_verbose ("Removed match rule %s for connection %p\n",
901 s, rule->matches_go_to);
906 bus_match_rule_unref (rule);
909 /* Remove a single rule which is equal to the given rule by value */
911 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
915 /* FIXME this is an unoptimized linear scan */
919 /* we traverse backward because bus_connection_remove_match_rule()
920 * removes the most-recently-added rule
922 link = _dbus_list_get_last_link (&matchmaker->all_rules);
929 prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
931 if (match_rule_equal (rule, value))
933 bus_matchmaker_remove_rule_link (matchmaker, link);
942 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
943 "The given match rule wasn't found and can't be removed");
951 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
952 DBusConnection *disconnected)
958 * This scans all match rules on the bus. We could avoid that
959 * for the rules belonging to the connection, since we keep
960 * a list of those; but for the rules that just refer to
961 * the connection we'd need to do something more elaborate.
965 _dbus_assert (bus_connection_is_active (disconnected));
967 link = _dbus_list_get_first_link (&matchmaker->all_rules);
974 next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
976 if (rule->matches_go_to == disconnected)
978 bus_matchmaker_remove_rule_link (matchmaker, link);
980 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
981 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
983 /* The rule matches to/from a base service, see if it's the
984 * one being disconnected, since we know this service name
985 * will never be recycled.
989 name = bus_connection_get_name (disconnected);
990 _dbus_assert (name != NULL); /* because we're an active connection */
992 if (((rule->flags & BUS_MATCH_SENDER) &&
993 strcmp (rule->sender, name) == 0) ||
994 ((rule->flags & BUS_MATCH_DESTINATION) &&
995 strcmp (rule->destination, name) == 0))
997 bus_matchmaker_remove_rule_link (matchmaker, link);
1006 connection_is_primary_owner (DBusConnection *connection,
1007 const char *service_name)
1009 BusService *service;
1011 BusRegistry *registry;
1013 _dbus_assert (connection != NULL);
1015 registry = bus_connection_get_registry (connection);
1017 _dbus_string_init_const (&str, service_name);
1018 service = bus_registry_lookup (registry, &str);
1020 if (service == NULL)
1021 return FALSE; /* Service doesn't exist so connection can't own it. */
1023 return bus_service_get_primary_owner (service) == connection;
1027 match_rule_matches (BusMatchRule *rule,
1028 BusConnections *connections,
1029 DBusConnection *sender,
1030 DBusConnection *addressed_recipient,
1031 DBusMessage *message)
1033 /* All features of the match rule are AND'd together,
1034 * so FALSE if any of them don't match.
1037 /* sender/addressed_recipient of #NULL may mean bus driver,
1038 * or for addressed_recipient may mean a message with no
1039 * specific recipient (i.e. a signal)
1042 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
1044 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1046 if (rule->message_type != dbus_message_get_type (message))
1050 if (rule->flags & BUS_MATCH_INTERFACE)
1054 _dbus_assert (rule->interface != NULL);
1056 iface = dbus_message_get_interface (message);
1060 if (strcmp (iface, rule->interface) != 0)
1064 if (rule->flags & BUS_MATCH_MEMBER)
1068 _dbus_assert (rule->member != NULL);
1070 member = dbus_message_get_member (message);
1074 if (strcmp (member, rule->member) != 0)
1078 if (rule->flags & BUS_MATCH_SENDER)
1080 _dbus_assert (rule->sender != NULL);
1084 if (strcmp (rule->sender,
1085 DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) != 0)
1090 if (!connection_is_primary_owner (sender, rule->sender))
1095 if (rule->flags & BUS_MATCH_DESTINATION)
1097 const char *destination;
1099 _dbus_assert (rule->destination != NULL);
1101 destination = dbus_message_get_destination (message);
1102 if (destination == NULL)
1105 if (addressed_recipient == NULL)
1107 if (strcmp (rule->destination,
1108 DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) != 0)
1113 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1118 if (rule->flags & BUS_MATCH_PATH)
1122 _dbus_assert (rule->path != NULL);
1124 path = dbus_message_get_path (message);
1128 if (strcmp (path, rule->path) != 0)
1136 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1137 BusConnections *connections,
1138 DBusConnection *sender,
1139 DBusConnection *addressed_recipient,
1140 DBusMessage *message,
1141 DBusList **recipients_p)
1143 /* FIXME for now this is a wholly unoptimized linear search */
1144 /* Guessing the important optimization is to skip the signal-related
1145 * match lists when processing method call and exception messages.
1146 * So separate match rule lists for signals?
1151 _dbus_assert (*recipients_p == NULL);
1153 /* This avoids sending same message to the same connection twice.
1154 * Purpose of the stamp instead of a bool is to avoid iterating over
1155 * all connections resetting the bool each time.
1157 bus_connections_increment_stamp (connections);
1159 /* addressed_recipient is already receiving the message, don't add to list.
1160 * NULL addressed_recipient means either bus driver, or this is a signal
1161 * and thus lacks a specific addressed_recipient.
1163 if (addressed_recipient != NULL)
1164 bus_connection_mark_stamp (addressed_recipient);
1166 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1167 while (link != NULL)
1173 #ifdef DBUS_ENABLE_VERBOSE_MODE
1175 char *s = match_rule_to_string (rule);
1177 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1178 s, rule->matches_go_to);
1183 if (match_rule_matches (rule, connections,
1184 sender, addressed_recipient, message))
1186 _dbus_verbose ("Rule matched\n");
1188 /* Append to the list if we haven't already */
1189 if (bus_connection_mark_stamp (rule->matches_go_to))
1191 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1194 #ifdef DBUS_ENABLE_VERBOSE_MODE
1197 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1199 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1202 link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1208 _dbus_list_clear (recipients_p);
1212 #ifdef DBUS_BUILD_TESTS
1216 static BusMatchRule*
1217 check_parse (dbus_bool_t should_succeed,
1224 dbus_error_init (&error);
1226 _dbus_string_init_const (&str, text);
1228 rule = bus_match_rule_parse (NULL, &str, &error);
1229 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1231 dbus_error_free (&error);
1235 if (should_succeed && rule == NULL)
1237 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1238 error.name, error.message,
1239 _dbus_string_get_const_data (&str));
1243 if (!should_succeed && rule != NULL)
1245 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1246 _dbus_string_get_const_data (&str));
1250 dbus_error_free (&error);
1256 assert_large_rule (BusMatchRule *rule)
1258 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1259 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1260 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1261 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1262 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1263 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1265 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1266 _dbus_assert (rule->interface != NULL);
1267 _dbus_assert (rule->member != NULL);
1268 _dbus_assert (rule->sender != NULL);
1269 _dbus_assert (rule->destination != NULL);
1270 _dbus_assert (rule->path != NULL);
1272 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1273 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1274 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1275 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1276 _dbus_assert (strcmp (rule->destination, ":452345-34") == 0);
1280 test_parsing (void *data)
1284 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345-34'");
1287 assert_large_rule (rule);
1288 bus_match_rule_unref (rule);
1291 /* With extra whitespace and useless quotes */
1292 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345-34'''''");
1295 assert_large_rule (rule);
1296 bus_match_rule_unref (rule);
1300 /* A simple signal connection */
1301 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1304 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1305 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1306 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1308 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1309 _dbus_assert (rule->interface != NULL);
1310 _dbus_assert (rule->path != NULL);
1312 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
1313 _dbus_assert (strcmp (rule->path, "/foo") == 0);
1315 bus_match_rule_unref (rule);
1318 /* Reject duplicates */
1319 rule = check_parse (FALSE, "type='signal',type='method_call'");
1320 _dbus_assert (rule == NULL);
1322 /* Reject broken keys */
1323 rule = check_parse (FALSE, "blah='signal'");
1324 _dbus_assert (rule == NULL);
1326 /* Allow empty rule */
1327 rule = check_parse (TRUE, "");
1330 _dbus_assert (rule->flags == 0);
1332 bus_match_rule_unref (rule);
1335 /* All-whitespace rule is the same as empty */
1336 rule = check_parse (TRUE, " \t");
1339 _dbus_assert (rule->flags == 0);
1341 bus_match_rule_unref (rule);
1344 /* But with non-whitespace chars and no =value, it's not OK */
1345 rule = check_parse (FALSE, "type");
1346 _dbus_assert (rule == NULL);
1348 /* Empty string values are allowed at the moment */
1349 rule = check_parse (TRUE, "interface=");
1352 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1353 _dbus_assert (rule->interface);
1354 _dbus_assert (strlen (rule->interface) == 0);
1356 bus_match_rule_unref (rule);
1359 /* Empty string expressed with quotes */
1360 rule = check_parse (TRUE, "interface=''");
1363 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1364 _dbus_assert (rule->interface);
1365 _dbus_assert (strlen (rule->interface) == 0);
1367 bus_match_rule_unref (rule);
1370 /* Check whitespace in a value */
1371 rule = check_parse (TRUE, "interface= ");
1374 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1375 _dbus_assert (rule->interface);
1376 _dbus_assert (strcmp (rule->interface, " ") == 0);
1378 bus_match_rule_unref (rule);
1381 /* Check whitespace mixed with non-whitespace in a value */
1382 rule = check_parse (TRUE, "interface= foo ");
1385 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1386 _dbus_assert (rule->interface);
1387 _dbus_assert (strcmp (rule->interface, " foo ") == 0);
1389 bus_match_rule_unref (rule);
1396 bus_signals_test (const DBusString *test_data_dir)
1398 BusMatchmaker *matchmaker;
1400 matchmaker = bus_matchmaker_new ();
1401 bus_matchmaker_ref (matchmaker);
1402 bus_matchmaker_unref (matchmaker);
1403 bus_matchmaker_unref (matchmaker);
1405 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
1406 _dbus_assert_not_reached ("Parsing match rules test failed");
1411 #endif /* DBUS_BUILD_TESTS */