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 1.2
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);
71 bus_match_rule_unref (BusMatchRule *rule)
73 _dbus_assert (rule->refcount > 0);
76 if (rule->refcount == 0)
78 dbus_free (rule->interface);
79 dbus_free (rule->member);
80 dbus_free (rule->sender);
81 dbus_free (rule->destination);
82 dbus_free (rule->path);
87 #ifdef DBUS_ENABLE_VERBOSE_MODE
89 match_rule_to_string (BusMatchRule *rule)
94 if (!_dbus_string_init (&str))
97 while ((s = _dbus_strdup ("nomem")) == NULL)
98 ; /* only OK for debug spew... */
102 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
104 /* FIXME make type readable */
105 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
109 if (rule->flags & BUS_MATCH_INTERFACE)
111 if (_dbus_string_get_length (&str) > 0)
113 if (!_dbus_string_append (&str, ","))
117 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
121 if (rule->flags & BUS_MATCH_MEMBER)
123 if (_dbus_string_get_length (&str) > 0)
125 if (!_dbus_string_append (&str, ","))
129 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
133 if (rule->flags & BUS_MATCH_PATH)
135 if (_dbus_string_get_length (&str) > 0)
137 if (!_dbus_string_append (&str, ","))
141 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
145 if (rule->flags & BUS_MATCH_SENDER)
147 if (_dbus_string_get_length (&str) > 0)
149 if (!_dbus_string_append (&str, ","))
153 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
157 if (rule->flags & BUS_MATCH_DESTINATION)
159 if (_dbus_string_get_length (&str) > 0)
161 if (!_dbus_string_append (&str, ","))
165 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
169 if (!_dbus_string_steal_data (&str, &ret))
172 _dbus_string_free (&str);
176 _dbus_string_free (&str);
179 while ((s = _dbus_strdup ("nomem")) == NULL)
180 ; /* only OK for debug spew... */
184 #endif /* DBUS_ENABLE_VERBOSE_MODE */
187 bus_match_rule_set_message_type (BusMatchRule *rule,
190 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
192 rule->message_type = type;
198 bus_match_rule_set_interface (BusMatchRule *rule,
199 const char *interface)
203 _dbus_assert (interface != NULL);
205 new = _dbus_strdup (interface);
209 rule->flags |= BUS_MATCH_INTERFACE;
210 dbus_free (rule->interface);
211 rule->interface = new;
217 bus_match_rule_set_member (BusMatchRule *rule,
222 _dbus_assert (member != NULL);
224 new = _dbus_strdup (member);
228 rule->flags |= BUS_MATCH_MEMBER;
229 dbus_free (rule->member);
236 bus_match_rule_set_sender (BusMatchRule *rule,
241 _dbus_assert (sender != NULL);
243 new = _dbus_strdup (sender);
247 rule->flags |= BUS_MATCH_SENDER;
248 dbus_free (rule->sender);
255 bus_match_rule_set_destination (BusMatchRule *rule,
256 const char *destination)
260 _dbus_assert (destination != NULL);
262 new = _dbus_strdup (destination);
266 rule->flags |= BUS_MATCH_DESTINATION;
267 dbus_free (rule->destination);
268 rule->destination = new;
274 bus_match_rule_set_path (BusMatchRule *rule,
279 _dbus_assert (path != NULL);
281 new = _dbus_strdup (path);
285 rule->flags |= BUS_MATCH_PATH;
286 dbus_free (rule->path);
292 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
295 find_key (const DBusString *str,
303 const char *key_start;
306 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
308 s = _dbus_string_get_const_data (str);
312 while (*p && ISWHITE (*p))
317 while (*p && *p != '=' && !ISWHITE (*p))
322 while (*p && ISWHITE (*p))
325 if (key_start == key_end)
327 /* Empty match rules or trailing whitespace are OK */
334 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
335 "Match rule has a key with no subsequent '=' character");
340 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
352 find_value (const DBusString *str,
364 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
366 orig_len = _dbus_string_get_length (value);
368 s = _dbus_string_get_const_data (str);
376 if (quote_char == '\0')
396 if (!_dbus_string_append_byte (value, *p))
403 else if (quote_char == '\\')
405 /* \ only counts as an escape if escaping a quote mark */
408 if (!_dbus_string_append_byte (value, '\\'))
415 if (!_dbus_string_append_byte (value, *p))
425 _dbus_assert (quote_char == '\'');
433 if (!_dbus_string_append_byte (value, *p))
447 if (quote_char == '\\')
449 if (!_dbus_string_append_byte (value, '\\'))
455 else if (quote_char == '\'')
457 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
458 "Unbalanced quotation marks in match rule");
462 _dbus_assert (quote_char == '\0');
464 /* Zero-length values are allowed */
471 _DBUS_ASSERT_ERROR_IS_SET (error);
472 _dbus_string_set_length (value, orig_len);
476 /* duplicates aren't allowed so the real legitimate max is only 6 or
477 * so. Leaving extra so we don't have to bother to update it.
479 #define MAX_RULE_TOKENS 16
481 /* this is slightly too high level to be termed a "token"
482 * but let's not be pedantic.
491 tokenize_rule (const DBusString *rule_text,
492 RuleToken tokens[MAX_RULE_TOKENS],
503 if (!_dbus_string_init (&key))
509 if (!_dbus_string_init (&value))
511 _dbus_string_free (&key);
518 while (i < MAX_RULE_TOKENS &&
519 pos < _dbus_string_get_length (rule_text))
521 _dbus_assert (tokens[i].key == NULL);
522 _dbus_assert (tokens[i].value == NULL);
524 if (!find_key (rule_text, pos, &key, &pos, error))
527 if (_dbus_string_get_length (&key) == 0)
530 if (!_dbus_string_steal_data (&key, &tokens[i].key))
536 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
539 if (!_dbus_string_steal_data (&value, &tokens[i].value))
555 while (tokens[i].key || tokens[i].value)
557 dbus_free (tokens[i].key);
558 dbus_free (tokens[i].value);
559 tokens[i].key = NULL;
560 tokens[i].value = NULL;
565 _dbus_string_free (&key);
566 _dbus_string_free (&value);
572 * The format is comma-separated with strings quoted with single quotes
573 * as for the shell (to escape a literal single quote, use '\'').
575 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
576 * path='/bar/foo',destination=':452345-34'
580 bus_match_rule_parse (DBusConnection *matches_go_to,
581 const DBusString *rule_text,
585 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
588 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
590 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
592 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
593 "Match rule text is %d bytes, maximum is %d",
594 _dbus_string_get_length (rule_text),
595 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
599 memset (tokens, '\0', sizeof (tokens));
601 rule = bus_match_rule_new (matches_go_to);
608 if (!tokenize_rule (rule_text, tokens, error))
612 while (tokens[i].key != NULL)
614 const char *key = tokens[i].key;
615 const char *value = tokens[i].value;
617 if (strcmp (key, "type") == 0)
621 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
623 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
624 "Key %s specified twice in match rule\n", key);
628 t = dbus_message_type_from_string (value);
630 if (!bus_match_rule_set_message_type (rule, t))
636 else if (strcmp (key, "sender") == 0)
638 if (rule->flags & BUS_MATCH_SENDER)
640 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
641 "Key %s specified twice in match rule\n", key);
645 if (!bus_match_rule_set_sender (rule, value))
651 else if (strcmp (key, "interface") == 0)
653 if (rule->flags & BUS_MATCH_INTERFACE)
655 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
656 "Key %s specified twice in match rule\n", key);
660 if (!bus_match_rule_set_interface (rule, value))
666 else if (strcmp (key, "member") == 0)
668 if (rule->flags & BUS_MATCH_MEMBER)
670 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
671 "Key %s specified twice in match rule\n", key);
675 if (!bus_match_rule_set_member (rule, value))
681 else if (strcmp (key, "path") == 0)
683 if (rule->flags & BUS_MATCH_PATH)
685 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
686 "Key %s specified twice in match rule\n", key);
690 if (!bus_match_rule_set_path (rule, value))
696 else if (strcmp (key, "destination") == 0)
698 if (rule->flags & BUS_MATCH_DESTINATION)
700 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
701 "Key %s specified twice in match rule\n", key);
705 if (!bus_match_rule_set_destination (rule, value))
713 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
714 "Unknown key \"%s\" in match rule",
726 _DBUS_ASSERT_ERROR_IS_SET (error);
729 bus_match_rule_unref (rule);
736 while (tokens[i].key || tokens[i].value)
738 _dbus_assert (i < MAX_RULE_TOKENS);
739 dbus_free (tokens[i].key);
740 dbus_free (tokens[i].value);
755 bus_matchmaker_new (void)
757 BusMatchmaker *matchmaker;
759 matchmaker = dbus_new0 (BusMatchmaker, 1);
760 if (matchmaker == NULL)
763 matchmaker->refcount = 1;
769 bus_matchmaker_ref (BusMatchmaker *matchmaker)
771 _dbus_assert (matchmaker->refcount > 0);
773 matchmaker->refcount += 1;
777 bus_matchmaker_unref (BusMatchmaker *matchmaker)
779 _dbus_assert (matchmaker->refcount > 0);
781 matchmaker->refcount -= 1;
782 if (matchmaker->refcount == 0)
784 while (matchmaker->all_rules != NULL)
788 rule = matchmaker->all_rules->data;
789 bus_match_rule_unref (rule);
790 _dbus_list_remove_link (&matchmaker->all_rules,
791 matchmaker->all_rules);
794 dbus_free (matchmaker);
798 /* The rule can't be modified after it's added. */
800 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
803 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
805 if (!_dbus_list_append (&matchmaker->all_rules, rule))
808 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
810 _dbus_list_remove_last (&matchmaker->all_rules, rule);
814 bus_match_rule_ref (rule);
816 #ifdef DBUS_ENABLE_VERBOSE_MODE
818 char *s = match_rule_to_string (rule);
820 _dbus_verbose ("Added match rule %s to connection %p\n",
821 s, rule->matches_go_to);
830 match_rule_equal (BusMatchRule *a,
833 if (a->flags != b->flags)
836 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
837 a->message_type != b->message_type)
840 if ((a->flags & BUS_MATCH_MEMBER) &&
841 strcmp (a->member, b->member) != 0)
844 if ((a->flags & BUS_MATCH_PATH) &&
845 strcmp (a->path, b->path) != 0)
848 if ((a->flags & BUS_MATCH_INTERFACE) &&
849 strcmp (a->interface, b->interface) != 0)
852 if ((a->flags & BUS_MATCH_SENDER) &&
853 strcmp (a->sender, b->sender) != 0)
856 if ((a->flags & BUS_MATCH_DESTINATION) &&
857 strcmp (a->destination, b->destination) != 0)
864 bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
867 BusMatchRule *rule = link->data;
869 bus_connection_remove_match_rule (rule->matches_go_to, rule);
870 _dbus_list_remove_link (&matchmaker->all_rules, link);
872 #ifdef DBUS_ENABLE_VERBOSE_MODE
874 char *s = match_rule_to_string (rule);
876 _dbus_verbose ("Removed match rule %s for connection %p\n",
877 s, rule->matches_go_to);
882 bus_match_rule_unref (rule);
886 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
889 bus_connection_remove_match_rule (rule->matches_go_to, rule);
890 _dbus_list_remove (&matchmaker->all_rules, rule);
892 #ifdef DBUS_ENABLE_VERBOSE_MODE
894 char *s = match_rule_to_string (rule);
896 _dbus_verbose ("Removed match rule %s for connection %p\n",
897 s, rule->matches_go_to);
902 bus_match_rule_unref (rule);
905 /* Remove a single rule which is equal to the given rule by value */
907 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
911 /* FIXME this is an unoptimized linear scan */
915 /* we traverse backward because bus_connection_remove_match_rule()
916 * removes the most-recently-added rule
918 link = _dbus_list_get_last_link (&matchmaker->all_rules);
925 prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
927 if (match_rule_equal (rule, value))
929 bus_matchmaker_remove_rule_link (matchmaker, link);
938 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
939 "The given match rule wasn't found and can't be removed");
947 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
948 DBusConnection *disconnected)
954 * This scans all match rules on the bus. We could avoid that
955 * for the rules belonging to the connection, since we keep
956 * a list of those; but for the rules that just refer to
957 * the connection we'd need to do something more elaborate.
961 _dbus_assert (bus_connection_is_active (disconnected));
963 link = _dbus_list_get_first_link (&matchmaker->all_rules);
970 next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
972 if (rule->matches_go_to == disconnected)
974 bus_matchmaker_remove_rule_link (matchmaker, link);
976 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
977 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
979 /* The rule matches to/from a base service, see if it's the
980 * one being disconnected, since we know this service name
981 * will never be recycled.
985 name = bus_connection_get_name (disconnected);
986 _dbus_assert (name != NULL); /* because we're an active connection */
988 if (((rule->flags & BUS_MATCH_SENDER) &&
989 strcmp (rule->sender, name) == 0) ||
990 ((rule->flags & BUS_MATCH_DESTINATION) &&
991 strcmp (rule->destination, name) == 0))
993 bus_matchmaker_remove_rule_link (matchmaker, link);
1002 connection_is_primary_owner (DBusConnection *connection,
1003 const char *service_name)
1005 BusService *service;
1007 BusRegistry *registry;
1009 registry = bus_connection_get_registry (connection);
1011 _dbus_string_init_const (&str, service_name);
1012 service = bus_registry_lookup (registry, &str);
1014 if (service == NULL)
1015 return FALSE; /* Service doesn't exist so connection can't own it. */
1017 return bus_service_get_primary_owner (service) == connection;
1021 match_rule_matches (BusMatchRule *rule,
1022 BusConnections *connections,
1023 DBusConnection *sender,
1024 DBusConnection *addressed_recipient,
1025 DBusMessage *message)
1027 /* All features of the match rule are AND'd together,
1028 * so FALSE if any of them don't match.
1031 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
1033 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1035 if (rule->message_type != dbus_message_get_type (message))
1039 if (rule->flags & BUS_MATCH_INTERFACE)
1043 _dbus_assert (rule->interface != NULL);
1045 iface = dbus_message_get_interface (message);
1049 if (strcmp (iface, rule->interface) != 0)
1053 if (rule->flags & BUS_MATCH_MEMBER)
1057 _dbus_assert (rule->member != NULL);
1059 member = dbus_message_get_member (message);
1063 if (strcmp (member, rule->member) != 0)
1067 if (rule->flags & BUS_MATCH_SENDER)
1069 _dbus_assert (rule->sender != NULL);
1071 if (!connection_is_primary_owner (sender, rule->sender))
1075 if (rule->flags & BUS_MATCH_DESTINATION)
1077 const char *destination;
1079 _dbus_assert (rule->destination != NULL);
1081 if (addressed_recipient == NULL)
1084 destination = dbus_message_get_destination (message);
1085 if (destination == NULL)
1088 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1092 if (rule->flags & BUS_MATCH_PATH)
1096 _dbus_assert (rule->path != NULL);
1098 path = dbus_message_get_path (message);
1102 if (strcmp (path, rule->path) != 0)
1110 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1111 BusConnections *connections,
1112 DBusConnection *sender,
1113 DBusConnection *addressed_recipient,
1114 DBusMessage *message,
1115 DBusList **recipients_p)
1117 /* FIXME for now this is a wholly unoptimized linear search */
1118 /* Guessing the important optimization is to skip the signal-related
1119 * match lists when processing method call and exception messages.
1120 * So separate match rule lists for signals?
1125 _dbus_assert (*recipients_p == NULL);
1127 /* This avoids sending same message to the same connection twice.
1128 * Purpose of the stamp instead of a bool is to avoid iterating over
1129 * all connections resetting the bool each time.
1131 bus_connections_increment_stamp (connections);
1133 /* addressed_recipient is already receiving the message, don't add to list.
1134 * NULL addressed_recipient means either bus driver, or this is a signal
1135 * and thus lacks a specific addressed_recipient.
1137 if (addressed_recipient != NULL)
1138 bus_connection_mark_stamp (addressed_recipient);
1140 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1141 while (link != NULL)
1147 #ifdef DBUS_ENABLE_VERBOSE_MODE
1149 char *s = match_rule_to_string (rule);
1151 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1152 s, rule->matches_go_to);
1157 if (match_rule_matches (rule, connections,
1158 sender, addressed_recipient, message))
1160 _dbus_verbose ("Rule matched\n");
1162 /* Append to the list if we haven't already */
1163 if (bus_connection_mark_stamp (rule->matches_go_to))
1165 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1168 #ifdef DBUS_ENABLE_VERBOSE_MODE
1171 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1173 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1176 link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1182 _dbus_list_clear (recipients_p);
1186 #ifdef DBUS_BUILD_TESTS
1190 static BusMatchRule*
1191 check_parse (dbus_bool_t should_succeed,
1198 dbus_error_init (&error);
1200 _dbus_string_init_const (&str, text);
1202 rule = bus_match_rule_parse (NULL, &str, &error);
1203 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1205 dbus_error_free (&error);
1209 if (should_succeed && rule == NULL)
1211 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1212 error.name, error.message,
1213 _dbus_string_get_const_data (&str));
1217 if (!should_succeed && rule != NULL)
1219 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1220 _dbus_string_get_const_data (&str));
1224 dbus_error_free (&error);
1230 assert_large_rule (BusMatchRule *rule)
1232 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1233 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1234 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1235 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1236 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1237 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1239 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1240 _dbus_assert (rule->interface != NULL);
1241 _dbus_assert (rule->member != NULL);
1242 _dbus_assert (rule->sender != NULL);
1243 _dbus_assert (rule->destination != NULL);
1244 _dbus_assert (rule->path != NULL);
1246 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1247 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1248 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1249 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1250 _dbus_assert (strcmp (rule->destination, ":452345-34") == 0);
1254 test_parsing (void *data)
1258 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345-34'");
1261 assert_large_rule (rule);
1262 bus_match_rule_unref (rule);
1265 /* With extra whitespace and useless quotes */
1266 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345-34'''''");
1269 assert_large_rule (rule);
1270 bus_match_rule_unref (rule);
1274 /* A simple signal connection */
1275 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1278 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1279 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1280 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1282 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1283 _dbus_assert (rule->interface != NULL);
1284 _dbus_assert (rule->path != NULL);
1286 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
1287 _dbus_assert (strcmp (rule->path, "/foo") == 0);
1289 bus_match_rule_unref (rule);
1292 /* Reject duplicates */
1293 rule = check_parse (FALSE, "type='signal',type='method_call'");
1294 _dbus_assert (rule == NULL);
1296 /* Reject broken keys */
1297 rule = check_parse (FALSE, "blah='signal'");
1298 _dbus_assert (rule == NULL);
1300 /* Allow empty rule */
1301 rule = check_parse (TRUE, "");
1304 _dbus_assert (rule->flags == 0);
1306 bus_match_rule_unref (rule);
1309 /* All-whitespace rule is the same as empty */
1310 rule = check_parse (TRUE, " \t");
1313 _dbus_assert (rule->flags == 0);
1315 bus_match_rule_unref (rule);
1318 /* But with non-whitespace chars and no =value, it's not OK */
1319 rule = check_parse (FALSE, "type");
1320 _dbus_assert (rule == NULL);
1322 /* Empty string values are allowed at the moment */
1323 rule = check_parse (TRUE, "interface=");
1326 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1327 _dbus_assert (rule->interface);
1328 _dbus_assert (strlen (rule->interface) == 0);
1330 bus_match_rule_unref (rule);
1333 /* Empty string expressed with quotes */
1334 rule = check_parse (TRUE, "interface=''");
1337 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1338 _dbus_assert (rule->interface);
1339 _dbus_assert (strlen (rule->interface) == 0);
1341 bus_match_rule_unref (rule);
1344 /* Check whitespace in a value */
1345 rule = check_parse (TRUE, "interface= ");
1348 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1349 _dbus_assert (rule->interface);
1350 _dbus_assert (strcmp (rule->interface, " ") == 0);
1352 bus_match_rule_unref (rule);
1355 /* Check whitespace mixed with non-whitespace in a value */
1356 rule = check_parse (TRUE, "interface= foo ");
1359 _dbus_assert (rule->flags == BUS_MATCH_INTERFACE);
1360 _dbus_assert (rule->interface);
1361 _dbus_assert (strcmp (rule->interface, " foo ") == 0);
1363 bus_match_rule_unref (rule);
1370 bus_signals_test (const DBusString *test_data_dir)
1372 BusMatchmaker *matchmaker;
1374 matchmaker = bus_matchmaker_new ();
1375 bus_matchmaker_ref (matchmaker);
1376 bus_matchmaker_unref (matchmaker);
1377 bus_matchmaker_unref (matchmaker);
1379 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
1380 _dbus_assert_not_reached ("Parsing match rules test failed");
1385 #endif /* DBUS_BUILD_TESTS */