/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Portions Copyright 2008 Sun Microsystems, Inc. All Rights Reserved
 * Use is subject to license terms.
 * Some preexisting portions Copyright 1997-2001 Netscape Communications Corp.
 * All rights reserved.
 */
/************************************************************

 testentry.c

 This source file provides examples of entry store and
 entry fetch plug-in functions.  These plug-in functions are
 called by the server before writing an entry to disk and
 after reading an entry from disk.

 Entry store and entry fetch plug-in functions are passed
 the string representation (in LDIF -- LDAP Data Interchange
 Format) of the entry.

 In this example, the entry store function performs a bitwise
 exclusive-or operation on each character in the entry
 against the value 0xaa (10101010).  The entry fetch
 function performs this again to revert each character
 back to its initial value.

 NOTE: Directory Server caches recently added and retrieved
 entries in memory.  The entry fetch plug-in function is called
 only when reading the entry from the disk, *not* when reading
 the entry from the cache.

 For example, if you add an entry and search for it, you will
 not see a message in the server errors log indicating that
 the entry fetch plug-in function was called. In the process
 of adding the entry to the directory, the server also added
 the entry to the cache; the server then reads the entry from
 the cache instead of from the disk and does not need to call
 the entry fetch plug-in function.

 You can flush the cache by shutting down the server.

 ACTIVATING THIS PLUG-IN
 -----------------------
 1. Build the library containing the plug-in.

 2. Configure the server to log plug-in messages.

    $ dsconf set-log-prop error level:err-plugins

 3. Configure the server to load the plug-in.

    $ dsconf create-plugin -H <lib-path> -F testentry_init -Y ldbmentryfetchstore "Test entry"
    $ dsconf set-plugin-prop "Test entry" depends-on-type:database feature:test-entry version:7.0 desc:"Sample entry store/fetch plug-in"
    $ dsconf enable-plugin "Test entry"
    Directory Server needs to be restarted for changes to take effect
    $ dsadm restart <inst-path>

*************************************************************/
#include <stdio.h>
#include <string.h>
#include "slapi-plugin.h"
#ifdef _WIN32
typedef unsigned int uint;
#endif

Slapi_PluginDesc entrypdesc = {
    "test-entry",                      /* plug-in identifier      */
    "Oracle Corporation (test)",       /* vendor name             */
    "11.1.1.3.0",                      /* plug-in revision number */
    "Sample entry store/fetch plug-in" /* plug-in description     */
};

/* Scramble the entry to store and note the work in the log.      */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
testentry_scramble(unsigned char ** entry, uint * len)
{
    uint i;

    (*len)++;
    *entry = slapi_ch_realloc(*entry, *len);
    /* Scramble using bitwise exclusive-or on each character.     */
    for (i = *len - 1; i > 0; i--) {
         (*entry)[i] = (*entry)[i - 1] ^ 0xaa;
    }
    (*entry)[0] = 0xaa;

    slapi_log_info_ex(
        SLAPI_LOG_INFO_AREA_PLUGIN,
        SLAPI_LOG_INFO_LEVEL_DEFAULT,
        SLAPI_LOG_NO_MSGID,
        SLAPI_LOG_NO_CONNID,
        SLAPI_LOG_NO_OPID,
        "testentry_scramble in test-entry plug-in",
        "Entry data scrambled.\n"
    );

    return 0;
}

/* Unscramble scrambled entries and note the work in the log.     */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
testentry_unscramble(unsigned char ** entry, uint * len)
{
    uint i;

    /* Return now if the entry is not scrambled.                  */
    if (**entry != 0xaa) { return 0; }

    /* Unscramble using bitwise exclusive-or on each character.   */
    (*len)--;
    for (i = 0; i < *len; i++) {
        (*entry)[i] = (*entry)[i + 1] ^ 0xaa;
    }

    slapi_log_info_ex(
        SLAPI_LOG_INFO_AREA_PLUGIN,
        SLAPI_LOG_INFO_LEVEL_DEFAULT,
        SLAPI_LOG_NO_MSGID,
        SLAPI_LOG_NO_CONNID,
        SLAPI_LOG_NO_OPID,
        "testentry_unscramble in test-entry plug-in",
        "Entry data unscrambled.\n"
    );

    return 0;
}

/* Register the plug-in with the server.                          */
#ifdef _WIN32
__declspec(dllexport)
#endif
int
testentry_init(Slapi_PBlock *pb)
{
    int rc = 0;                        /* 0 means success         */
    rc |= slapi_pblock_set(            /* Plug-in API version     */
        pb,
        SLAPI_PLUGIN_VERSION,
        SLAPI_PLUGIN_CURRENT_VERSION
    );
    rc |= slapi_pblock_set(            /* Plug-in description     */
        pb,
        SLAPI_PLUGIN_DESCRIPTION,
        (void *) &entrypdesc
    );
    rc |= slapi_pblock_set(            /* Entry store function    */
        pb,
        SLAPI_PLUGIN_ENTRY_STORE_FUNC,
        (void *) testentry_scramble
    );
    rc |= slapi_pblock_set(            /* Entry fetch function    */
        pb,
        SLAPI_PLUGIN_ENTRY_FETCH_FUNC,
        (void *) testentry_unscramble
    );
    return rc;
}
