2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2007 IBM Corp.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 /* collection.c: implements the Collection interface */
28 #include <droute/droute.h>
32 #include "spi-common/bitarray.h"
33 #include "spi-common/spi-dbus.h"
35 typedef struct _MatchRulePrivate MatchRulePrivate;
36 struct _MatchRulePrivate
39 Accessibility_Collection_MatchType statematchtype;
40 AtkAttributeSet *attributes;
41 Accessibility_Collection_MatchType attributematchtype;
43 Accessibility_Collection_MatchType rolematchtype;
45 Accessibility_Collection_MatchType interfacematchtype;
50 child_interface_p (AtkObject *child,
53 if (!strcasecmp(repo_id, "action")) return atk_is_action(child);
54 if (!strcasecmp(repo_id, "component")) return atk_is_component(child);
55 if (!strcasecmp(repo_id, "editabletext")) return atk_is_editable_text(child);
56 if (!strcasecmp(repo_id, "text")) return atk_is_text(child);
57 if (!strcasecmp(repo_id, "hypertext")) return atk_is_hypertext(child);
58 if (!strcasecmp(repo_id, "image")) return atk_is_image(child);
59 if (!strcasecmp(repo_id, "selection")) return atk_is_selection(child);
60 if (!strcasecmp(repo_id, "table")) return atk_is_table(child);
61 if (!strcasecmp(repo_id, "value")) return atk_is_value(child);
62 if (!strcasecmp(repo_id, "streamablecontent")) return atk_is_streamable_content(child);
63 if (!strcasecmp(repo_id, "document")) return atk_is_document(child);
67 #define child_collection_p(ch) (TRUE)
70 match_states_all_p (AtkObject *child,
80 chs = atk_object_ref_state_set (child);
82 // TODO: use atk-state_set_contains_states; would be more efficient
83 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
85 if (!atk_state_set_contains_state(chs, set[i]))
97 match_states_any_p (AtkObject *child,
102 gboolean ret = FALSE;
107 chs = atk_object_ref_state_set (child);
109 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
111 if (!atk_state_set_contains_state(chs, set[i]))
123 match_states_none_p (AtkObject *child,
133 chs = atk_object_ref_state_set (child);
135 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
137 if (atk_state_set_contains_state(chs, set[i]))
148 // TODO: need to convert at-spi roles/states to atk roles/states */
150 match_states_lookup (AtkObject *child,
151 MatchRulePrivate *mrp)
153 switch (mrp->statematchtype){
154 case Accessibility_Collection_MATCH_ALL :
155 if (match_states_all_p (child, mrp->states))
159 case Accessibility_Collection_MATCH_ANY :
160 if (match_states_any_p (child, mrp->states))
164 case Accessibility_Collection_MATCH_NONE :
165 if (match_states_none_p (child, mrp->states))
175 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
176 // would be more efficient
177 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
180 match_roles_all_p (AtkObject *child,
183 Accessibility_Role role;
185 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
186 else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
188 return (atk_object_get_role(child) == roles[0]);
193 match_roles_any_p (AtkObject *child,
199 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
201 role = atk_object_get_role(child);
203 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
204 if (role == roles[i])
211 match_roles_none_p (AtkObject *child,
217 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
219 role = atk_object_get_role(child);
221 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
222 if (role == roles[i])
229 match_roles_lookup (AtkObject *child,
230 MatchRulePrivate *mrp)
232 switch (mrp->rolematchtype){
233 case Accessibility_Collection_MATCH_ALL :
234 if (match_roles_all_p (child, mrp->roles))
238 case Accessibility_Collection_MATCH_ANY :
239 if (match_roles_any_p (child, mrp->roles))
243 case Accessibility_Collection_MATCH_NONE :
244 if (match_roles_none_p (child, mrp->roles))
255 match_interfaces_all_p (AtkObject *obj,
263 for (i = 0; ifaces[i]; i++)
264 if (!child_interface_p (obj, ifaces [i])){
271 match_interfaces_any_p (AtkObject *obj,
280 for (i = 0; ifaces[i]; i++)
281 if (child_interface_p (obj, ifaces [i])){
288 match_interfaces_none_p (AtkObject *obj,
293 for (i = 0; ifaces[i]; i++)
294 if (child_interface_p (obj, ifaces [i]))
301 match_interfaces_lookup (AtkObject *child,
302 MatchRulePrivate *mrp)
304 switch (mrp->interfacematchtype){
306 case Accessibility_Collection_MATCH_ALL :
307 if (match_interfaces_all_p (child, mrp->ifaces))
311 case Accessibility_Collection_MATCH_ANY :
312 if (match_interfaces_any_p (child, mrp->ifaces))
316 case Accessibility_Collection_MATCH_NONE :
317 if (match_interfaces_none_p (child, mrp->ifaces))
327 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
330 match_attributes_all_p (AtkObject *child,
331 AtkAttributeSet *attributes)
335 gint length, oa_length;
336 gboolean flag = FALSE;
338 if (attributes == NULL || g_slist_length (attributes) == 0)
341 oa = atk_object_get_attributes(child);
342 length = g_slist_length(attributes);
343 oa_length = g_slist_length(oa);
345 for (i = 0; i < length; i++) {
346 AtkAttribute *attr = g_slist_nth_data(attributes, i);
347 for (k = 0; k < oa_length; k++) {
348 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
349 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
350 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
358 atk_attribute_set_free(oa);
362 atk_attribute_set_free(oa);
367 match_attributes_any_p (AtkObject *child,
368 AtkAttributeSet *attributes)
373 gint length, oa_length;
375 length = g_slist_length(attributes);
379 oa = atk_object_get_attributes(child);
380 oa_length = g_slist_length(oa);
382 for (i = 0; i < length; i++){
383 AtkAttribute *attr = g_slist_nth_data(attributes, i);
384 for (k = 0; k < oa_length; k++){
385 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
386 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
387 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
388 atk_attribute_set_free(oa);
393 atk_attribute_set_free(oa);
398 match_attributes_none_p (AtkObject *child,
399 AtkAttributeSet *attributes)
404 gint length, oa_length;
406 length = g_slist_length(attributes);
410 oa = atk_object_get_attributes(child);
411 oa_length = g_slist_length(oa);
413 for (i = 0; i < length; i++){
414 AtkAttribute *attr = g_slist_nth_data(attributes, i);
415 for (k = 0; k < oa_length; k++){
416 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
417 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
418 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
419 atk_attribute_set_free(oa);
424 atk_attribute_set_free(oa);
429 match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
431 switch (mrp->attributematchtype){
433 case Accessibility_Collection_MATCH_ALL :
434 if (match_attributes_all_p (child, mrp->attributes))
438 case Accessibility_Collection_MATCH_ANY :
439 if (match_attributes_any_p (child, mrp->attributes))
443 case Accessibility_Collection_MATCH_NONE :
444 if (match_attributes_none_p (child, mrp->attributes))
454 traverse_p (AtkObject *child,
455 const gboolean traverse)
459 else return !child_collection_p (child);
463 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
464 gint kount, gint max,
465 AtkObject *obj, glong index, gboolean flag,
466 AtkObject *pobj, gboolean recurse,
470 glong acount = atk_object_get_n_accessible_children (obj);
471 gboolean prev = pobj? TRUE : FALSE;
473 for (; i < acount && (max == 0 || kount < max); i++){
475 atk_object_ref_accessible_child(obj, i);
477 g_object_unref(child);
478 if (prev && child == pobj){
482 if (flag && match_interfaces_lookup (child, mrp)
483 && match_states_lookup (child, mrp)
484 && match_roles_lookup (child, mrp)
485 && match_attributes_lookup (child, mrp)
488 ls = g_list_append (ls, child);
495 if (recurse && traverse_p (child, traverse))
496 kount = sort_order_canonical (mrp, ls, kount,
498 pobj, recurse, traverse);
504 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
505 gint kount, gint max,
506 AtkObject *obj, gboolean flag,
513 /* This breaks us out of the recursion. */
514 if (!obj || obj == pobj)
519 /* Add to the list if it matches */
520 if (flag && match_interfaces_lookup (obj, mrp)
521 && match_states_lookup (obj, mrp)
522 && match_roles_lookup (obj, mrp)
523 && match_attributes_lookup (obj, mrp))
525 ls = g_list_append (ls, obj);
529 if(!flag) flag = TRUE;
531 /* Get the current nodes index in it's parent and the parent object. */
532 indexinparent = atk_object_get_index_in_parent (obj);
533 parent = atk_object_get_parent(obj);
535 if(indexinparent > 0)
537 /* there are still some siblings to visit so get the previous sibling
538 and get it's last descendant.
539 First, get the previous sibling */
540 nextobj = atk_object_ref_accessible_child (parent,
542 g_object_unref(nextobj);
544 /* Now, drill down the right side to the last descendant */
545 while(atk_object_get_n_accessible_children (nextobj) > 0)
547 nextobj = atk_object_ref_accessible_child(nextobj,
548 atk_object_get_n_accessible_children (nextobj)-1);
549 g_object_unref (nextobj);
551 /* recurse with the last descendant */
552 kount = sort_order_rev_canonical (mrp, ls, kount, max,
553 nextobj, TRUE, pobj);
557 /* no more siblings so next node must be the parent */
558 kount = sort_order_rev_canonical (mrp, ls, kount, max,
566 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
567 GList *ls, gint kount, gint max,
568 AtkObject *obj, glong index,
571 gboolean recurse, gboolean traverse)
574 case Accessibility_Collection_SORT_ORDER_CANONICAL :
575 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
576 pobj, recurse, traverse);
578 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
579 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
580 pobj, recurse, traverse);
584 g_warning ("Sort method not implemented yet");
592 read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
594 DBusMessageIter mrc, arrayc;
595 dbus_uint32_t *array;
596 dbus_int32_t matchType;
601 char *interfaces = NULL;
603 // TODO: error checking
604 dbus_message_iter_recurse(iter, &mrc);
605 dbus_message_iter_recurse(&mrc, &arrayc);
606 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
607 bitarray_to_seq(array, array_count, &mrp->states);
608 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
610 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
612 dbus_message_iter_next(&mrc);
613 dbus_message_iter_read_basic(&mrc, &matchType);
614 dbus_message_iter_next(&mrc);
615 mrp->statematchtype = matchType;;
617 dbus_message_iter_recurse(&mrc, &arrayc);
618 mrp->attributes = NULL;
619 while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
621 dbus_message_iter_get_basic(&arrayc, &str);
622 // TODO: remove this print
623 g_print("Got attribute: %s\n", str);
624 attr = g_new (AtkAttribute, 1);
627 int len = strcspn(str, ":");
628 attr->name = g_strndup(str, len);
632 if (str[len] == ' ') len++;
633 attr->value = g_strdup(str + len);
635 else attr->value = NULL;
636 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
638 dbus_message_iter_next(&arrayc);
640 dbus_message_iter_next(&mrc);
641 dbus_message_iter_read_basic(&mrc, &matchType);
642 mrp->attributematchtype = matchType;;
643 dbus_message_iter_next(&mrc);
644 /* Get roles and role match */
645 dbus_message_iter_recurse(&mrc, &arrayc);
646 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
647 bitarray_to_seq(array, array_count, &mrp->roles);
648 dbus_message_iter_next(&mrc);
649 dbus_message_iter_read_basic(&mrc, &matchType);
650 mrp->rolematchtype = matchType;;
651 dbus_message_iter_next(&mrc);
652 /* Get interfaces and interface match */
653 dbus_message_iter_read_basic(&mrc, &interfaces);
654 dbus_message_iter_next(&mrc);
655 mrp->ifaces = g_strsplit(interfaces, ";", 0);
656 dbus_message_iter_read_basic(&mrc, &matchType);
657 mrp->interfacematchtype = matchType;;
658 dbus_message_iter_next(&mrc);
660 dbus_message_iter_read_basic(&mrc, &mrp->invert);
661 dbus_message_iter_next(iter);
666 return_and_free_list(DBusMessage *message, GList *ls)
669 DBusMessageIter iter, iter_array;
672 reply = dbus_message_new_method_return(message);
673 if (!reply) return NULL;
674 dbus_message_iter_init_append(reply, &iter);
675 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
676 for (item = ls; item; item = g_list_next(item))
678 char *path = (char *) spi_dbus_object_to_path ((AtkObject *)item->data);
679 dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
682 if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
686 // TODO: Handle out of memory
691 static void free_mrp_data(MatchRulePrivate *mrp)
694 atk_attribute_set_free(mrp->attributes);
696 g_strfreev(mrp->ifaces);
700 getMatchesFrom (DBusMessage *message,
701 AtkObject *current_object,
702 MatchRulePrivate *mrp,
703 const Accessibility_Collection_SortOrder sortby,
704 const dbus_bool_t isrestrict,
706 const dbus_bool_t traverse)
711 atk_object_get_index_in_parent (current_object);
714 ls = g_list_append (ls, current_object);
718 parent = atk_object_get_parent (current_object);
719 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
720 FALSE, NULL, TRUE, traverse);
723 kount = query_exec (mrp, sortby, ls, 0, count,
724 current_object, 0, FALSE, NULL,
727 ls = g_list_remove (ls, ls->data);
729 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
730 ls = g_list_reverse (ls);
733 return return_and_free_list (message, ls);
737 inorder traversal from a given object in the hierarchy
741 inorder (AtkObject *collection, MatchRulePrivate *mrp,
742 GList *ls, gint kount, gint max,
746 dbus_bool_t traverse)
750 /* First, look through the children recursively. */
751 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
754 /* Next, we look through the right subtree */
755 while ((max == 0 || kount < max)
756 && obj != collection)
759 atk_object_get_parent (obj);
760 i = atk_object_get_index_in_parent (obj);
761 kount = sort_order_canonical (mrp, ls, kount, max, parent,
762 i+1, TRUE, FALSE, TRUE, TRUE);
768 kount = sort_order_canonical (mrp, ls, kount, max,
769 obj, i + 1, TRUE, FALSE,
777 GetMatchesInOrder: get matches from a given object in an inorder traversal.
781 getMatchesInOrder (DBusMessage *message,
782 AtkObject *current_object,
783 MatchRulePrivate *mrp,
784 const Accessibility_Collection_SortOrder sortby,
785 const dbus_bool_t recurse,
787 const dbus_bool_t traverse)
793 ls = g_list_append (ls, current_object);
795 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
797 kount = inorder (obj, mrp, ls, 0, count,
798 current_object, TRUE, NULL, traverse);
800 ls = g_list_remove (ls, ls->data);
802 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
803 ls = g_list_reverse (ls);
806 return return_and_free_list (message, ls);
810 GetMatchesInBackOrder: get matches from a given object in a
811 reverse order traversal.
815 getMatchesInBackOrder (DBusMessage *message,
816 AtkObject *current_object,
817 MatchRulePrivate *mrp,
818 const Accessibility_Collection_SortOrder sortby,
822 AtkObject *collection;
825 ls = g_list_append (ls, current_object);
827 collection = atk_dbus_path_to_object (dbus_message_get_path (message));
829 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
832 ls = g_list_remove (ls, ls->data);
834 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
835 ls = g_list_reverse (ls);
838 return return_and_free_list (message, ls);
842 getMatchesTo (DBusMessage *message,
843 AtkObject *current_object,
844 MatchRulePrivate *mrp,
845 const Accessibility_Collection_SortOrder sortby,
846 const dbus_bool_t recurse,
847 const dbus_bool_t isrestrict,
849 const dbus_bool_t traverse)
855 ls = g_list_append (ls, current_object);
858 obj = atk_object_get_parent (current_object);
859 kount = query_exec (mrp, sortby, ls, 0, count,
860 obj, 0, TRUE, current_object, TRUE, traverse);
863 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
864 kount = query_exec (mrp, sortby, ls, 0, count,
865 obj, 0, TRUE, current_object, TRUE, traverse);
869 ls = g_list_remove (ls, ls->data);
871 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
872 ls = g_list_reverse (ls);
875 return return_and_free_list (message, ls);
879 impl_getMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
881 char *current_object_path = NULL;
882 AtkObject *current_object;
883 DBusMessageIter iter;
884 MatchRulePrivate rule;
885 dbus_uint16_t sortby;
888 dbus_bool_t traverse;
891 dbus_message_iter_init(message, &iter);
892 dbus_message_iter_get_basic (&iter, current_object_path);
893 current_object = atk_dbus_path_to_object (current_object_path);
896 // TODO: object-not-found error
897 return spi_dbus_general_error (message);
899 dbus_message_iter_next (&iter);
900 if (!read_mr(&iter, &rule))
902 return spi_dbus_general_error (message);
904 dbus_message_iter_get_basic(&iter, &sortby);
905 dbus_message_iter_next(&iter);
906 dbus_message_iter_get_basic(&iter, &tree);
907 dbus_message_iter_next(&iter);
908 dbus_message_iter_get_basic(&iter, &count);
909 dbus_message_iter_next(&iter);
910 dbus_message_iter_get_basic(&iter, &traverse);
911 dbus_message_iter_next(&iter);
914 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
915 return getMatchesFrom (message, current_object,
916 &rule, sortby, TRUE, count, traverse);
918 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
919 return getMatchesFrom (message, current_object,
920 &rule, sortby, FALSE, count, traverse);
922 case Accessibility_Collection_TREE_INORDER :
923 return getMatchesInOrder (message, current_object,
924 &rule, sortby, TRUE, count, traverse);
926 default : return NULL;
931 impl_getMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
933 char *current_object_path = NULL;
934 AtkObject *current_object;
935 DBusMessageIter iter;
936 MatchRulePrivate rule;
937 dbus_uint16_t sortby;
941 dbus_bool_t traverse;
944 dbus_message_iter_init(message, &iter);
945 dbus_message_iter_get_basic (&iter, current_object_path);
946 current_object = atk_dbus_path_to_object (current_object_path);
949 // TODO: object-not-found error
950 return spi_dbus_general_error (message);
952 dbus_message_iter_next (&iter);
953 if (!read_mr(&iter, &rule))
955 return spi_dbus_general_error (message);
957 dbus_message_iter_get_basic(&iter, &sortby);
958 dbus_message_iter_next(&iter);
959 dbus_message_iter_get_basic(&iter, &tree);
960 dbus_message_iter_next(&iter);
961 dbus_message_iter_get_basic(&iter, &recurse);
962 dbus_message_iter_next(&iter);
963 dbus_message_iter_get_basic(&iter, &count);
964 dbus_message_iter_next(&iter);
965 dbus_message_iter_get_basic(&iter, &traverse);
966 dbus_message_iter_next(&iter);
969 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
970 return getMatchesTo (message, current_object,
971 &rule, sortby, recurse, TRUE, count, traverse);
973 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
974 return getMatchesTo (message, current_object,
975 &rule, sortby, recurse, FALSE, count, traverse);
977 case Accessibility_Collection_TREE_INORDER :
978 return getMatchesInBackOrder (message, current_object,
979 &rule, sortby, count);
981 default : return NULL;
986 impl_getMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
988 AtkObject *obj = path_to_object (message);
989 DBusMessageIter iter;
990 MatchRulePrivate rule;
991 dbus_uint16_t sortby;
993 dbus_bool_t traverse;
996 dbus_message_iter_init(message, &iter);
997 if (!read_mr(&iter, &rule))
999 return spi_dbus_general_error (message);
1001 dbus_message_iter_get_basic(&iter, &sortby);
1002 dbus_message_iter_next(&iter);
1003 dbus_message_iter_get_basic(&iter, &count);
1004 dbus_message_iter_next(&iter);
1005 dbus_message_iter_get_basic(&iter, &traverse);
1006 dbus_message_iter_next(&iter);
1007 ls = g_list_prepend (ls, obj);
1008 count = query_exec (&rule, sortby, ls, 0, count,
1009 obj, 0, TRUE, NULL, TRUE, traverse);
1010 ls = g_list_remove (ls, ls->data);
1012 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1013 ls = g_list_reverse (ls);
1014 free_mrp_data (&rule);
1015 return return_and_free_list (message, ls);
1018 static DRouteMethod methods[] = {
1019 { impl_getMatchesFrom, "getMatchesFrom" },
1020 { impl_getMatchesTo, "getMatchesTo" },
1021 { impl_getMatches, "getMatches" },
1026 spi_initialize_collection (DRoutePath *path)
1028 droute_path_add_interface (path,
1029 SPI_DBUS_INTERFACE_COLLECTION,