 
/*****************************************************************************
**
**  Copyright (C) 2002  - the shmoo group -
**
**  This program is free software; you can redistribute it and/or
**  modify it, however, you cannot sell it.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
**  You should have received a copy of the license attached to the
**  use of this software.  If not, visit www.shmoo.com/osiris for
**  details.
**
******************************************************************************/

/*****************************************************************************
**
**    The Shmoo Group (TSG)
**
**    File:      osirisctl.c
**    Author:    Brian Wotring
**
**    Date:      May 22, 2002
**    Project:   osiris
**
******************************************************************************/

#include "libosiris.h"
#include "libosirism.h"

#include "osirisctl.h"


void wrap_control_request( CONTROL_REQUEST *request )
{
    if( request != NULL )
    {
         request->command = HTONLL( request->command );
    }
}

void unwrap_control_request( CONTROL_REQUEST *request )
{
    if( request != NULL )
    {
         request->command = NTOHLL( request->command );
    }
}

void wrap_hello_response( OSI_HELLO_RESPONSE *hello )
{
    if( hello != NULL )
    {
        /* nothing but char arrays so far. */
    }
}

void unwrap_hello_response( OSI_HELLO_RESPONSE *hello )
{
    if( hello != NULL )
    {
        /* nothing but char arrays so far. */
    }
}

SSL * ctl_connect( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    SSL *ssl;

    OSI_AUTH_CONTEXT auth_context;
    memset( &auth_context, 0, sizeof( auth_context ) );

    if( context == NULL )
    {
        return NULL;
    }

    /* for auths, we only need send our user and pass. */

    osi_strlcpy( auth_context.auth_user, context->username,
                 sizeof( auth_context.auth_user ) );

    osi_strlcpy( auth_context.auth_pass, context->password,
                 sizeof( auth_context.auth_pass ) );

    context->ssl = NULL;
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &auth_context,
                                  sizeof( auth_context ), 0 );

    /* send request message to management application. */

    ssl = osi_ssl_connect_to_host_on_port( context->mhost,
                                           MANAGEMENT_CONTROL_PORT,
                                           context->ssl_context, TRUE );

    if( ssl != NULL )
    {
        client_socket = SSL_get_fd( ssl );
        result = osi_ssl_write_message( &req, ssl );
    }

    else
    {
        context->error.type = OSI_ERROR_UNABLE_TO_CONNECT;
        return NULL;
    }

    if( osi_ssl_read_message( &res, ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_error;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        context->ssl = ssl;
        goto exit_gracefully;
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );

        goto exit_error;
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
        goto exit_error;
    }

exit_error:

    client_socket = SSL_get_fd( ssl );
    osi_close_socket( client_socket );
    osi_ssl_destroy( &ssl );

    return NULL;

exit_gracefully:

    return ssl;
}

osi_bool ctl_disconnect( CTL_CONTEXT *context )
{
    int client_socket;

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    client_socket = SSL_get_fd( context->ssl );

    SSL_shutdown( context->ssl );
    shutdown( client_socket, 2 );
    osi_ssl_destroy( &(context->ssl) );

    return TRUE;
}

OSI_HELLO_RESPONSE * ctl_send_hello( CTL_CONTEXT *context )
{
    int result;
    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    OSI_HELLO_RESPONSE *hello_response = NULL;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_HELLO;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    result = osi_ssl_write_message( &req, context->ssl );
        
    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        return NULL;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_CONTROL_DATA )
    {
        OSI_HELLO_RESPONSE *response;
        response = MESSAGE_TO_TYPE( &res, OSI_HELLO_RESPONSE * );

        if( response != NULL )
        {
            hello_response = osi_malloc( sizeof( OSI_HELLO_RESPONSE ) );
            memcpy( hello_response, response, sizeof( OSI_HELLO_RESPONSE ) );
        }
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

    return hello_response;
}

osi_bool ctl_set_user( CTL_CONTEXT *context )
{
    int result;

    osi_bool password_set = FALSE;
    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    OSI_AUTH_CONTEXT auth;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    osi_strlcpy( auth.auth_user, context->username, sizeof( auth.auth_user ) );
    osi_strlcpy( auth.auth_pass, context->password, sizeof( auth.auth_pass ) );

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_SET_USER;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    /* request was received, now send the auth context.  the */
    /* management host is expecting it.                      */

    if( result == MESSAGE_OK )
    {
        initialize_message( &req, MESSAGE_TYPE_CONTROL_DATA_LAST );
    
        message_set_payload( &req, &auth, sizeof( auth ), 1 );        
        result = osi_ssl_write_message( &req, context->ssl );

        if( result != MESSAGE_OK )
        {
            context->error.type = OSI_ERROR_SENDING_MESSAGE;

            osi_strlcpy( context->error.message,
                         "unable to send auth information.",
                         sizeof( context->error.message ) );

            goto exit_gracefully;
        }
    }

    else
    {
        context->error.type = OSI_ERROR_UNABLE_TO_CONNECT;
        goto exit_gracefully;
    }

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        password_set = TRUE;
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

exit_gracefully:

    return password_set;
}

osi_bool ctl_delete_user( CTL_CONTEXT *context )
{
    int result;

    osi_bool deleted = FALSE;
    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return  FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_DELETE_USER;

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    result = osi_ssl_write_message( &req, context->ssl );

    /* read response, should just be a success message. */

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        deleted = TRUE;
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

exit_gracefully:

    return deleted;
}


osi_list ctl_get_user_list( CTL_CONTEXT *context )
{
    int result;
    int client_socket;

    MESSAGE req;
    MESSAGE res;

    osi_list users = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_USERS;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    client_socket = SSL_get_fd( context->ssl );
    osi_set_socket_non_blocking( client_socket );

    osi_ssl_write_message( &req, context->ssl );

    /* create our list for the hosts. */

    users = list_new();

    /* receive host messages. */

    for(;;)
    {
        int sresult;
        OSI_AUTH_CONTEXT *auth;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( users,(void (*)(void *))&osi_free );
                users = NULL;

                break;
            }

            auth = MESSAGE_TO_TYPE( &res, OSI_AUTH_CONTEXT * );

            if( auth != NULL )
            {
                 OSI_AUTH_CONTEXT *a = osi_malloc( sizeof( OSI_AUTH_CONTEXT ) );
                 memcpy( a, auth, sizeof( OSI_AUTH_CONTEXT ) );
                 list_add( users, a );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                 context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( users, (void (*)(void *))&osi_free );
            users = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return users;
}



OSI_STATUS * ctl_get_status( CTL_CONTEXT *context )
{
    int result;

    osi_uint16 type;
    OSI_STATUS *status = NULL;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return status;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_STATUS;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );

    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );
    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }
    
    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_STATUS_RESPONSE )
    {
        OSI_STATUS *s = MESSAGE_TO_TYPE( &res, OSI_STATUS * );
        unwrap_status( s );

        status = osi_malloc( sizeof( OSI_STATUS ) );
        memcpy( status, s, sizeof( OSI_STATUS ) );
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

exit_gracefully:

    return status;
}


OSI_HOST_BRIEF * ctl_get_host( CTL_CONTEXT *context )
{
    int result;

    osi_uint16 type;
    OSI_HOST_BRIEF *host_brief = NULL;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_HOST_BRIEF;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
    {
        OSI_HOST_BRIEF *h = MESSAGE_TO_TYPE( &res, OSI_HOST_BRIEF * );
        unwrap_host_brief( h );

        host_brief = osi_malloc( sizeof( OSI_HOST_BRIEF ) );
        memcpy( host_brief, h, sizeof( OSI_HOST_BRIEF ) );
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;
    
        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

exit_gracefully:

    return host_brief;
}

string_list * ctl_get_log( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    fd_set read_set;
    osi_uint16 type;

    string_list *log_data = NULL;
    CONTROL_REQUEST control_request;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_LOG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    client_socket = SSL_get_fd( context->ssl );
    osi_set_socket_non_blocking( client_socket );

    log_data = string_list_new();

    /* receive config data messages. */

    for(;;)
    {
        char *line;
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                break;
            }

            /* not an error, we get the log data from the message. */

            line = MESSAGE_TO_TYPE( &res, char * );

            if( line != NULL )
            {
                string_list_add_item( log_data, line );
            }

            /* check the type, if it is the last message, we bail */
            /* here; we have received all log data.               */

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        /* error reading next message. */

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;
                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            break;
        }

    } /* end for loop. */

exit_gracefully:

    return log_data;
}


OSI_DATABASE_BRIEF * ctl_get_db_results( CTL_CONTEXT *context )
{
    int result;

    osi_uint16 type;
    OSI_DATABASE_BRIEF *database_brief = NULL;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_DATABASE_BRIEF;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
    {
        OSI_DATABASE_BRIEF *brief = MESSAGE_TO_TYPE(&res,OSI_DATABASE_BRIEF * );
        unwrap_database_brief( brief );

        database_brief = osi_malloc( sizeof( OSI_DATABASE_BRIEF ) );
        memcpy( database_brief, brief, sizeof( OSI_DATABASE_BRIEF ) );
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
    }

exit_gracefully:

    return database_brief;
}


osi_list ctl_get_host_brief_list( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    osi_list hosts = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_HOSTS;

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    client_socket = SSL_get_fd( context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* create our list for the hosts. */

    hosts = list_new();

    /* receive host messages. */

    for(;;)
    {
        OSI_HOST_BRIEF *host_data;
        int sresult;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( hosts,(void (*)(void *))&osi_free );
                hosts = NULL;

                break;
            }

            host_data = MESSAGE_TO_TYPE( &res, OSI_HOST_BRIEF * );

           if( host_data != NULL )
           {
                OSI_HOST_BRIEF *host = osi_malloc( sizeof( OSI_HOST_BRIEF ) );

                unwrap_host_brief( host_data );
                memcpy( host, host_data, sizeof( OSI_HOST_BRIEF ) );

                list_add( hosts, host );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                 context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( hosts, (void (*)(void *))&osi_free );
            hosts = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return hosts;
}

osi_list ctl_get_config_brief_list( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    osi_list configs = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_CONFIGS;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* create our list for the hosts. */

    configs = list_new();

    /* receive host messages. */

    for(;;)
    {
        int sresult;
        OSI_CONFIG_BRIEF *config_data;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( configs,
                                            (void (*)(void *))&osi_free );

                configs = NULL;
                break;
            }

            config_data = MESSAGE_TO_TYPE( &res, OSI_CONFIG_BRIEF * );

            if( config_data != NULL )
            {
                OSI_CONFIG_BRIEF *config = osi_malloc(
                                            sizeof( OSI_CONFIG_BRIEF ) );

                unwrap_config_brief( config_data );
                memcpy( config, config_data, sizeof( OSI_CONFIG_BRIEF ) );

                list_add( configs, config );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );
                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( configs, (void (*)(void *))&osi_free );
            configs = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return configs;
}

osi_bool ctl_send_notify_test( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_SEND_NOTIFY_TEST;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    osi_ssl_write_message( &req, context->ssl );

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) == MESSAGE_OK )
    {
        osi_uint16 type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_SUCCESS )
        {
            status = TRUE;
        }

        else if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );
            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );
        }
    }

    else
    {
        char *error = osi_get_name_for_error( result );
        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

    return status;
}



osi_list ctl_get_database_brief_list( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    osi_list databases = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_DATABASES;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* create our list for the databases. */

    databases = list_new();

    /* receive database messages. */

    for(;;)
    {
        int sresult;
        OSI_DATABASE_BRIEF *database_data;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the db list and bail. */

                list_destroy_with_function( databases,
                                            (void (*)(void *))&osi_free );
                databases = NULL;
                break;
            }

            database_data = MESSAGE_TO_TYPE( &res, OSI_DATABASE_BRIEF * );

            if( database_data != NULL )
            {
                OSI_DATABASE_BRIEF *database = osi_malloc( 
                                            sizeof( OSI_DATABASE_BRIEF ) );

                unwrap_database_brief( database_data );
                memcpy( database, database_data, sizeof( OSI_DATABASE_BRIEF ) );

                list_add( databases, database );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );
                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the db list and bail. */

            list_destroy_with_function( databases,(void (*)(void *))&osi_free );
            databases = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return databases;
}

osi_list ctl_get_log_brief_list( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    osi_list logs = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_LOGS;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* create our list for the hosts. */

    logs = list_new();

    /* receive host messages. */

    for(;;)
    {
        int sresult;
        OSI_LOG_BRIEF *log_data;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( logs, (void (*)(void *))&osi_free );
                logs = NULL;

                break;
            }

            log_data = MESSAGE_TO_TYPE( &res, OSI_LOG_BRIEF * );

            if( log_data != NULL )
            {
                OSI_LOG_BRIEF *log = osi_malloc( sizeof(OSI_LOG_BRIEF) );

                unwrap_log_brief( log_data );
                memcpy( log, log_data, sizeof( OSI_LOG_BRIEF ) );

                list_add( logs, log );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );
                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( logs, (void (*)(void *))&osi_free );
            logs = NULL;

            break;
        }

    } /* end for loop. */

exit_gracefully:

    return logs;
}

osi_bool ctl_save_notify_filters( CTL_CONTEXT *context )
{
    int result;
    int sequence = 0;

    osi_list temp;
    osi_bool status = FALSE;

    OSI_NOTIFY_FILTER *filter;

    osi_uint16 type;
    int number_of_filters;

    CONTROL_REQUEST control_request;

    MESSAGE req;
    MESSAGE res;

    if( ( context == NULL ) || ( context->ssl == NULL ) ||
        ( context->notify_filters == NULL ) )
    {
        context->error.type = OSI_ERROR_NULL_ARGUMENT;
        context->error.message[0] = '\0';
        
        return FALSE;
    }

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );
    control_request.command = CONTROL_COMMAND_SAVE_NOTIFY_FILTERS;

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );
    number_of_filters = list_get_size( context->notify_filters );

    /* in case we don't have any filters, send an empty last message. */

    if( number_of_filters == 0 )
    {
        MESSAGE message;
        
        initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
        osi_ssl_write_message( &message, context->ssl );

        goto read_response;
    }

    temp = list_get_first_node( context->notify_filters );

    while( temp )
    {
        OSI_NOTIFY_FILTER f;
        MESSAGE message;
        unsigned char buffer[sizeof(OSI_NOTIFY_FILTER)];

        filter = (OSI_NOTIFY_FILTER *)temp->data;
        memset( &f, 0, sizeof( f ) );

        if( filter != NULL )
        {
            unsigned int size;

            /* populate the filter structure. */

            osi_strlcpy( f.host, filter->host, sizeof( f.host ) );
            osi_strlcpy( f.path, filter->path, sizeof( f.path ) );

            f.type = filter->type;
            f.mask = filter->mask;
            
            /* wrap and pack this filter structure. */

            wrap_notify_filter( &f );
            size = pack_notify_filter( &f, buffer, sizeof( buffer ) );

            /* send this out in a message, if we are sending the */
            /* last message, put it in a CONTROL_DATA_LAST type. */

            if( ( sequence + 1 ) < number_of_filters )
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA );
            }

            else
            {
                initialize_message( &message, MESSAGE_TYPE_CONTROL_DATA_LAST );
            }

            result = message_set_payload( &message, buffer, size, sequence );

            if( result == MESSAGE_OK )
            {
                osi_ssl_write_message( &message, context->ssl );
            }
        }

        temp = list_get_next_node( temp );
        sequence++;
    }

read_response:

    /* now read the response from the managment host after */
    /* sending the config.                                 */

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}


osi_list ctl_get_notify_filters_list( CTL_CONTEXT *context )
{
    int result;
    int client_socket;

    MESSAGE req;
    MESSAGE res;

    osi_list filters = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_LIST_NOTIFY_FILTERS;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    client_socket = SSL_get_fd( context->ssl );
    osi_set_socket_non_blocking( client_socket );
    osi_ssl_write_message( &req, context->ssl );

    /* create our list for the hosts. */

    filters = list_new();

    /* receive host messages. */

    for(;;)
    {
        int sresult;
        OSI_NOTIFY_FILTER *filter;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( filters,
                                            (void(*)(void *))&osi_free );
                filters = NULL;

                break;
            }

            filter = MESSAGE_TO_TYPE( &res, OSI_NOTIFY_FILTER * );

            if( filter != NULL )
            {
                osi_uint16 size;
                OSI_NOTIFY_FILTER *f = osi_malloc( sizeof(OSI_NOTIFY_FILTER) );

                size = GET_MESSAGE_LENGTH( ( (MESSAGE *)&res ) );

                /* unpack, then unwrap notify filter. */

                unpack_notify_filter( f, (unsigned char *)filter, (int)size );
                unwrap_notify_filter( f );

                list_add( filters, f );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                 context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( filters, (void (*)(void *))&osi_free );
            filters = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return filters;
}

osi_list ctl_get_database_errors( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    osi_list errors = NULL;

    fd_set read_set;
    osi_uint16 type;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_DATABASE_ERRORS;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* create our list for the hosts. */

    errors = list_new();

    /* receive host messages. */

    for(;;)
    {
        int sresult;
        unsigned char *error_data;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                /* destroy the config list and bail. */

                list_destroy_with_function( errors,
                                           (void (*)(void *))&osi_free );

                errors = NULL;
                break;
            }

            error_data = MESSAGE_TO_TYPE( &res, unsigned char * );

            if( error_data != NULL )
            {
                int length = (int)GET_MESSAGE_LENGTH( ((MESSAGE *)&res) );
                OSI_ERROR *error = osi_malloc( sizeof( OSI_ERROR ) );

                unpack_error( error, error_data, length );
                unwrap_error( error );

                list_add( errors, error );
            }

            if( type == MESSAGE_TYPE_CONTROL_DATA_LAST )
            {
                goto exit_gracefully;
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );
                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            /* destroy the config list and bail. */

            list_destroy_with_function( errors, (void (*)(void *))&osi_free );
            errors = NULL;

            break;
        }

    } /* end for loop */

exit_gracefully:

    return errors;
}


osi_bool ctl_push_config( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;

    int client_socket;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_PUSH_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );
        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}

osi_bool ctl_import_default_config( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;

    int client_socket;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_IMPORT_DEFAULT_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );
        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}

osi_bool ctl_set_base_db( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_SET_BASE_DATABASE;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );
        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}

osi_bool ctl_unset_base_db( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_UNSET_BASE_DATABASE;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );
        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}


osi_bool ctl_import_config( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;

    int client_socket;
    int result;

    int index;
    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    string_list *lines;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->config == NULL ) ||
        ( context->ssl == NULL ) )
    {
        context->error.type = OSI_ERROR_UNKNOWN;
        return FALSE;
    }

    lines = context->config->data;

    if( lines == NULL )
    {
        context->error.type = OSI_ERROR_CONFIG_IS_EMPTY;
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_IMPORT_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );

    initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA_FIRST );

    result = message_set_payload( &req, lines->list[0],
                                  strlen( lines->list[0] ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &req, context->ssl );
    }

    for( index = 1; (unsigned int)index < lines->size; index++ )
    {
        if( (unsigned int)( index + 1 ) != lines->size )
        {
            initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA );
        }

        else
        {
            initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA_LAST );
        }

        result = message_set_payload( &req, lines->list[index],
                                      strlen( lines->list[index] ), index );

        if( result == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &req, context->ssl );
        }

        else
        {
            context->error.type = OSI_ERROR_SETTING_MESSAGE_PAYLOAD;
            goto exit_gracefully;
        }
    }

    /* now read the response from the managment host after */
    /* sending the config.                                 */

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}

osi_bool ctl_start_scan( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_START_SCAN;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) == MESSAGE_OK )
    {
        type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_SUCCESS )
        {
            status = TRUE;
        }

        else if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );
            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );
        }

        else
        {
            context->error.type = OSI_ERROR_INVALID_RESPONSE;
        }
    }

    else
    {
        char *error = osi_get_name_for_error( result );
        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

    return status;
}

osi_bool ctl_stop_scan( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_STOP_SCAN;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) == MESSAGE_OK )
    {
        type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_SUCCESS )
        {
            status = TRUE;
        }

        else if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );

            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );
        }

        else
        {
            context->error.type = OSI_ERROR_INVALID_RESPONSE;
        }
    }

    else
    {
        char *error = osi_get_name_for_error( result );

        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

    return status;
}

osi_bool ctl_new_host( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_NEW_HOST;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    if( context->host_brief == NULL )
    {
        context->error.type = OSI_ERROR_NO_HOST_SPECIFIED;
        return FALSE;
    }

    message_set_payload( &req, &control_request,
                         sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    if( result != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_SENDING_MESSAGE;
        return FALSE;
    }

    /* now send the host brief, the management host is waiting for it. */

    wrap_host_brief( context->host_brief );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_DATA_LAST );

    message_set_payload( &req, context->host_brief,
                         sizeof( (*(context->host_brief)) ), 1 );

    result = osi_ssl_write_message( &req, context->ssl );

    if( result != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_SENDING_MESSAGE;
        return FALSE;
    }

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_INVALID_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    else if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

    else
    {
        char *error = osi_get_name_for_error( result );
        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}


osi_bool ctl_edit_host_brief( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_EDIT_HOST_BRIEF;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    if( context->host_brief == NULL )
    {
        context->error.type = OSI_ERROR_NO_HOST_SPECIFIED;
        return FALSE;
    }

    message_set_payload( &req, &control_request,
                         sizeof( control_request ), 0 );

    /* send request message to management application. */

    result = osi_ssl_write_message( &req, context->ssl );

    if( result != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_SENDING_MESSAGE;
        return FALSE;
    }

    /* now send the host brief, the management host is waiting for it. */

    wrap_host_brief( context->host_brief );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_DATA_LAST );

    message_set_payload( &req, context->host_brief,
                         sizeof( (*(context->host_brief)) ), 1 );

    result = osi_ssl_write_message( &req, context->ssl );

    if( result != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_SENDING_MESSAGE;
        return FALSE;
    }

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) == MESSAGE_OK )
    {
        type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_SUCCESS )
        {
            status = TRUE;
        }

        else if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );

            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );
        }

        else
        {
            context->error.type = OSI_ERROR_INVALID_RESPONSE;
        }
    }

    else
    {
        char *error = osi_get_name_for_error( result );

        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

    return status;
}

configuration * ctl_get_config( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    fd_set read_set;
    osi_uint16 type;

    configuration *cfg = NULL;
    CONTROL_REQUEST control_request;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* receive config data messages. */

    for(;;)
    {
        int sresult;
        char *line;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                break;
            }

            line = MESSAGE_TO_TYPE( &res, char * );

            if( line != NULL )
            {
                if( type == MESSAGE_TYPE_CONFIG_DATA )
                {
                    osi_config_receive( cfg, line, strlen( line ) );
                    continue;
                }

                else if( type == MESSAGE_TYPE_CONFIG_DATA_FIRST )
                {
                    cfg = osi_config_new();
                    osi_config_receive_first( cfg, line, strlen( line ) );

                    continue;
                }

                else if( type == MESSAGE_TYPE_CONFIG_DATA_LAST )
                {
                    osi_config_receive_last( cfg, line, strlen( line ) );
                    break;
                }

                /* drop all other message types. */
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            break;
        }

    }  /* end for loop. */

    return cfg;
}

OSI_HOST_CONFIG *ctl_get_host_config( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    fd_set read_set;
    osi_uint16 type;

    OSI_HOST_CONFIG *cfg = NULL;
    CONTROL_REQUEST control_request;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_HOST_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* receive config data messages. */

    for(;;)
    {
        int sresult;
        char *line;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( FD_ISSET( client_socket, &read_set ) )
        {
            result = osi_ssl_read_message( &res, context->ssl );

            if( result == MESSAGE_OK )
            {
                type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

                if( type == MESSAGE_TYPE_ERROR )
                {
                    OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                    unwrap_error( error );

                    /* set error in context. */

                    context->error.type = error->type;

                    osi_strlcpy( context->error.message, error->message,
                                 sizeof( context->error.message ) );

                    break;
                }

                line = MESSAGE_TO_TYPE( &res, char * );

                if( line != NULL )
                {
                    if( type == MESSAGE_TYPE_CONFIG_DATA )
                    {
                        osi_host_config_receive( cfg, line, strlen( line ) );
                        continue;
                    }

                    else if( type == MESSAGE_TYPE_CONFIG_DATA_FIRST )
                    {
                        cfg = osi_host_config_new();
                        osi_host_config_receive_first( cfg, line,
                                                       strlen( line ) );

                        continue;
                    }

                    else if( type == MESSAGE_TYPE_CONFIG_DATA_LAST )
                    {
                        osi_host_config_receive_last( cfg, line,
                                                      strlen( line ) );
                        break;
                    }

                    /* drop all other message types. */
                }
            }

            else
            {
                if( result == OSI_ERROR_SOCKET_CLOSED )
                {
                    context->error.type = OSI_ERROR_SOCKET_CLOSED;
                }

                else
                {
                    char *error = osi_get_name_for_error( result );

                    context->error.type = OSI_ERROR_UNKNOWN;

                    osi_strlcpy( context->error.message, error,
                                 sizeof( context->error.message ) );
                }

                break;
            }
        }

    } /* end for loop. */

    return cfg;
}

OSI_MANAGEMENT_CONFIG *ctl_get_management_config( CTL_CONTEXT *context )
{
    int client_socket;
    int result;

    MESSAGE req;
    MESSAGE res;

    fd_set read_set;
    osi_uint16 type;

    OSI_MANAGEMENT_CONFIG *cfg = NULL;
    CONTROL_REQUEST control_request;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return NULL;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_MANAGEMENT_CONFIG;
    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* receive config data messages. */

    for(;;)
    {
        int sresult;
        char *line;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result == MESSAGE_OK )
        {
            type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

            if( type == MESSAGE_TYPE_ERROR )
            {
                OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
                unwrap_error( error );

                /* set error in context. */

                context->error.type = error->type;

                osi_strlcpy( context->error.message, error->message,
                             sizeof( context->error.message ) );

                break;
            }

            line = MESSAGE_TO_TYPE( &res, char * );

            if( line != NULL )
            {
                if( type == MESSAGE_TYPE_CONFIG_DATA )
                {
                    osi_management_config_receive( cfg, line, strlen( line ) );
                    continue;
                }

                else if( type == MESSAGE_TYPE_CONFIG_DATA_FIRST )
                {
                    cfg = osi_management_config_new();
                    osi_management_config_receive_first( cfg, line,
                                                         strlen( line ) );

                    continue;
                }

                else if( type == MESSAGE_TYPE_CONFIG_DATA_LAST )
                {
                    osi_management_config_receive_last( cfg, line,
                                                        strlen( line ) );
                    break;
                }

                /* drop all other message types. */
            }
        }

        else
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            break;
        }

    } /* end of for loop. */

    return cfg;
}

osi_bool ctl_save_host_config( CTL_CONTEXT *context )
{
    return FALSE;
}

osi_bool ctl_save_management_config( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;

    int client_socket;
    int result;

    int index;
    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    string_list *lines;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->mhost_config == NULL ) ||
        ( context->ssl == NULL ) )
    {
        context->error.type = OSI_ERROR_UNKNOWN;
        return FALSE;
    }

    lines = context->mhost_config->data;

    if( lines == NULL )
    {
        context->error.type = OSI_ERROR_CONFIG_IS_EMPTY;
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_SAVE_MANAGEMENT_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );

    initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA_FIRST );

    result = message_set_payload( &req, lines->list[0],
                                  strlen( lines->list[0] ), 0 );

    if( result == MESSAGE_OK )
    {
        osi_ssl_write_message( &req, context->ssl );
    }

    for( index = 1; (unsigned int)index < lines->size; index++ )
    {
        if( (unsigned int)( index + 1 ) != lines->size )
        {
            initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA );
        }

        else
        {
            initialize_message( &req, MESSAGE_TYPE_CONFIG_DATA_LAST );
        }

        result = message_set_payload( &req, lines->list[index],
                                      strlen( lines->list[index] ), index );

        if( result == MESSAGE_OK )
        {
            result = osi_ssl_write_message( &req, context->ssl );
        }

        else
        {
            context->error.type = OSI_ERROR_SETTING_MESSAGE_PAYLOAD;
            goto exit_gracefully;
        }
    }

    /* now read the response from the managment host after */
    /* sending the config.                                 */

    if( osi_ssl_read_message( &res, context->ssl ) != MESSAGE_OK )
    {
        context->error.type = OSI_ERROR_NO_RESPONSE;
        goto exit_gracefully;
    }

    type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

    if( type == MESSAGE_TYPE_SUCCESS )
    {
        status = TRUE;
    }

    if( type == MESSAGE_TYPE_ERROR )
    {
        OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
        unwrap_error( error );

        context->error.type = error->type;

        osi_strlcpy( context->error.message, error->message,
                     sizeof( context->error.message ) );
    }

exit_gracefully:

    return status;
}

osi_bool ctl_drop_config( CTL_CONTEXT *context )
{
    osi_bool status = FALSE;
    int result;

    osi_uint16 type;

    MESSAGE req;
    MESSAGE res;

    CONTROL_REQUEST control_request;
    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_DROP_CONFIG;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    osi_ssl_write_message( &req, context->ssl );

    if( ( result = osi_ssl_read_message( &res, context->ssl ) ) == MESSAGE_OK )
    {
        type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_SUCCESS )
        {
            status = TRUE;
        }

        else if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );

            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );
        }

        else
        {
            context->error.type = OSI_ERROR_INVALID_RESPONSE;
        }
    }

    else
    {
        char *error = osi_get_name_for_error( result );

        context->error.type = OSI_ERROR_UNKNOWN;

        osi_strlcpy( context->error.message, error,
                     sizeof( context->error.message ) );
    }

    return status;
}

X509 * ctl_get_peer_certificate( CTL_CONTEXT *context )
{
    SSL *ssl           = NULL;
    X509 *peer         = NULL;

    int connection_socket = 0;

    if( context == NULL )
    {
        return NULL;
    }

    ssl = osi_ssl_connect_to_host_on_port( context->mhost,
                                           MANAGEMENT_CONTROL_PORT,
                                           context->ssl_context, TRUE );

    if( ssl != NULL )
    {
        connection_socket = SSL_get_fd( ssl );
        peer = SSL_get_peer_certificate( ssl );

        SSL_shutdown( ssl );

        osi_close_socket( connection_socket );
        osi_ssl_destroy( &ssl );
    }

    return peer;
}

osi_bool ctl_get_database( CTL_CONTEXT *context )
{
    osi_bool status            = FALSE;
    osi_uint64 db_file_size    = 0;
    long bytes_received        = 0;
    
    int client_socket;
    int result;
    int message_size;
    
    MESSAGE req;
    MESSAGE res;

    fd_set read_set;
    osi_uint16 type;

    FILE *dbfile;
    CONTROL_REQUEST control_request;

    memset( &control_request, 0, sizeof( CONTROL_REQUEST ) );

    if( ( context == NULL ) || ( context->ssl == NULL ) )
    {
        return FALSE;
    }

    if( strlen( context->filename ) == 0 )
    {
        context->error.type = OSI_ERROR_DB_PATH;
        return FALSE;
    }
        
    /* set command and wrap our control request. */

    control_request.command = CONTROL_COMMAND_GET_DATABASE;

    osi_strlcpy( control_request.host, context->host,
                 sizeof( control_request.host ) );

    osi_strlcpy( control_request.buffer, context->buffer,
                 sizeof( control_request.buffer ) );

    wrap_control_request( &control_request );
    initialize_message( &req, MESSAGE_TYPE_CONTROL_REQUEST );

    result = message_set_payload( &req, &control_request,
                                  sizeof( control_request ), 0 );

    /* send request message to management application. */

    client_socket = SSL_get_fd( context->ssl );
    osi_ssl_write_message( &req, context->ssl );
    osi_set_socket_non_blocking( client_socket );

    /* receive database data messages. */

    for(;;)
    {
        int sresult;
        unsigned char *data;

        FD_ZERO( &read_set );
        FD_SET( client_socket, &read_set );

        sresult = select( client_socket + 1, &read_set, NULL, NULL, NULL );

        if( ( sresult < 0 ) && ( errno == EINTR ) )
        {
            continue;
        }

        if( !FD_ISSET( client_socket, &read_set ) )
        {
            continue;
        }

        result = osi_ssl_read_message( &res, context->ssl );

        if( result != MESSAGE_OK )
        {
            if( result == OSI_ERROR_SOCKET_CLOSED )
            {
                context->error.type = OSI_ERROR_SOCKET_CLOSED;
            }

            else
            {
                char *error = osi_get_name_for_error( result );

                context->error.type = OSI_ERROR_UNKNOWN;

                osi_strlcpy( context->error.message, error,
                             sizeof( context->error.message ) );
            }

            break;
        }

        /* process the message. */

        type = GET_MESSAGE_TYPE(((MESSAGE *)&res) );

        if( type == MESSAGE_TYPE_ERROR )
        {
            OSI_ERROR *error = MESSAGE_TO_TYPE( &res, OSI_ERROR * );
            unwrap_error( error );

            /* set error in context. */

            context->error.type = error->type;

            osi_strlcpy( context->error.message, error->message,
                         sizeof( context->error.message ) );

            break;
        }

        data = MESSAGE_TO_TYPE( &res, char * );
        message_size = (int)GET_MESSAGE_LENGTH( ( (MESSAGE *)&res ) );

        if( data != NULL )
        {
            if( type == MESSAGE_TYPE_DB_DATA )
            {
                /* get and store data. */
                            
                if( message_size > 0 )
                {
                    fwrite( res.data, 1, message_size, dbfile );
                    bytes_received += (long)message_size;
                                
                    if( context->db_receive_callback != NULL )
                    {
                        context->db_receive_callback( bytes_received,
                                                     (long)db_file_size );
                    }
                }
                                                
                continue;
            }

            else if( type == MESSAGE_TYPE_DB_DATA_FIRST )
            {
                /* make sure we were given the 64 bit db */
                /* length value.                         */
                            
                if( message_size = sizeof( db_file_size ) )
                {
                    memcpy( &db_file_size, res.data, message_size );
                    db_file_size = NTOHLL( db_file_size );
                }
                          
                /* open the file we are to store this data in. */
                           
                dbfile = osi_fopen( context->filename, "w+",
                                    DB_RETREIVE_FILE_PERMISSIONS );
                            
                if( dbfile == NULL )
                {
                    context->error.type = OSI_ERROR_UNABLE_TO_WRITE_FILE;
                    break;
                }

                continue;
            }

            else if( type == MESSAGE_TYPE_DB_DATA_LAST )
            {
                /* get and store data. */
                               
                if( message_size > 0 )
                {
                    fwrite( res.data, 1, message_size, dbfile );
                    bytes_received += (long)message_size;
                               
                    if( context->db_receive_callback != NULL )
                    {
                        context->db_receive_callback( bytes_received,
                                                      (long)db_file_size );
                    }
                }
                            
                status = TRUE;
                break;
            }

            /* drop all other message types. */
        }

    } /* end for loop. */

    if( dbfile )
    {
        fclose( dbfile );
    }
       
    return status;
}

