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>
30 #include "accessible-register.h"
31 #include "accessible-marshaller.h"
33 #include "common/bitarray.h"
34 #include "common/spi-dbus.h"
36 typedef struct _MatchRulePrivate MatchRulePrivate;
37 struct _MatchRulePrivate
40 Accessibility_Collection_MatchType statematchtype;
41 AtkAttributeSet *attributes;
42 Accessibility_Collection_MatchType attributematchtype;
44 Accessibility_Collection_MatchType rolematchtype;
46 Accessibility_Collection_MatchType interfacematchtype;
51 child_interface_p (AtkObject *child,
54 if (!strcasecmp(repo_id, "action")) return atk_is_action(child);
55 if (!strcasecmp(repo_id, "component")) return atk_is_component(child);
56 if (!strcasecmp(repo_id, "editabletext")) return atk_is_editable_text(child);
57 if (!strcasecmp(repo_id, "text")) return atk_is_text(child);
58 if (!strcasecmp(repo_id, "hypertext")) return atk_is_hypertext(child);
59 if (!strcasecmp(repo_id, "image")) return atk_is_image(child);
60 if (!strcasecmp(repo_id, "selection")) return atk_is_selection(child);
61 if (!strcasecmp(repo_id, "table")) return atk_is_table(child);
62 if (!strcasecmp(repo_id, "value")) return atk_is_value(child);
63 if (!strcasecmp(repo_id, "streamablecontent")) return atk_is_streamable_content(child);
64 if (!strcasecmp(repo_id, "document")) return atk_is_document(child);
68 #define child_collection_p(ch) (TRUE)
71 match_states_all_p (AtkObject *child,
81 chs = atk_object_ref_state_set (child);
83 // TODO: use atk-state_set_contains_states; would be more efficient
84 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
86 if (!atk_state_set_contains_state(chs, set[i]))
98 match_states_any_p (AtkObject *child,
103 gboolean ret = FALSE;
108 chs = atk_object_ref_state_set (child);
110 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
112 if (!atk_state_set_contains_state(chs, set[i]))
124 match_states_none_p (AtkObject *child,
134 chs = atk_object_ref_state_set (child);
136 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
138 if (atk_state_set_contains_state(chs, set[i]))
149 // TODO: need to convert at-spi roles/states to atk roles/states */
151 match_states_lookup (AtkObject *child,
152 MatchRulePrivate *mrp)
154 switch (mrp->statematchtype){
155 case Accessibility_Collection_MATCH_ALL :
156 if (match_states_all_p (child, mrp->states))
160 case Accessibility_Collection_MATCH_ANY :
161 if (match_states_any_p (child, mrp->states))
165 case Accessibility_Collection_MATCH_NONE :
166 if (match_states_none_p (child, mrp->states))
176 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
177 // would be more efficient
178 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
181 match_roles_all_p (AtkObject *child,
184 Accessibility_Role role;
186 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
187 else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
189 return (atk_object_get_role(child) == roles[0]);
194 match_roles_any_p (AtkObject *child,
200 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
202 role = atk_object_get_role(child);
204 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
205 if (role == roles[i])
212 match_roles_none_p (AtkObject *child,
218 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
220 role = atk_object_get_role(child);
222 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
223 if (role == roles[i])
230 match_roles_lookup (AtkObject *child,
231 MatchRulePrivate *mrp)
233 switch (mrp->rolematchtype){
234 case Accessibility_Collection_MATCH_ALL :
235 if (match_roles_all_p (child, mrp->roles))
239 case Accessibility_Collection_MATCH_ANY :
240 if (match_roles_any_p (child, mrp->roles))
244 case Accessibility_Collection_MATCH_NONE :
245 if (match_roles_none_p (child, mrp->roles))
256 match_interfaces_all_p (AtkObject *obj,
264 for (i = 0; ifaces[i]; i++)
265 if (!child_interface_p (obj, ifaces [i])){
272 match_interfaces_any_p (AtkObject *obj,
281 for (i = 0; ifaces[i]; i++)
282 if (child_interface_p (obj, ifaces [i])){
289 match_interfaces_none_p (AtkObject *obj,
294 for (i = 0; ifaces[i]; i++)
295 if (child_interface_p (obj, ifaces [i]))
302 match_interfaces_lookup (AtkObject *child,
303 MatchRulePrivate *mrp)
305 switch (mrp->interfacematchtype){
307 case Accessibility_Collection_MATCH_ALL :
308 if (match_interfaces_all_p (child, mrp->ifaces))
312 case Accessibility_Collection_MATCH_ANY :
313 if (match_interfaces_any_p (child, mrp->ifaces))
317 case Accessibility_Collection_MATCH_NONE :
318 if (match_interfaces_none_p (child, mrp->ifaces))
328 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
331 match_attributes_all_p (AtkObject *child,
332 AtkAttributeSet *attributes)
336 gint length, oa_length;
337 gboolean flag = FALSE;
339 if (attributes == NULL || g_slist_length (attributes) == 0)
342 oa = atk_object_get_attributes(child);
343 length = g_slist_length(attributes);
344 oa_length = g_slist_length(oa);
346 for (i = 0; i < length; i++) {
347 AtkAttribute *attr = g_slist_nth_data(attributes, i);
348 for (k = 0; k < oa_length; k++) {
349 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
350 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
351 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
359 atk_attribute_set_free(oa);
363 atk_attribute_set_free(oa);
368 match_attributes_any_p (AtkObject *child,
369 AtkAttributeSet *attributes)
374 gint length, oa_length;
376 length = g_slist_length(attributes);
380 oa = atk_object_get_attributes(child);
381 oa_length = g_slist_length(oa);
383 for (i = 0; i < length; i++){
384 AtkAttribute *attr = g_slist_nth_data(attributes, i);
385 for (k = 0; k < oa_length; k++){
386 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
387 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
388 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
389 atk_attribute_set_free(oa);
394 atk_attribute_set_free(oa);
399 match_attributes_none_p (AtkObject *child,
400 AtkAttributeSet *attributes)
405 gint length, oa_length;
407 length = g_slist_length(attributes);
411 oa = atk_object_get_attributes(child);
412 oa_length = g_slist_length(oa);
414 for (i = 0; i < length; i++){
415 AtkAttribute *attr = g_slist_nth_data(attributes, i);
416 for (k = 0; k < oa_length; k++){
417 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
418 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
419 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
420 atk_attribute_set_free(oa);
425 atk_attribute_set_free(oa);
430 match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
432 switch (mrp->attributematchtype){
434 case Accessibility_Collection_MATCH_ALL :
435 if (match_attributes_all_p (child, mrp->attributes))
439 case Accessibility_Collection_MATCH_ANY :
440 if (match_attributes_any_p (child, mrp->attributes))
444 case Accessibility_Collection_MATCH_NONE :
445 if (match_attributes_none_p (child, mrp->attributes))
455 traverse_p (AtkObject *child,
456 const gboolean traverse)
460 else return !child_collection_p (child);
464 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
465 gint kount, gint max,
466 AtkObject *obj, glong index, gboolean flag,
467 AtkObject *pobj, gboolean recurse,
471 glong acount = atk_object_get_n_accessible_children (obj);
472 gboolean prev = pobj? TRUE : FALSE;
474 for (; i < acount && (max == 0 || kount < max); i++){
476 atk_object_ref_accessible_child(obj, i);
478 g_object_unref(child);
479 if (prev && child == pobj){
483 if (flag && match_interfaces_lookup (child, mrp)
484 && match_states_lookup (child, mrp)
485 && match_roles_lookup (child, mrp)
486 && match_attributes_lookup (child, mrp)
489 ls = g_list_append (ls, child);
496 if (recurse && traverse_p (child, traverse))
497 kount = sort_order_canonical (mrp, ls, kount,
499 pobj, recurse, traverse);
505 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
506 gint kount, gint max,
507 AtkObject *obj, gboolean flag,
514 /* This breaks us out of the recursion. */
515 if (!obj || obj == pobj)
520 /* Add to the list if it matches */
521 if (flag && match_interfaces_lookup (obj, mrp)
522 && match_states_lookup (obj, mrp)
523 && match_roles_lookup (obj, mrp)
524 && match_attributes_lookup (obj, mrp))
526 ls = g_list_append (ls, obj);
530 if(!flag) flag = TRUE;
532 /* Get the current nodes index in it's parent and the parent object. */
533 indexinparent = atk_object_get_index_in_parent (obj);
534 parent = atk_object_get_parent(obj);
536 if(indexinparent > 0)
538 /* there are still some siblings to visit so get the previous sibling
539 and get it's last descendant.
540 First, get the previous sibling */
541 nextobj = atk_object_ref_accessible_child (parent,
543 g_object_unref(nextobj);
545 /* Now, drill down the right side to the last descendant */
546 while(atk_object_get_n_accessible_children (nextobj) > 0)
548 nextobj = atk_object_ref_accessible_child(nextobj,
549 atk_object_get_n_accessible_children (nextobj)-1);
550 g_object_unref (nextobj);
552 /* recurse with the last descendant */
553 kount = sort_order_rev_canonical (mrp, ls, kount, max,
554 nextobj, TRUE, pobj);
558 /* no more siblings so next node must be the parent */
559 kount = sort_order_rev_canonical (mrp, ls, kount, max,
567 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
568 GList *ls, gint kount, gint max,
569 AtkObject *obj, glong index,
572 gboolean recurse, gboolean traverse)
575 case Accessibility_Collection_SORT_ORDER_CANONICAL :
576 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
577 pobj, recurse, traverse);
579 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
580 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
581 pobj, recurse, traverse);
585 g_warning ("Sort method not implemented yet");
593 read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
595 DBusMessageIter mrc, arrayc;
596 dbus_uint32_t *array;
597 dbus_int32_t matchType;
602 char *interfaces = NULL;
604 // TODO: error checking
605 dbus_message_iter_recurse(iter, &mrc);
606 dbus_message_iter_recurse(&mrc, &arrayc);
607 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
608 bitarray_to_seq(array, array_count, &mrp->states);
609 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
611 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
613 dbus_message_iter_next(&mrc);
614 dbus_message_iter_read_basic(&mrc, &matchType);
615 dbus_message_iter_next(&mrc);
616 mrp->statematchtype = matchType;;
618 dbus_message_iter_recurse(&mrc, &arrayc);
619 mrp->attributes = NULL;
620 while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
622 dbus_message_iter_get_basic(&arrayc, &str);
623 // TODO: remove this print
624 g_print("Got attribute: %s\n", str);
625 attr = g_new (AtkAttribute, 1);
628 int len = strcspn(str, ":");
629 attr->name = g_strndup(str, len);
633 if (str[len] == ' ') len++;
634 attr->value = g_strdup(str + len);
636 else attr->value = NULL;
637 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
639 dbus_message_iter_next(&arrayc);
641 dbus_message_iter_next(&mrc);
642 dbus_message_iter_read_basic(&mrc, &matchType);
643 mrp->attributematchtype = matchType;;
644 dbus_message_iter_next(&mrc);
645 /* Get roles and role match */
646 dbus_message_iter_recurse(&mrc, &arrayc);
647 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
648 bitarray_to_seq(array, array_count, &mrp->roles);
649 dbus_message_iter_next(&mrc);
650 dbus_message_iter_read_basic(&mrc, &matchType);
651 mrp->rolematchtype = matchType;;
652 dbus_message_iter_next(&mrc);
653 /* Get interfaces and interface match */
654 dbus_message_iter_read_basic(&mrc, &interfaces);
655 dbus_message_iter_next(&mrc);
656 mrp->ifaces = g_strsplit(interfaces, ";", 0);
657 dbus_message_iter_read_basic(&mrc, &matchType);
658 mrp->interfacematchtype = matchType;;
659 dbus_message_iter_next(&mrc);
661 dbus_message_iter_read_basic(&mrc, &mrp->invert);
662 dbus_message_iter_next(iter);
667 return_and_free_list(DBusMessage *message, GList *ls)
670 DBusMessageIter iter, iter_array;
673 reply = dbus_message_new_method_return(message);
674 if (!reply) return NULL;
675 dbus_message_iter_init_append(reply, &iter);
676 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
677 for (item = ls; item; item = g_list_next(item))
679 char *path = (char *) spi_dbus_object_to_path ((AtkObject *)item->data);
680 dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
683 if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
687 // TODO: Handle out of memory
692 static void free_mrp_data(MatchRulePrivate *mrp)
695 atk_attribute_set_free(mrp->attributes);
697 g_strfreev(mrp->ifaces);
701 getMatchesFrom (DBusMessage *message,
702 AtkObject *current_object,
703 MatchRulePrivate *mrp,
704 const Accessibility_Collection_SortOrder sortby,
705 const dbus_bool_t isrestrict,
707 const dbus_bool_t traverse)
712 atk_object_get_index_in_parent (current_object);
715 ls = g_list_append (ls, current_object);
719 parent = atk_object_get_parent (current_object);
720 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
721 FALSE, NULL, TRUE, traverse);
724 kount = query_exec (mrp, sortby, ls, 0, count,
725 current_object, 0, FALSE, NULL,
728 ls = g_list_remove (ls, ls->data);
730 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
731 ls = g_list_reverse (ls);
734 return return_and_free_list (message, ls);
738 inorder traversal from a given object in the hierarchy
742 inorder (AtkObject *collection, MatchRulePrivate *mrp,
743 GList *ls, gint kount, gint max,
747 dbus_bool_t traverse)
751 /* First, look through the children recursively. */
752 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
755 /* Next, we look through the right subtree */
756 while ((max == 0 || kount < max)
757 && obj != collection)
760 atk_object_get_parent (obj);
761 i = atk_object_get_index_in_parent (obj);
762 kount = sort_order_canonical (mrp, ls, kount, max, parent,
763 i+1, TRUE, FALSE, TRUE, TRUE);
769 kount = sort_order_canonical (mrp, ls, kount, max,
770 obj, i + 1, TRUE, FALSE,
778 GetMatchesInOrder: get matches from a given object in an inorder traversal.
782 getMatchesInOrder (DBusMessage *message,
783 AtkObject *current_object,
784 MatchRulePrivate *mrp,
785 const Accessibility_Collection_SortOrder sortby,
786 const dbus_bool_t recurse,
788 const dbus_bool_t traverse)
794 ls = g_list_append (ls, current_object);
796 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
798 kount = inorder (obj, mrp, ls, 0, count,
799 current_object, TRUE, NULL, traverse);
801 ls = g_list_remove (ls, ls->data);
803 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
804 ls = g_list_reverse (ls);
807 return return_and_free_list (message, ls);
811 GetMatchesInBackOrder: get matches from a given object in a
812 reverse order traversal.
816 getMatchesInBackOrder (DBusMessage *message,
817 AtkObject *current_object,
818 MatchRulePrivate *mrp,
819 const Accessibility_Collection_SortOrder sortby,
823 AtkObject *collection;
826 ls = g_list_append (ls, current_object);
828 collection = atk_dbus_path_to_object (dbus_message_get_path (message));
830 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
833 ls = g_list_remove (ls, ls->data);
835 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
836 ls = g_list_reverse (ls);
839 return return_and_free_list (message, ls);
843 getMatchesTo (DBusMessage *message,
844 AtkObject *current_object,
845 MatchRulePrivate *mrp,
846 const Accessibility_Collection_SortOrder sortby,
847 const dbus_bool_t recurse,
848 const dbus_bool_t isrestrict,
850 const dbus_bool_t traverse)
856 ls = g_list_append (ls, current_object);
859 obj = atk_object_get_parent (current_object);
860 kount = query_exec (mrp, sortby, ls, 0, count,
861 obj, 0, TRUE, current_object, TRUE, traverse);
864 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
865 kount = query_exec (mrp, sortby, ls, 0, count,
866 obj, 0, TRUE, current_object, TRUE, traverse);
870 ls = g_list_remove (ls, ls->data);
872 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
873 ls = g_list_reverse (ls);
876 return return_and_free_list (message, ls);
880 impl_getMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
882 char *current_object_path = NULL;
883 AtkObject *current_object;
884 DBusMessageIter iter;
885 MatchRulePrivate rule;
886 dbus_uint16_t sortby;
889 dbus_bool_t traverse;
892 dbus_message_iter_init(message, &iter);
893 dbus_message_iter_get_basic (&iter, current_object_path);
894 current_object = atk_dbus_path_to_object (current_object_path);
897 // TODO: object-not-found error
898 return spi_dbus_general_error (message);
900 dbus_message_iter_next (&iter);
901 if (!read_mr(&iter, &rule))
903 return spi_dbus_general_error (message);
905 dbus_message_iter_get_basic(&iter, &sortby);
906 dbus_message_iter_next(&iter);
907 dbus_message_iter_get_basic(&iter, &tree);
908 dbus_message_iter_next(&iter);
909 dbus_message_iter_get_basic(&iter, &count);
910 dbus_message_iter_next(&iter);
911 dbus_message_iter_get_basic(&iter, &traverse);
912 dbus_message_iter_next(&iter);
915 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
916 return getMatchesFrom (message, current_object,
917 &rule, sortby, TRUE, count, traverse);
919 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
920 return getMatchesFrom (message, current_object,
921 &rule, sortby, FALSE, count, traverse);
923 case Accessibility_Collection_TREE_INORDER :
924 return getMatchesInOrder (message, current_object,
925 &rule, sortby, TRUE, count, traverse);
927 default : return NULL;
932 impl_getMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
934 char *current_object_path = NULL;
935 AtkObject *current_object;
936 DBusMessageIter iter;
937 MatchRulePrivate rule;
938 dbus_uint16_t sortby;
942 dbus_bool_t traverse;
945 dbus_message_iter_init(message, &iter);
946 dbus_message_iter_get_basic (&iter, current_object_path);
947 current_object = atk_dbus_path_to_object (current_object_path);
950 // TODO: object-not-found error
951 return spi_dbus_general_error (message);
953 dbus_message_iter_next (&iter);
954 if (!read_mr(&iter, &rule))
956 return spi_dbus_general_error (message);
958 dbus_message_iter_get_basic(&iter, &sortby);
959 dbus_message_iter_next(&iter);
960 dbus_message_iter_get_basic(&iter, &tree);
961 dbus_message_iter_next(&iter);
962 dbus_message_iter_get_basic(&iter, &recurse);
963 dbus_message_iter_next(&iter);
964 dbus_message_iter_get_basic(&iter, &count);
965 dbus_message_iter_next(&iter);
966 dbus_message_iter_get_basic(&iter, &traverse);
967 dbus_message_iter_next(&iter);
970 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
971 return getMatchesTo (message, current_object,
972 &rule, sortby, recurse, TRUE, count, traverse);
974 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
975 return getMatchesTo (message, current_object,
976 &rule, sortby, recurse, FALSE, count, traverse);
978 case Accessibility_Collection_TREE_INORDER :
979 return getMatchesInBackOrder (message, current_object,
980 &rule, sortby, count);
982 default : return NULL;
987 impl_getMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
989 AtkObject *obj = atk_dbus_path_to_object (dbus_message_get_path (message));
990 DBusMessageIter iter;
991 MatchRulePrivate rule;
992 dbus_uint16_t sortby;
994 dbus_bool_t traverse;
997 dbus_message_iter_init(message, &iter);
998 if (!read_mr(&iter, &rule))
1000 return spi_dbus_general_error (message);
1002 dbus_message_iter_get_basic(&iter, &sortby);
1003 dbus_message_iter_next(&iter);
1004 dbus_message_iter_get_basic(&iter, &count);
1005 dbus_message_iter_next(&iter);
1006 dbus_message_iter_get_basic(&iter, &traverse);
1007 dbus_message_iter_next(&iter);
1008 ls = g_list_prepend (ls, obj);
1009 count = query_exec (&rule, sortby, ls, 0, count,
1010 obj, 0, TRUE, NULL, TRUE, traverse);
1011 ls = g_list_remove (ls, ls->data);
1013 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1014 ls = g_list_reverse (ls);
1015 free_mrp_data (&rule);
1016 return return_and_free_list (message, ls);
1019 static DRouteMethod methods[] = {
1020 { impl_getMatchesFrom, "getMatchesFrom" },
1021 { impl_getMatchesTo, "getMatchesTo" },
1022 { impl_getMatches, "getMatches" },
1027 spi_initialize_collection (DRoutePath *path)
1029 droute_path_add_interface (path,
1030 SPI_DBUS_INTERFACE_COLLECTION,