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

 reqextop.c

 This example LDAP client requests an extended operation.  Use
 it with the testextendedop.c server plug-in, which handles an
 extended operation having OID 1.2.3.4.

*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ldap.h"

/* Global variables for client connection information.
 * You may set these here or on the command line.                  */
static char * host     = "localhost";  /* Server hostname          */
static int    port     = 389;          /* Server port              */
static char * bind_DN  = "cn=Directory Manager"; /* DN to bind as  */
static char * bind_pwd = "23skidoo";   /* Password for bind DN     */

/* Check for connection info as command line arguments.            */
int get_user_args(int argc, char ** argv);

int
main(int argc, char ** argv)
{
    /* OID of the extended operation that you are requesting       */
    const char    * oidrequest = "1.2.3.4"; /* Ext op OID          */
    char          * oidresult;         /* OID in reply from server */
    struct berval   valrequest;        /* Request sent             */
    struct berval * valresult;         /* Reply received           */
    LDAP          * ld;                /* Handle to connection     */
    int             version;           /* LDAP version             */

    /* Use default connection arguments unless all four are
     * provided as arguments on the command line.                  */
    if (get_user_args(argc, argv) != 0) return 1; /* Usage error   */

    /* Set up the value that you want to pass to the server        */
    printf("Setting up value to pass to server...\n");
    valrequest.bv_val = "My Value";
    valrequest.bv_len = strlen("My Value");

    /* Get a handle to an LDAP connection                          */
    printf("Getting the handle to the LDAP connection...\n");
    if ((ld = ldap_init(host, port)) == NULL) {
        perror("ldap_init");
        ldap_unbind(ld);
        return 1;
    }

    /* Set the LDAP protocol version supported by the client
       to 3. (By default, this is set to 2. Extended operations
       are part of version 3 of the LDAP protocol.)                */
    printf("Resetting version to 3.0...\n");
    version = LDAP_VERSION3;
    ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);

    /* Authenticate to the directory as the Directory Manager      */
    printf("Binding to the directory...\n");
    if (ldap_simple_bind_s(ld, bind_DN, bind_pwd) != LDAP_SUCCESS) {
        ldap_perror(ld, "ldap_simple_bind_s");
        ldap_unbind(ld);
        return 1;
    }

    /* Initiate the extended operation                             */
    printf( "Initiating the extended operation...\n" );
    if (ldap_extended_operation_s(
            ld,
            oidrequest,
            &valrequest,
            NULL,
            NULL,
            &oidresult,
            &valresult
        ) != LDAP_SUCCESS) {
        ldap_perror(ld, "ldap_extended_operation_s failed: ");
        ldap_unbind(ld);
        return 1;
    } 

    /* Get OID and value from result returned by server.           */
    printf("Operation successful.\n");
    if (oidresult != NULL){
        printf("\tOID returned: %s\n", oidresult);
    }
    else {
        printf("\tNo OID returned\n");
    }
    if (valresult->bv_val != NULL){
    	printf("\tValue returned: %s\n", valresult->bv_val);
    }
    else {
    	printf("\tNo value returned\n");
    }

    /* Disconnect from the server.                                 */
    ldap_unbind(ld);
    return 0;
}

/* Check for connection info as command line arguments.            */
int
get_user_args(int argc, char ** argv)
{
    int    errflag   = 0;              /* Any unrecognized args?   */  
    int    i;
    char * option_id = NULL;           /* Which arg is this?       */

    /* Try to use the any arguments provided by the user. If some
     * of the defaults can be reused, so much the better. So keep
     * interpreting arguments until it is no longer possible,
     * displaying a usage message when not all arguments are used,
     * and displaying the list of the arguments recorded.          */
    for (i = 1; i+1 <= argc; i += 2) {
        option_id = argv[i];
        if (argv[i][0] == '-') {
            if ((strcmp(option_id, "-h") == 0) && (i+1 < argc)) {
                host = argv[i+1];
            } else if ((strcmp(option_id, "-p") == 0) && (i+1 < argc)) {
                port = atoi(argv[i+1]);
            } else if ((strcmp(option_id, "-D") == 0) && (i+1 < argc)) {
                bind_DN = argv[i+1];
            } else if ((strcmp(option_id, "-w") == 0) && (i+1 < argc)) {
                bind_pwd = argv[i+1];
            } else {
                errflag = 1;
                fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
            }
        }
    }

    if (errflag) {
        fprintf(stderr, "USAGE:\n");
        fprintf(
            stderr,
            "\t %s -h host -p port -D \"bind DN\" -w password\n",
            argv[0]
        );
        return 1;
    } 

    fprintf(stderr, "Using the following connection info:\n");
    fprintf(stderr, "\thost:    %s\n\tport:    %d\n"
                    "\tbind DN: %s\n\tpwd:     %s\n",
            host, port, bind_DN, bind_pwd);

    return 0;
}
