
/******************************************************************************
**
**  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.
**
******************************************************************************/

/*****************************************************************************
**
**  File:    md_filter.c
**  Date:    September 17, 2003
**
**  Author:  Brian Wotring
**  Purpose: handle notification filter operations.
**
******************************************************************************/


#include "libosiris.h"
#include "libosirism.h"
#include "libosirisdb.h"
#include "libosirisctl.h"
#include "libfileapi.h"

#include "md_hosts.h"
#include "md_log.h"
#include "md_config.h"
#include "md_compare.h"
#include "md_auth.h"
#include "md_filter.h"

#include "common.h"
#include "logging.h"

#ifdef HAVE_REGEX_H
#include <regex.h>
#endif


extern char notify_filter_db_path[MAX_PATH_LENGTH];

osi_bool create_notify_filter_db( const char *filter_db_path )
{
    int result;
    OSI_DB db;

    if( filter_db_path == NULL )
    {
        return FALSE;
    }

    memset( &db, 0, sizeof( OSI_DB ) );
    osi_strlcpy( db.path, filter_db_path, sizeof( db.path ) );

    result = osi_db_create( &db );

    if( result != OSI_DB_OK )
    {
        return FALSE;
    }

    return TRUE;
}


osi_bool changes_are_filtered( OSI_DB *filter_db, char *host,
                               unsigned int file_attr, char *path )
{
    int result;
    int result_size;

    osi_bool filtered = FALSE;
    OSI_NOTIFY_FILTER filter;

    unsigned int filter_attr;
    unsigned char buffer[sizeof(OSI_NOTIFY_FILTER)];

    if( ( filter_db == NULL ) || ( host == NULL ) || ( path == NULL ) )
    {
        return filtered;
    } 

    /* go through the filter database. check the least intensive    */
    /* match first, the attribute mask.  Then, check the host, then */
    /* the path.                                                    */

    result = osi_db_get_first_record( filter_db, buffer, sizeof( buffer ),
                                      &result_size );

    if( result != OSI_DB_OK )
    {
        return filtered;
    }

    while( result == OSI_DB_OK )
    {
        unpack_notify_filter( &filter, buffer, sizeof( buffer ) );
        unwrap_notify_filter( &filter );

        /* if we are an exclude rule, we swap the bits and do the same */
        /* as an include-only rule.                                    */

        filter_attr = (int)filter.mask;

        if( filter.type == NOTIFY_FILTER_TYPE_EXCLUDE )
        {
            filter_attr = (unsigned int)(~filter_attr);    
        }

        /* include only list, if we don't have the attribute, go to */
        /* the next filter.                                         */

        if( filter_attr & file_attr )
        {
            goto next_filter;
        }

        /* host doesn't match. */

#ifdef HAVE_REGEX_H
        if( name_regex( host, filter.host ) == FALSE )
#else
        if( strcmp( host, filter.host ) != 0 )
#endif
        {
            goto next_filter;
        }

        /* path doesn't match. */

#ifdef HAVE_REGEX_H
        if(  name_regex( path, filter.path ) == FALSE )
#else
        if( strcmp( path, filter.path ) != 0 )
#endif
        {
            goto next_filter;
        }

        /* we have a match, this change is filtered. */

        log_info( LOG_HIGH, host,
                  "change(s) to [%s] filtered from notifications.", path );

        filtered = TRUE;
        break;

next_filter:
        result = osi_db_get_next_record( filter_db, &filter, sizeof( filter ),
                                         &result_size );
    }
    
    return filtered;
}

osi_bool open_filter_db( OSI_DB *filter_db )
{
    if( filter_db != NULL )
    {
        memset( filter_db, 0, sizeof( OSI_DB ) );

        osi_strlcpy( filter_db->path, notify_filter_db_path,
                     sizeof( filter_db->path ) );

        if( osi_db_open( filter_db, OSI_DB_READ ) == OSI_DB_OK )
        {
            return TRUE;
        }
    }

    return FALSE;
}

osi_bool close_filter_db( OSI_DB *filter_db )
{
    if( filter_db != NULL )
    {
        osi_db_close( filter_db );
        return TRUE;
    }

    return FALSE;
}
