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
26 #include <dbus/dbus-marshal-validate.h>
30 int refcount; /**< reference count */
32 DBusConnection *matches_go_to; /**< Owner of the rule */
34 unsigned int flags; /**< BusMatchFlags */
45 bus_match_rule_new (DBusConnection *matches_go_to)
49 rule = dbus_new0 (BusMatchRule, 1);
54 rule->matches_go_to = matches_go_to;
56 #ifndef DBUS_BUILD_TESTS
57 _dbus_assert (rule->matches_go_to != NULL);
64 bus_match_rule_ref (BusMatchRule *rule)
66 _dbus_assert (rule->refcount > 0);
74 bus_match_rule_unref (BusMatchRule *rule)
76 _dbus_assert (rule->refcount > 0);
79 if (rule->refcount == 0)
81 dbus_free (rule->interface);
82 dbus_free (rule->member);
83 dbus_free (rule->sender);
84 dbus_free (rule->destination);
85 dbus_free (rule->path);
90 #ifdef DBUS_ENABLE_VERBOSE_MODE
92 match_rule_to_string (BusMatchRule *rule)
97 if (!_dbus_string_init (&str))
100 while ((s = _dbus_strdup ("nomem")) == NULL)
101 ; /* only OK for debug spew... */
105 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
107 /* FIXME make type readable */
108 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
112 if (rule->flags & BUS_MATCH_INTERFACE)
114 if (_dbus_string_get_length (&str) > 0)
116 if (!_dbus_string_append (&str, ","))
120 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
124 if (rule->flags & BUS_MATCH_MEMBER)
126 if (_dbus_string_get_length (&str) > 0)
128 if (!_dbus_string_append (&str, ","))
132 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
136 if (rule->flags & BUS_MATCH_PATH)
138 if (_dbus_string_get_length (&str) > 0)
140 if (!_dbus_string_append (&str, ","))
144 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
148 if (rule->flags & BUS_MATCH_SENDER)
150 if (_dbus_string_get_length (&str) > 0)
152 if (!_dbus_string_append (&str, ","))
156 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
160 if (rule->flags & BUS_MATCH_DESTINATION)
162 if (_dbus_string_get_length (&str) > 0)
164 if (!_dbus_string_append (&str, ","))
168 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
172 if (!_dbus_string_steal_data (&str, &ret))
175 _dbus_string_free (&str);
179 _dbus_string_free (&str);
182 while ((s = _dbus_strdup ("nomem")) == NULL)
183 ; /* only OK for debug spew... */
187 #endif /* DBUS_ENABLE_VERBOSE_MODE */
190 bus_match_rule_set_message_type (BusMatchRule *rule,
193 rule->flags |= BUS_MATCH_MESSAGE_TYPE;
195 rule->message_type = type;
201 bus_match_rule_set_interface (BusMatchRule *rule,
202 const char *interface)
206 _dbus_assert (interface != NULL);
208 new = _dbus_strdup (interface);
212 rule->flags |= BUS_MATCH_INTERFACE;
213 dbus_free (rule->interface);
214 rule->interface = new;
220 bus_match_rule_set_member (BusMatchRule *rule,
225 _dbus_assert (member != NULL);
227 new = _dbus_strdup (member);
231 rule->flags |= BUS_MATCH_MEMBER;
232 dbus_free (rule->member);
239 bus_match_rule_set_sender (BusMatchRule *rule,
244 _dbus_assert (sender != NULL);
246 new = _dbus_strdup (sender);
250 rule->flags |= BUS_MATCH_SENDER;
251 dbus_free (rule->sender);
258 bus_match_rule_set_destination (BusMatchRule *rule,
259 const char *destination)
263 _dbus_assert (destination != NULL);
265 new = _dbus_strdup (destination);
269 rule->flags |= BUS_MATCH_DESTINATION;
270 dbus_free (rule->destination);
271 rule->destination = new;
277 bus_match_rule_set_path (BusMatchRule *rule,
282 _dbus_assert (path != NULL);
284 new = _dbus_strdup (path);
288 rule->flags |= BUS_MATCH_PATH;
289 dbus_free (rule->path);
295 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
298 find_key (const DBusString *str,
306 const char *key_start;
309 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
311 s = _dbus_string_get_const_data (str);
315 while (*p && ISWHITE (*p))
320 while (*p && *p != '=' && !ISWHITE (*p))
325 while (*p && ISWHITE (*p))
328 if (key_start == key_end)
330 /* Empty match rules or trailing whitespace are OK */
337 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
338 "Match rule has a key with no subsequent '=' character");
343 if (!_dbus_string_append_len (key, key_start, key_end - key_start))
355 find_value (const DBusString *str,
367 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
369 orig_len = _dbus_string_get_length (value);
371 s = _dbus_string_get_const_data (str);
379 if (quote_char == '\0')
399 if (!_dbus_string_append_byte (value, *p))
406 else if (quote_char == '\\')
408 /* \ only counts as an escape if escaping a quote mark */
411 if (!_dbus_string_append_byte (value, '\\'))
418 if (!_dbus_string_append_byte (value, *p))
428 _dbus_assert (quote_char == '\'');
436 if (!_dbus_string_append_byte (value, *p))
450 if (quote_char == '\\')
452 if (!_dbus_string_append_byte (value, '\\'))
458 else if (quote_char == '\'')
460 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
461 "Unbalanced quotation marks in match rule");
465 _dbus_assert (quote_char == '\0');
467 /* Zero-length values are allowed */
474 _DBUS_ASSERT_ERROR_IS_SET (error);
475 _dbus_string_set_length (value, orig_len);
479 /* duplicates aren't allowed so the real legitimate max is only 6 or
480 * so. Leaving extra so we don't have to bother to update it.
482 #define MAX_RULE_TOKENS 16
484 /* this is slightly too high level to be termed a "token"
485 * but let's not be pedantic.
494 tokenize_rule (const DBusString *rule_text,
495 RuleToken tokens[MAX_RULE_TOKENS],
506 if (!_dbus_string_init (&key))
512 if (!_dbus_string_init (&value))
514 _dbus_string_free (&key);
521 while (i < MAX_RULE_TOKENS &&
522 pos < _dbus_string_get_length (rule_text))
524 _dbus_assert (tokens[i].key == NULL);
525 _dbus_assert (tokens[i].value == NULL);
527 if (!find_key (rule_text, pos, &key, &pos, error))
530 if (_dbus_string_get_length (&key) == 0)
533 if (!_dbus_string_steal_data (&key, &tokens[i].key))
539 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error))
542 if (!_dbus_string_steal_data (&value, &tokens[i].value))
558 while (tokens[i].key || tokens[i].value)
560 dbus_free (tokens[i].key);
561 dbus_free (tokens[i].value);
562 tokens[i].key = NULL;
563 tokens[i].value = NULL;
568 _dbus_string_free (&key);
569 _dbus_string_free (&value);
575 * The format is comma-separated with strings quoted with single quotes
576 * as for the shell (to escape a literal single quote, use '\'').
578 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
579 * path='/bar/foo',destination=':452345.34'
583 bus_match_rule_parse (DBusConnection *matches_go_to,
584 const DBusString *rule_text,
588 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
591 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
593 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH)
595 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
596 "Match rule text is %d bytes, maximum is %d",
597 _dbus_string_get_length (rule_text),
598 DBUS_MAXIMUM_MATCH_RULE_LENGTH);
602 memset (tokens, '\0', sizeof (tokens));
604 rule = bus_match_rule_new (matches_go_to);
611 if (!tokenize_rule (rule_text, tokens, error))
615 while (tokens[i].key != NULL)
619 const char *key = tokens[i].key;
620 const char *value = tokens[i].value;
622 _dbus_string_init_const (&tmp_str, value);
623 len = _dbus_string_get_length (&tmp_str);
625 if (strcmp (key, "type") == 0)
629 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
631 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
632 "Key %s specified twice in match rule\n", key);
636 t = dbus_message_type_from_string (value);
638 if (t == DBUS_MESSAGE_TYPE_INVALID)
640 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
641 "Invalid message type (%s) in match rule\n", value);
645 if (!bus_match_rule_set_message_type (rule, t))
651 else if (strcmp (key, "sender") == 0)
653 if (rule->flags & BUS_MATCH_SENDER)
655 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
656 "Key %s specified twice in match rule\n", key);
660 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
662 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
663 "Sender name '%s' is invalid\n", value);
667 if (!bus_match_rule_set_sender (rule, value))
673 else if (strcmp (key, "interface") == 0)
675 if (rule->flags & BUS_MATCH_INTERFACE)
677 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
678 "Key %s specified twice in match rule\n", key);
682 if (!_dbus_validate_interface (&tmp_str, 0, len))
684 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
685 "Interface name '%s' is invalid\n", value);
689 if (!bus_match_rule_set_interface (rule, value))
695 else if (strcmp (key, "member") == 0)
697 if (rule->flags & BUS_MATCH_MEMBER)
699 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
700 "Key %s specified twice in match rule\n", key);
704 if (!_dbus_validate_member (&tmp_str, 0, len))
706 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
707 "Member name '%s' is invalid\n", value);
711 if (!bus_match_rule_set_member (rule, value))
717 else if (strcmp (key, "path") == 0)
719 if (rule->flags & BUS_MATCH_PATH)
721 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
722 "Key %s specified twice in match rule\n", key);
726 if (!_dbus_validate_path (&tmp_str, 0, len))
728 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
729 "Path '%s' is invalid\n", value);
733 if (!bus_match_rule_set_path (rule, value))
739 else if (strcmp (key, "destination") == 0)
741 if (rule->flags & BUS_MATCH_DESTINATION)
743 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
744 "Key %s specified twice in match rule\n", key);
748 if (!_dbus_validate_bus_name (&tmp_str, 0, len))
750 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
751 "Destination name '%s' is invalid\n", value);
755 if (!bus_match_rule_set_destination (rule, value))
763 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
764 "Unknown key \"%s\" in match rule",
776 _DBUS_ASSERT_ERROR_IS_SET (error);
779 bus_match_rule_unref (rule);
786 while (tokens[i].key || tokens[i].value)
788 _dbus_assert (i < MAX_RULE_TOKENS);
789 dbus_free (tokens[i].key);
790 dbus_free (tokens[i].value);
805 bus_matchmaker_new (void)
807 BusMatchmaker *matchmaker;
809 matchmaker = dbus_new0 (BusMatchmaker, 1);
810 if (matchmaker == NULL)
813 matchmaker->refcount = 1;
819 bus_matchmaker_ref (BusMatchmaker *matchmaker)
821 _dbus_assert (matchmaker->refcount > 0);
823 matchmaker->refcount += 1;
829 bus_matchmaker_unref (BusMatchmaker *matchmaker)
831 _dbus_assert (matchmaker->refcount > 0);
833 matchmaker->refcount -= 1;
834 if (matchmaker->refcount == 0)
836 while (matchmaker->all_rules != NULL)
840 rule = matchmaker->all_rules->data;
841 bus_match_rule_unref (rule);
842 _dbus_list_remove_link (&matchmaker->all_rules,
843 matchmaker->all_rules);
846 dbus_free (matchmaker);
850 /* The rule can't be modified after it's added. */
852 bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
855 _dbus_assert (bus_connection_is_active (rule->matches_go_to));
857 if (!_dbus_list_append (&matchmaker->all_rules, rule))
860 if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
862 _dbus_list_remove_last (&matchmaker->all_rules, rule);
866 bus_match_rule_ref (rule);
868 #ifdef DBUS_ENABLE_VERBOSE_MODE
870 char *s = match_rule_to_string (rule);
872 _dbus_verbose ("Added match rule %s to connection %p\n",
873 s, rule->matches_go_to);
882 match_rule_equal (BusMatchRule *a,
885 if (a->flags != b->flags)
888 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
889 a->message_type != b->message_type)
892 if ((a->flags & BUS_MATCH_MEMBER) &&
893 strcmp (a->member, b->member) != 0)
896 if ((a->flags & BUS_MATCH_PATH) &&
897 strcmp (a->path, b->path) != 0)
900 if ((a->flags & BUS_MATCH_INTERFACE) &&
901 strcmp (a->interface, b->interface) != 0)
904 if ((a->flags & BUS_MATCH_SENDER) &&
905 strcmp (a->sender, b->sender) != 0)
908 if ((a->flags & BUS_MATCH_DESTINATION) &&
909 strcmp (a->destination, b->destination) != 0)
916 bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
919 BusMatchRule *rule = link->data;
921 bus_connection_remove_match_rule (rule->matches_go_to, rule);
922 _dbus_list_remove_link (&matchmaker->all_rules, link);
924 #ifdef DBUS_ENABLE_VERBOSE_MODE
926 char *s = match_rule_to_string (rule);
928 _dbus_verbose ("Removed match rule %s for connection %p\n",
929 s, rule->matches_go_to);
934 bus_match_rule_unref (rule);
938 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
941 bus_connection_remove_match_rule (rule->matches_go_to, rule);
942 _dbus_list_remove (&matchmaker->all_rules, rule);
944 #ifdef DBUS_ENABLE_VERBOSE_MODE
946 char *s = match_rule_to_string (rule);
948 _dbus_verbose ("Removed match rule %s for connection %p\n",
949 s, rule->matches_go_to);
954 bus_match_rule_unref (rule);
957 /* Remove a single rule which is equal to the given rule by value */
959 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
963 /* FIXME this is an unoptimized linear scan */
967 /* we traverse backward because bus_connection_remove_match_rule()
968 * removes the most-recently-added rule
970 link = _dbus_list_get_last_link (&matchmaker->all_rules);
977 prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
979 if (match_rule_equal (rule, value))
981 bus_matchmaker_remove_rule_link (matchmaker, link);
990 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
991 "The given match rule wasn't found and can't be removed");
999 bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
1000 DBusConnection *disconnected)
1006 * This scans all match rules on the bus. We could avoid that
1007 * for the rules belonging to the connection, since we keep
1008 * a list of those; but for the rules that just refer to
1009 * the connection we'd need to do something more elaborate.
1013 _dbus_assert (bus_connection_is_active (disconnected));
1015 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1016 while (link != NULL)
1022 next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1024 if (rule->matches_go_to == disconnected)
1026 bus_matchmaker_remove_rule_link (matchmaker, link);
1028 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
1029 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
1031 /* The rule matches to/from a base service, see if it's the
1032 * one being disconnected, since we know this service name
1033 * will never be recycled.
1037 name = bus_connection_get_name (disconnected);
1038 _dbus_assert (name != NULL); /* because we're an active connection */
1040 if (((rule->flags & BUS_MATCH_SENDER) &&
1041 strcmp (rule->sender, name) == 0) ||
1042 ((rule->flags & BUS_MATCH_DESTINATION) &&
1043 strcmp (rule->destination, name) == 0))
1045 bus_matchmaker_remove_rule_link (matchmaker, link);
1054 connection_is_primary_owner (DBusConnection *connection,
1055 const char *service_name)
1057 BusService *service;
1059 BusRegistry *registry;
1061 _dbus_assert (connection != NULL);
1063 registry = bus_connection_get_registry (connection);
1065 _dbus_string_init_const (&str, service_name);
1066 service = bus_registry_lookup (registry, &str);
1068 if (service == NULL)
1069 return FALSE; /* Service doesn't exist so connection can't own it. */
1071 return bus_service_get_primary_owner (service) == connection;
1075 match_rule_matches (BusMatchRule *rule,
1076 BusConnections *connections,
1077 DBusConnection *sender,
1078 DBusConnection *addressed_recipient,
1079 DBusMessage *message)
1081 /* All features of the match rule are AND'd together,
1082 * so FALSE if any of them don't match.
1085 /* sender/addressed_recipient of #NULL may mean bus driver,
1086 * or for addressed_recipient may mean a message with no
1087 * specific recipient (i.e. a signal)
1090 if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
1092 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
1094 if (rule->message_type != dbus_message_get_type (message))
1098 if (rule->flags & BUS_MATCH_INTERFACE)
1102 _dbus_assert (rule->interface != NULL);
1104 iface = dbus_message_get_interface (message);
1108 if (strcmp (iface, rule->interface) != 0)
1112 if (rule->flags & BUS_MATCH_MEMBER)
1116 _dbus_assert (rule->member != NULL);
1118 member = dbus_message_get_member (message);
1122 if (strcmp (member, rule->member) != 0)
1126 if (rule->flags & BUS_MATCH_SENDER)
1128 _dbus_assert (rule->sender != NULL);
1132 if (strcmp (rule->sender,
1133 DBUS_SERVICE_DBUS) != 0)
1138 if (!connection_is_primary_owner (sender, rule->sender))
1143 if (rule->flags & BUS_MATCH_DESTINATION)
1145 const char *destination;
1147 _dbus_assert (rule->destination != NULL);
1149 destination = dbus_message_get_destination (message);
1150 if (destination == NULL)
1153 if (addressed_recipient == NULL)
1155 if (strcmp (rule->destination,
1156 DBUS_SERVICE_DBUS) != 0)
1161 if (!connection_is_primary_owner (addressed_recipient, rule->destination))
1166 if (rule->flags & BUS_MATCH_PATH)
1170 _dbus_assert (rule->path != NULL);
1172 path = dbus_message_get_path (message);
1176 if (strcmp (path, rule->path) != 0)
1184 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
1185 BusConnections *connections,
1186 DBusConnection *sender,
1187 DBusConnection *addressed_recipient,
1188 DBusMessage *message,
1189 DBusList **recipients_p)
1191 /* FIXME for now this is a wholly unoptimized linear search */
1192 /* Guessing the important optimization is to skip the signal-related
1193 * match lists when processing method call and exception messages.
1194 * So separate match rule lists for signals?
1199 _dbus_assert (*recipients_p == NULL);
1201 /* This avoids sending same message to the same connection twice.
1202 * Purpose of the stamp instead of a bool is to avoid iterating over
1203 * all connections resetting the bool each time.
1205 bus_connections_increment_stamp (connections);
1207 /* addressed_recipient is already receiving the message, don't add to list.
1208 * NULL addressed_recipient means either bus driver, or this is a signal
1209 * and thus lacks a specific addressed_recipient.
1211 if (addressed_recipient != NULL)
1212 bus_connection_mark_stamp (addressed_recipient);
1214 link = _dbus_list_get_first_link (&matchmaker->all_rules);
1215 while (link != NULL)
1221 #ifdef DBUS_ENABLE_VERBOSE_MODE
1223 char *s = match_rule_to_string (rule);
1225 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
1226 s, rule->matches_go_to);
1231 if (match_rule_matches (rule, connections,
1232 sender, addressed_recipient, message))
1234 _dbus_verbose ("Rule matched\n");
1236 /* Append to the list if we haven't already */
1237 if (bus_connection_mark_stamp (rule->matches_go_to))
1239 if (!_dbus_list_append (recipients_p, rule->matches_go_to))
1242 #ifdef DBUS_ENABLE_VERBOSE_MODE
1245 _dbus_verbose ("Connection already receiving this message, so not adding again\n");
1247 #endif /* DBUS_ENABLE_VERBOSE_MODE */
1250 link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
1256 _dbus_list_clear (recipients_p);
1260 #ifdef DBUS_BUILD_TESTS
1264 static BusMatchRule*
1265 check_parse (dbus_bool_t should_succeed,
1272 dbus_error_init (&error);
1274 _dbus_string_init_const (&str, text);
1276 rule = bus_match_rule_parse (NULL, &str, &error);
1277 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1279 dbus_error_free (&error);
1283 if (should_succeed && rule == NULL)
1285 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n",
1286 error.name, error.message,
1287 _dbus_string_get_const_data (&str));
1291 if (!should_succeed && rule != NULL)
1293 _dbus_warn ("Failed to fail to parse: \"%s\"\n",
1294 _dbus_string_get_const_data (&str));
1298 dbus_error_free (&error);
1304 assert_large_rule (BusMatchRule *rule)
1306 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1307 _dbus_assert (rule->flags & BUS_MATCH_SENDER);
1308 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1309 _dbus_assert (rule->flags & BUS_MATCH_MEMBER);
1310 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION);
1311 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1313 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1314 _dbus_assert (rule->interface != NULL);
1315 _dbus_assert (rule->member != NULL);
1316 _dbus_assert (rule->sender != NULL);
1317 _dbus_assert (rule->destination != NULL);
1318 _dbus_assert (rule->path != NULL);
1320 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0);
1321 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0);
1322 _dbus_assert (strcmp (rule->member, "Foo") == 0);
1323 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0);
1324 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0);
1328 test_parsing (void *data)
1332 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'");
1335 assert_large_rule (rule);
1336 bus_match_rule_unref (rule);
1339 /* With extra whitespace and useless quotes */
1340 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''");
1343 assert_large_rule (rule);
1344 bus_match_rule_unref (rule);
1348 /* A simple signal connection */
1349 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'");
1352 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE);
1353 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE);
1354 _dbus_assert (rule->flags & BUS_MATCH_PATH);
1356 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL);
1357 _dbus_assert (rule->interface != NULL);
1358 _dbus_assert (rule->path != NULL);
1360 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0);
1361 _dbus_assert (strcmp (rule->path, "/foo") == 0);
1363 bus_match_rule_unref (rule);
1366 /* Reject duplicates */
1367 rule = check_parse (FALSE, "type='signal',type='method_call'");
1368 _dbus_assert (rule == NULL);
1370 /* Reject broken keys */
1371 rule = check_parse (FALSE, "blah='signal'");
1372 _dbus_assert (rule == NULL);
1374 /* Reject broken valuess */
1375 rule = check_parse (FALSE, "type='chouin'");
1376 _dbus_assert (rule == NULL);
1377 rule = check_parse (FALSE, "interface='abc@def++'");
1378 _dbus_assert (rule == NULL);
1379 rule = check_parse (FALSE, "service='youpi'");
1380 _dbus_assert (rule == NULL);
1382 /* Allow empty rule */
1383 rule = check_parse (TRUE, "");
1386 _dbus_assert (rule->flags == 0);
1388 bus_match_rule_unref (rule);
1391 /* All-whitespace rule is the same as empty */
1392 rule = check_parse (TRUE, " \t");
1395 _dbus_assert (rule->flags == 0);
1397 bus_match_rule_unref (rule);
1400 /* But with non-whitespace chars and no =value, it's not OK */
1401 rule = check_parse (FALSE, "type");
1402 _dbus_assert (rule == NULL);
1408 bus_signals_test (const DBusString *test_data_dir)
1410 BusMatchmaker *matchmaker;
1412 matchmaker = bus_matchmaker_new ();
1413 bus_matchmaker_ref (matchmaker);
1414 bus_matchmaker_unref (matchmaker);
1415 bus_matchmaker_unref (matchmaker);
1417 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL))
1418 _dbus_assert_not_reached ("Parsing match rules test failed");
1423 #endif /* DBUS_BUILD_TESTS */