Author: mkhl
Date: 2006-06-26 22:07:25 +0000 (Mon, 26 Jun 2006)
New Revision: 16534

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=16534

Log:
Add support for merging remote search results with local search
results.

Martin

Modified:
   branches/SOC/mkhl/ldb-map/modules/ldb_map.c


Changeset:
Modified: branches/SOC/mkhl/ldb-map/modules/ldb_map.c
===================================================================
--- branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-26 21:21:59 UTC (rev 
16533)
+++ branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-26 22:07:25 UTC (rev 
16534)
@@ -791,7 +791,6 @@
        return NULL;
 }
 
-
 /* local DN -> remote DN (as LDB values) */
 static
 struct ldb_val
@@ -1131,112 +1130,6 @@
 /* } */
 
 /* /\* XXX *\/ */
-/* /\* Remote message element -> Local message element *\/ */
-/* static struct ldb_message_element *mop_remote_msg_element(struct ldb_module 
*module, */
-/*                                                       struct ldb_message 
*msg, */
-/*                                                       const struct 
ldb_message *oldmsg, */
-/*                                                       const struct 
ldb_map_attribute *attr) */
-/* { */
-/*     struct ldb_message_element *el, *oldel; */
-/*     int i; */
-
-/*     el = talloc(msg, struct ldb_message_element); */
-/*     if (el == NULL) */
-/*             return NULL; */
-
-/*     switch (attr->type) { */
-/*     case MAP_IGNORE: */
-/*             goto failed; */
-
-/*     case MAP_KEEP: */
-/*             ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map: " */
-/*                       "Keeping remote attribute '%s'\n", attr->local_name); 
*/
-
-/*             oldel = ldb_msg_find_element(oldmsg, attr->local_name); */
-/*             if (oldel == NULL) */
-/*                     goto failed; */
-
-/*             el->name = talloc_strdup(el, attr->local_name); */
-/*             el->flags = oldel->flags; */
-/*             el->num_values = oldel->num_values; */
-/*             el->values = talloc_array(el, struct ldb_val, el->num_values); 
*/
-/*             if (el->values == NULL) */
-/*                     goto failed; */
-
-/*             for (i = 0; i < el->num_values; i++) */
-/*                     el->values[i] = ldb_val_dup(el, &oldel->values[i]); */
-
-/*             return el; */
-
-/*     case MAP_RENAME: */
-/*             ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map: " */
-/*                       "Renaming remote attribute '%s' to '%s'\n", */
-/*                       attr->u.rename.remote_name, attr->local_name); */
-
-/*             oldel = ldb_msg_find_element(oldmsg, 
attr->u.rename.remote_name); */
-/*             if (oldel == NULL) */
-/*                     goto failed; */
-
-/*             el->name = talloc_strdup(el, attr->local_name); */
-/*             el->flags = oldel->flags; */
-/*             el->num_values = oldel->num_values; */
-/*             el->values = talloc_array(el, struct ldb_val, el->num_values); 
*/
-/*             if (el->values == NULL) */
-/*                     goto failed; */
-
-/*             for (i = 0; i < el->num_values; i++) */
-/*                     el->values[i] = ldb_val_dup(el, &oldel->values[i]); */
-
-/*             return el; */
-                               
-/*     case MAP_CONVERT: */
-/*             ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map: " */
-/*                       "Converting remote attribute '%s' to '%s'\n", */
-/*                       attr->u.rename.remote_name, attr->local_name); */
-
-/*             if (attr->u.convert.convert_remote == NULL) { */
-/*                     ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " */
-/*                               "'convert_remote' not set!\n"); */
-/*                     goto failed; */
-/*             } */
-
-/*             oldel = ldb_msg_find_element(oldmsg, 
attr->u.rename.remote_name); */
-/*             if (oldel == NULL)  */
-/*                     goto failed; */
-
-/*             el->name = talloc_strdup(el, attr->local_name); */
-/*             el->flags = oldel->flags; */
-/*             el->num_values = oldel->num_values; */
-/*             el->values = talloc_array(el, struct ldb_val, el->num_values); 
*/
-/*             if (el->values == NULL) */
-/*                     goto failed; */
-
-/*             for (i = 0; i < el->num_values; i++) */
-/*                     el->values[i] = attr->u.convert.convert_remote(module, 
el, &oldel->values[i]); */
-
-/*             return el; */
-
-/*     case MAP_GENERATE: */
-/*             ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map: " */
-/*                       "Generating local attribute '%s'\n", */
-/*                       attr->local_name); */
-
-/*             if (attr->u.generate.generate_local == NULL) { */
-/*                     ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " */
-/*                               "'generate_local' not set!\n"); */
-/*                     goto failed; */
-/*             } */
-
-/*             talloc_free(el); */
-/*             return attr->u.generate.generate_local(module, msg, 
attr->local_name, oldmsg); */
-/*     } */
-
-/* failed: */
-/*     talloc_free(el); */
-/*     return NULL; */
-/* } */
-
-/* /\* XXX *\/ */
 /* /\* Remote message -> Local message *\/ */
 /* static struct ldb_message *mop_ldb_message_incoming(struct ldb_module 
*module, */
 /*                                                 const char *const names[], 
*/
@@ -1292,15 +1185,42 @@
 /*     return NULL; */
 /* } */
 
+/* add element to message, overwriting old elements of the same name */
+static
+int
+ldb_msg_replace(struct ldb_message *msg,
+               const struct ldb_message_element *el)
+{
+       struct ldb_message_element *old;
+
+       old = ldb_msg_find_element(msg, el->name);
+       /* no local result, add as new */
+       if (old == NULL) {
+               if (ldb_msg_add_empty(msg, el->name, 0) != LDB_SUCCESS)
+                       goto failed;
+
+               old = ldb_msg_find_element(msg, el->name);
+               if (old == NULL)
+                       goto failed;
+       }
+
+       *old = *el; /* copy element */
+
+       return 0;
+
+failed:
+       return -1;
+}
+
 /* Create a copy of the given message element with the specified name.
  * If a mapping is specified, use it to convert the values. */
 static
 struct ldb_message_element *
 copy_conv_msg_el(struct ldb_module *module,
                 struct ldb_message *msg,
-                const struct ldb_map_attribute *map,
                 const struct ldb_message_element *old,
-                const char *name)
+                const char *name,
+                const ldb_map_convert_func map)
 {
        struct ldb_message_element *el;
        int i;
@@ -1326,8 +1246,7 @@
                if (map == NULL)
                        el->values[i] = ldb_val_dup(el, &old->values[i]);
                else
-                       el->values[i] = map->u.convert
-                               .convert_local(module, el, &old->values[i]);
+                       el->values[i] = map(module, el, &old->values[i]);
        }
 
        return el;
@@ -1360,13 +1279,11 @@
                goto local;
 
        case MAP_KEEP:
-               el = copy_conv_msg_el(module, remote, NULL, old,
-                                     map->local_name);
+               el = copy_conv_msg_el(module, remote, old, map->local_name, 
NULL);
                break;
 
        case MAP_RENAME:
-               el = copy_conv_msg_el(module, remote, NULL, old,
-                                     map->u.rename.remote_name);
+               el = copy_conv_msg_el(module, remote, old, 
map->u.rename.remote_name, NULL);
                break;
 
        case MAP_CONVERT:
@@ -1377,8 +1294,7 @@
                                  map->local_name);
                goto failed;
 
-               el = copy_conv_msg_el(module, remote, map, old,
-                                     map->u.rename.remote_name);
+               el = copy_conv_msg_el(module, remote, old, 
map->u.convert.remote_name, map->u.convert.convert_local);
                break;
 
        case MAP_GENERATE:
@@ -1442,6 +1358,7 @@
                }
 
                map = find_local_attr(data, msg->elements[i].name);
+
                ret = partition_msg_el(module, local, remote, map,
                                       msg, &msg->elements[i]);
                if (ret != 0)
@@ -1451,14 +1368,97 @@
        return 0;
 }
 
+/* merge remote message element into local message */
 static
 int
-merge_mapped_results(struct map_async_search_context *context)
+merge_msg_el(struct ldb_module *module,
+            struct ldb_message *local,
+            struct ldb_message *remote,
+            const struct ldb_map_attribute *map,
+            const struct ldb_message_element *old)
 {
-       return LDB_SUCCESS;     /* TODO */
+       struct ldb_message_element *el;
+
+       /* no mapping: fail */
+       if (map == NULL) {
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
+                         "Not mapping attribute '%s': no mapping found\n",
+                         old->name);
+               goto failed;
+       }
+
+       switch (map->type) {
+       case MAP_IGNORE:
+               goto failed;
+
+       case MAP_KEEP:
+       case MAP_RENAME:
+               el = copy_conv_msg_el(module, local, old, map->local_name, 
NULL);
+               break;
+
+       case MAP_CONVERT:
+               if (map->u.convert.convert_remote == NULL) {
+                       ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+                                 "Skipping attribute '%s': "
+                                 "'convert_remote' not set\n",
+                                 old->name);
+                       goto unmapped;
+               }
+
+               el = copy_conv_msg_el(module, local, old, map->local_name, 
map->u.convert.convert_remote);
+               break;
+
+       case MAP_GENERATE:
+               if (map->u.generate.generate_local == NULL) {
+                       ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+                                 "Skipping attribute '%s': "
+                                 "'generate_local' not set\n",
+                                 old->name);
+                       goto unmapped;
+               }
+
+               el =  map->u.generate.generate_local(module, local, 
map->local_name, remote);
+               break;
+       }
+
+       if (el == NULL)
+               goto failed;
+       return ldb_msg_replace(local, el);
+
+unmapped:
+               return 0;
+
+failed:
+               return -1;
 }
 
+/* merge remote message into local message */
+static
+int
+merge_msg(struct ldb_module *module,
+         struct ldb_message *local,
+         struct ldb_message *remote)
+{
+       struct ldb_map_context *data = map_get_context(module);
+       const struct ldb_map_attribute *map;
+       int i, ret;
 
+       /* try to map each attribute back;
+          add to the local message is possible,
+          overwrite old local attribute if necessary */
+       for (i = 0; i < remote->num_elements; i++) {
+               map = find_remote_attr(data, remote->elements[i].name);
+
+               ret = merge_msg_el(module, local, remote, map,
+                                  &remote->elements[i]);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
 /* store single search result in async context */
 static
 int
@@ -1577,7 +1577,7 @@
                sc->remote_res = ares;
 
                /* merge remote into local record */
-               ret = merge_mapped_results(sc);
+               ret = merge_msg(sc->ac->module, sc->local_res->message, 
sc->remote_res->message);
                if (ret != LDB_SUCCESS)
                        talloc_free(ares);
 
@@ -1648,6 +1648,7 @@
        sc->local_res = ares;
        sc->remote_res = NULL;
 
+       /* TODO: map the remote parse-tree */
        remote_attrs = select_mapped_attrs(ac->module, ac,
                                           ac->orig_req->op.search.attrs);
        req = search_base_req(ac, dn, remote_attrs, remote_search_callback);

Reply via email to