4 Copyright (C) Simo Sorce 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb server side sort control module
30 * Description: this module sorts the results of a search
36 #include "ldb/include/includes.h"
39 struct ldb_context *ldb;
40 const struct ldb_attrib_handler *h;
41 const char *attribute;
46 static int build_response(struct ldb_result *res, int result, const char *desc)
48 struct ldb_sort_resp_control *resp;
52 for (i = 0; res->controls[i]; i++);
53 res->controls = talloc_realloc(res, res->controls, struct ldb_control *, i + 2);
56 res->controls = talloc_array(res, struct ldb_control *, 2);
59 return LDB_ERR_OPERATIONS_ERROR;
61 res->controls[i+1] = NULL;
62 res->controls[i] = talloc(res->controls, struct ldb_control);
63 if (! res->controls[i] )
64 return LDB_ERR_OPERATIONS_ERROR;
66 res->controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
67 res->controls[i]->critical = 0;
69 resp = talloc(res->controls[i], struct ldb_sort_resp_control);
71 return LDB_ERR_OPERATIONS_ERROR;
73 resp->result = result;
74 resp->attr_desc = talloc_strdup(resp, desc);
76 if (! resp->attr_desc )
77 return LDB_ERR_OPERATIONS_ERROR;
79 res->controls[i]->data = resp;
84 static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
86 struct opaque *data = (struct opaque *)opaque;
87 struct ldb_message_element *el1, *el2;
89 if (data->result != 0) {
90 /* an error occurred previously,
91 * let's exit the sorting by returning always 0 */
95 el1 = ldb_msg_find_element(*msg1, data->attribute);
96 el2 = ldb_msg_find_element(*msg2, data->attribute);
99 /* the attribute was not found return and
106 return data->h->comparison_fn(data->ldb, data, &el2->values[0], &el1->values[0]);
108 return data->h->comparison_fn(data->ldb, data, &el1->values[0], &el2->values[0]);
112 static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
114 struct ldb_result *sort_result = NULL;
115 struct ldb_control *control;
116 struct ldb_control **saved_controls;
117 struct ldb_server_sort_control **sort_ctrls;
121 /* check if there's a paged request control */
122 control = get_control_from_list(req->controls, LDB_CONTROL_SERVER_SORT_OID);
123 if (control == NULL) {
124 /* not found go on */
125 return ldb_next_request(module, req);
128 sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
130 return LDB_ERR_PROTOCOL_ERROR;
133 /* FIXME: we do not support more than one attribute for sorting right now */
134 /* FIXME: we need to check if the attribute type exist or return an error */
135 if (sort_ctrls[1] != NULL)
138 if (!do_sort && control->critical) {
139 sort_result = talloc_zero(req, struct ldb_result);
141 return LDB_ERR_OPERATIONS_ERROR;
143 req->op.search.res = sort_result;
145 /* 53 = unwilling to perform */
146 if ((ret = build_response(sort_result, 53, "sort control is not complete yet")) != LDB_SUCCESS) {
150 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
153 /* save it locally and remove it from the list */
154 if (!save_controls(control, req, &saved_controls)) {
155 return LDB_ERR_OPERATIONS_ERROR;
158 ret = ldb_next_request(module, req);
160 if (req->controls) talloc_free(req->controls);
161 req->controls = saved_controls;
163 if (ret != LDB_SUCCESS) {
171 data = talloc(module, struct opaque);
173 return LDB_ERR_OPERATIONS_ERROR;
175 data->attribute = sort_ctrls[0]->attributeName;
176 data->reverse = sort_ctrls[0]->reverse;
177 data->ldb = module->ldb;
178 data->h = ldb_attrib_handler(data->ldb, data->attribute);
180 sort_result = req->op.search.res;
182 /* FIXME: I don't like to use a static structure like sort_control
184 * a) write a qsort function that takes a third void parameter
186 * b) prepare a structure with all elements pre digested like:
188 * struct ldb_message_element *el;
189 * struct ldb_message *msg;
192 * this mean we will have to do a linear scan of
193 * the msgs array to build the new sort array, and
194 * then do a linear scan of the resulting array
195 * to rebuild the msgs array in the original shape.
198 ldb_qsort(sort_result->msgs,
200 sizeof(struct ldb_message *),
202 (ldb_qsort_cmp_fn_t)sort_compare);
204 result = data->result;
211 if ((ret = build_response(sort_result, result, "sort control is not complete yet")) != LDB_SUCCESS) {
218 static int server_sort(struct ldb_module *module, struct ldb_request *req)
220 switch (req->operation) {
223 return server_sort_search(module, req);
226 return ldb_next_request(module, req);
231 static int server_sort_init(struct ldb_module *module)
233 struct ldb_request request;
236 request.operation = LDB_REQ_REGISTER;
237 request.op.reg.oid = LDB_CONTROL_SERVER_SORT_OID;
238 request.controls = NULL;
240 ret = ldb_request(module->ldb, &request);
241 if (ret != LDB_SUCCESS) {
242 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "server_sort: Unable to register control with rootdse!\n");
243 return LDB_ERR_OTHER;
246 return ldb_next_init(module);
249 static const struct ldb_module_ops server_sort_ops = {
250 .name = "server_sort",
251 .request = server_sort,
252 .init_context = server_sort_init
255 int ldb_sort_init(void)
257 return ldb_register_module(&server_sort_ops);