// snfCFGmgr.cpp
// Copyright (C) 2006 - 2009 Arm Research Labs, LLC
// See www.armresearch.com for the copyright terms.
//

// See snfCFGmgr.hpp for details.

#include "snfCFGmgr.hpp"
#include <iostream>


//// RangeHandler //////////////////////////////////////////////////////////////

bool RangeHandler::isInBlack(RangePoint& x) {                                   // Find if x is on the black side.
    if(EdgeMap.empty()) {                                                       // If there are no points then
        return false;                                                           // there is no map so there is
    }                                                                           // no side to be on.
                                                                                // If there are points we will need
    set<RangePoint>::iterator iRangePoint;                                      // to examine them.
    iRangePoint = EdgeMap.begin();                                              // What is the first point.

    if(x < (*iRangePoint)) {                                                    // If x is below that then
        return false;                                                           // x is out of range -- false.
    }
    iRangePoint = EdgeMap.end();--iRangePoint;                                  // What is the last range point.
    if(x > (*iRangePoint)) {                                                    // If x is beyond that then
        return false;                                                           // x is out of range -- false.
    }

    // At this point we know our point is in the range of the edge map.
    // So our next task is to find the two points between which we will
    // interpolate our comparative result.

    iRangePoint = EdgeMap.lower_bound(x);                                       // Find the lower point.
    if(x < (*iRangePoint)) --iRangePoint;                                       // If we've overshot, then move back.
    RangePoint LowerBound = (*iRangePoint);                                     // Grab the value at that point.
    iRangePoint = EdgeMap.upper_bound(x);                                       // Find the upper point.
    if(iRangePoint == EdgeMap.end()) --iRangePoint;                             // If we've overshot, then move back.
    RangePoint UpperBound = (*iRangePoint);                                     // Grab the value at that point.

    // So then, where is x in [Lower, Upper]
    // First we check the obvious matching values. Then if those fail we will
    // interpolate between the two points.
    double ComparativeProbability;                                              // This value will map the edge.

    if(x == LowerBound) {                                                       // If we match the lower bound then
        ComparativeProbability = LowerBound.Probability;                        // that is the Probability we compare.
    } else
    if(x == UpperBound) {                                                       // If we match the upper bound then
        ComparativeProbability = UpperBound.Probability;                        // that is the Probability we compare.
    } else {                                                                    // For in-between we interpolate.
        double ULDifference = UpperBound.Confidence - LowerBound.Confidence;    // First, find the difference.
        double Incursion = x.Confidence - LowerBound.Confidence;                // How far does x go past L to U?
        double Ratio = Incursion / ULDifference;                                // Express that as a ratio.
        ComparativeProbability =                                                // Interpolate the Probability using
          (((1-Ratio) * LowerBound.Probability) +                               // a weighted average of the lower and
          (Ratio * UpperBound.Probability));                                    // upper bound values using the Ratio
    }

    // Now compare x to the interpolated edge.

    return (x.Probability >= ComparativeProbability);                           // True if on or right of the edge.
}

bool RangeHandler::isInWhite(RangePoint& x) {
    if(EdgeMap.empty()) {                                                       // If there are no points then
        return false;                                                           // there is no map so there is
    }                                                                           // no side to be on.
                                                                                // If ther are points then we
    set<RangePoint>::iterator iRangePoint;                                      // need to examine them.
    iRangePoint = EdgeMap.begin();                                              // What is the first point.

    if(x < (*iRangePoint)) {                                                    // If x is below that then
        return false;                                                           // x is out of range -- false.
    }
    iRangePoint = EdgeMap.end();--iRangePoint;                                  // What is the last range point.
    if(x > (*iRangePoint)) {                                                    // If x is beyond that then
        return false;                                                           // x is out of range -- false.
    }

    // At this point we know our point is in the range of the edge map.
    // So our next task is to find the two points between which we will
    // interpolate our comparative result.

    iRangePoint = EdgeMap.lower_bound(x);                                       // Find the lower point.
    if(x < (*iRangePoint)) --iRangePoint;                                       // If we've overshot, then move back.
    RangePoint LowerBound = (*iRangePoint);                                     // Grab the value at that point.
    iRangePoint = EdgeMap.upper_bound(x);                                       // Find the upper point.
    if(iRangePoint == EdgeMap.end()) --iRangePoint;                             // If we've overshot, then move back.
    RangePoint UpperBound = (*iRangePoint);                                     // Grab the value at that point.

    // So then, where is x in [Lower, Upper]
    // First we check the obvious matching values. Then if those fail we will
    // interpolate between the two points.
    double ComparativeProbability;                                              // This value will map the edge.

    if(x == LowerBound) {                                                       // If we match the lower bound then
        ComparativeProbability = LowerBound.Probability;                        // that is the Probability we compare.
    } else
    if(x == UpperBound) {                                                       // If we match the upper bound then
        ComparativeProbability = UpperBound.Probability;                        // that is the Probability we compare.
    } else {                                                                    // For in-between we interpolate.
        double ULDifference = UpperBound.Confidence - LowerBound.Confidence;    // First, find the difference.
        double Incursion = x.Confidence - LowerBound.Confidence;                // How far does x go past L to U?
        double Ratio = Incursion / ULDifference;                                // Express that as a ratio.
        ComparativeProbability =                                                // Interpolate the Probability using
          (((1-Ratio) * LowerBound.Probability) +                               // a weighted average of the lower and
          (Ratio * UpperBound.Probability));                                    // upper bound values using the Ratio
    }

    // Now compare x to the interpolated edge.

    return (x.Probability <= ComparativeProbability);                           // True if on or left of the edge.
}

//// snfCFGData ////////////////////////////////////////////////////////////////

snfCFGData::snfCFGData() :                                                      // Constructor. No init list because the
  MyCFGReader("snf") {                                                          // interpreter will set the defaults.

    WhiteRangeInitializer.setTarget(WhiteRangeHandler);                         // However, we do need to link up our
    BlackRangeInitializer.setTarget(BlackRangeHandler);                         // Initialization configurators with our
    CautionRangeInitializer.setTarget(CautionRangeHandler);                     // Handlers.
    RulePanicInitializer.setTarget(RulePanicHandler);
    XHDRSymbolHeadersInitializer.setTarget(XHDRSymbolHeaders);
    HeaderDirectivesInitializer.setTarget(HeaderDirectivesHandler);
    HDSourceHeaderInitializer.setTarget(HeaderDirectivesHandler);
    HDDrilldownInitializer.setTarget(HeaderDirectivesHandler);
    HDBypassHeaderInitializer.setTarget(HeaderDirectivesHandler);
    HDWhiteHeaderInitializer.setTarget(HeaderDirectivesHandler);
    TrainingBypassRuleInitializer.setTarget(TrainingBypassRuleHandler);
    TrainingWhiteRuleInitializer.setTarget(TrainingWhiteRuleHandler);

    MyCFGReader                                                                 // Building our interpreter.
        .Element("node")
            .Attribute("identity", node_identity)
            .Attribute("licenseid", node_licenseid)
            .Attribute("authentication", node_authentication)
            .Element("paths")
                .Element("workspace")
                    .Attribute("path", paths_workspace_path)
                .End("workspace")
                .Element("rulebase")
                    .Attribute("path", paths_rulebase_path)
                .End("rulebase")
                .Element("log")
                    .Attribute("path", paths_log_path)
                .End("log")
            .End("paths")
            .Element("logs")
                .Element("rotation")
                    .Attribute("localtime", Logs_Rotation_LocalTime_OnOff, false)
                        .Mnemonic("yes", "true")
                        .Mnemonic("no", "false")
                .End("rotation")
                .Element("status")
                    .Element("second")
                        .Attribute("log", Status_SecondReport_Log_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                        .Attribute("append", Status_SecondReport_Append_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                    .End("second")
                    .Element("minute")
                        .Attribute("log", Status_MinuteReport_Log_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                        .Attribute("append", Status_MinuteReport_Append_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                    .End("minute")
                    .Element("hour")
                        .Attribute("log", Status_HourReport_Log_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                        .Attribute("append", Status_HourReport_Append_OnOff, false)
                            .Mnemonic("yes", "true")
                            .Mnemonic("no", "false")
                    .End("hour")
                .End("status")
                .Element("scan")
                    .Element("identifier")
                        .Attribute("force-message-id", Scan_Identifier_Force_Message_Id, false)
                    .End("identifier")
                    .Element("classic")
                        .Attribute("mode", Scan_Classic_Mode, LogOutputMode_None)
                            .Mnemonic("none", "0")
                            .Mnemonic("api", "1")
                            .Mnemonic("file", "2")
                        .Attribute("rotate", Scan_Classic_Rotate, false)
                        .Attribute("matches", Scan_Classic_Matches, ScanLogMatches_None)
                            .Mnemonic("none", "0")
                            .Mnemonic("unique", "1")
                            .Mnemonic("all","2")
                    .End("classic")
                    .Element("xml")
                        .Attribute("mode", Scan_XML_Mode, LogOutputMode_None)
                            .Mnemonic("none", "0")
                            .Mnemonic("api", "1")
                            .Mnemonic("file", "2")
                        .Attribute("rotate", Scan_XML_Rotate, false)
                        .Attribute("matches", Scan_XML_Matches, ScanLogMatches_None)
                            .Mnemonic("none", "0")
                            .Mnemonic("unique", "1")
                            .Mnemonic("all","2")
                        .Attribute("performance", Scan_XML_Performance, false)
                        .Attribute("gbudb", Scan_XML_GBUdb, false)
                    .End("xml")
                    .Element("xheaders")
                        .atStartCall(XHDRSymbolHeadersInitializer)
                        .Element("output")
                            .Attribute("mode", XHDROutput_Mode, LogOutputMode_None)
                                .Mnemonic("none", "0")
                                .Mnemonic("api", "1")
                                .Mnemonic("file", "2")
                                .Mnemonic("inject", "3")
                        .End("output")
                        .Element("symbol", XHDRSymbolHeaders.Header, "")
                            .atEndCall(XHDRSymbolHeaders)
                            .Attribute("on-off", XHDRSymbolHeaders.OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("n", XHDRSymbolHeaders.Symbol, -1)
                        .End("symbol")
                        .Element("version", XHDRVersion_Header, "")
                            .Attribute("on-off", XHDRVersion_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("version")
                        .Element("license", XHDRLicense_Header, "")
                            .Attribute("on-off", XHDRLicense_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("license")
                        .Element("rulebase", XHDRRulebase_Header, "")
                            .Attribute("on-off", XHDRRulebase_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("rulebase")
                        .Element("identifier", XHDRIdentifier_Header, "")
                            .Attribute("on-off", XHDRIdentifier_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("identifier")
                        .Element("gbudb", XHDRGBUdb_Header, "")
                            .Attribute("on-off", XHDRGBUdb_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("gbudb")
                        .Element("result", XHDRResult_Header, "")
                            .Attribute("on-off", XHDRResult_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("result")
                        .Element("matches", XHDRMatches_Header, "")
                            .Attribute("on-off", XHDRMatches_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("matches")
                        .Element("black", XHDRBlack_Header, "")
                            .Attribute("on-off", XHDRBlack_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("black")
                        .Element("white", XHDRWhite_Header, "")
                            .Attribute("on-off", XHDRWhite_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("white")
                        .Element("clean", XHDRClean_Header, "")
                            .Attribute("on-off", XHDRClean_OnOff, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                        .End("clean")
                    .End("xheaders")
                .End("scan")
            .End("logs")
            .Element("network")
                .Element("sync")
                    .Attribute("secs", network_sync_secs, 30)
                    .Attribute("host", network_sync_host, "sync.messagesniffer.net")
                    .Attribute("port", network_sync_port, 25)
                .End("sync")
                .Element("update-script")
                    .Attribute("on-off", update_script_on_off, false)
                        .Mnemonic("on", "true")
                        .Mnemonic("off", "false")
                    .Attribute("call", update_script_call, "")
                    .Attribute("guard-time", update_script_guard_time, 180)
                .End("update-script")
            .End("network")
            .Element("xci")
                .Attribute("on-off", XCI_OnOff, true)
                    .Mnemonic("on", "true")
                    .Mnemonic("off", "false")
                .Attribute("port", XCI_Port, 9001)
            .End("xci")
            .Element("gbudb")
                .Element("database")
                    .Element("condense")
                        .Attribute("minimum-seconds-between", gbudb_database_condense_minimum_seconds_between, 600)
                        .Element("time-trigger")
                            .Attribute("on-off", gbudb_database_condense_time_trigger_on_off, true)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("seconds", gbudb_database_condense_time_trigger_seconds, 84600)
                        .End("time-trigger")
                        .Element("posts-trigger")
                            .Attribute("on-off", gbudb_database_condense_posts_trigger_on_off, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("posts", gbudb_database_condense_posts_trigger_posts, 32768)
                        .End("posts-trigger")
                        .Element("records-trigger")
                            .Attribute("on-off", gbudb_database_condense_records_trigger_on_off, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("records", gbudb_database_condense_records_trigger_records, 150000)
                        .End("records-trigger")
                        .Element("size-trigger")
                            .Attribute("on-off", gbudb_database_condense_size_trigger_on_off, false)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("megabytes", gbudb_database_condense_size_trigger_megabytes, 150)
                        .End("size-trigger")
                    .End("condense")
                    .Element("checkpoint")
                        .Attribute("on-off", gbudb_database_checkpoint_on_off, true)
                            .Mnemonic("on", "true")
                            .Mnemonic("off", "false")
                        .Attribute("secs", gbudb_database_checkpoint_secs, 3600)
                    .End("checkpoint")
                .End("database")
                .Element("regions")
                    .Element("white")
                        .atStartCall(WhiteRangeInitializer)
                        .Attribute("on-off", WhiteRangeHandler.On_Off, true)
                            .Mnemonic("on", "true")
                            .Mnemonic("off", "false")
                        .Attribute("symbol", WhiteRangeHandler.Symbol, 0)
                        .Attribute("priority", WhiteRangeHandler.Priority, 1)
                        .Element("edge")
                            .atEndCall(WhiteRangeHandler)
                            .Attribute("probability", WhiteRangeHandler.EdgeInput.Probability, 0.0)
                            .Attribute("confidence", WhiteRangeHandler.EdgeInput.Confidence, 0.0)
                        .End("edge")
                        .Element("panic")
                            .Attribute("on-off", gbudb_regions_white_panic_on_off, true)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("rule-range", gbudb_regions_white_panic_rule_range, 1000)
                        .End("panic")
                    .End("white")
                    .Element("black")
                        .atStartCall(BlackRangeInitializer)
                        .Attribute("on-off", BlackRangeHandler.On_Off, true)
                            .Mnemonic("on", "true")
                            .Mnemonic("off", "false")
                        .Attribute("symbol", BlackRangeHandler.Symbol, 63)
                            .mapTo(gbudb_regions_black_truncate_symbol, 63)
                        .Attribute("priority", BlackRangeHandler.Priority, 2)
                        .Element("edge")
                            .atEndCall(BlackRangeHandler)
                            .Attribute("probability", BlackRangeHandler.EdgeInput.Probability, 0.0)
                            .Attribute("confidence", BlackRangeHandler.EdgeInput.Confidence, 0.0)
                        .End("edge")
                        .Element("truncate")
                            .Attribute("on-off", gbudb_regions_black_truncate_on_off, true)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("probability", gbudb_regions_black_truncate_probability, 0.5)
                            .Attribute("peek-one-in", gbudb_regions_black_truncate_peek_one_in, 3)
                            .Attribute("symbol", gbudb_regions_black_truncate_symbol, 63)
                        .End("truncate")
                        .Element("sample")
                            .Attribute("on-off", gbudb_regions_black_sample_on_off, true)
                                .Mnemonic("on", "true")
                                .Mnemonic("off", "false")
                            .Attribute("probability", gbudb_regions_black_sample_probability, 0.5)
                            .Attribute("grab-one-in", gbudb_regions_black_sample_grab_one_in, 10)
                            .Attribute("passthrough", gbudb_regions_black_sample_passthrough, false)
                            .Attribute("passthrough-symbol", gbudb_regions_black_sample_passthrough_symbol, 0)
                        .End("sample")
                    .End("black")
                    .Element("caution")
                        .atStartCall(CautionRangeInitializer)
                        .Attribute("on-off", CautionRangeHandler.On_Off, true)
                            .Mnemonic("on", "true")
                            .Mnemonic("off", "false")
                        .Attribute("symbol", CautionRangeHandler.Symbol, 30)
                        .Attribute("priority", CautionRangeHandler.Priority, 3)
                        .Element("edge")
                            .atEndCall(CautionRangeHandler)
                            .Attribute("probability", CautionRangeHandler.EdgeInput.Probability, 0.0)
                            .Attribute("confidence", CautionRangeHandler.EdgeInput.Confidence, 0.0)
                        .End("edge")
                    .End("caution")
                .End("regions")
                .Element("training")
                    .atStartCall(HeaderDirectivesInitializer)
                    .Attribute("on-off", GBUdbTrainingOn_Off, true)
                            .Mnemonic("on", "true")
                            .Mnemonic("off", "false")
                    .Element("source")
                        .Element("header")
                            .atStartCall(HDSourceHeaderInitializer)
                            .atEndCall(HeaderDirectivesHandler)
                            .Attribute("name", HeaderDirectivesHandler.DirectiveInput.Header, "\n\n")
                            .Attribute("received", HeaderDirectivesHandler.ContextInput.Contains, "\n\n")
                            .Attribute("ordinal", HeaderDirectivesHandler.ContextInput.Ordinal, 0)
                        .End("header")
                    .End("source")
                    .Element("drilldown")
                        .Element("received")
                            .atStartCall(HDDrilldownInitializer)
                            .atEndCall(HeaderDirectivesHandler)
                            .Attribute("ordinal", HeaderDirectivesHandler.DirectiveInput.Ordinal, 0)
                            .Attribute("find", HeaderDirectivesHandler.DirectiveInput.Contains, "\n\n")
                        .End("received")
                    .End("drilldown")
                    .Element("bypass")
                        .atStartCall(TrainingBypassRuleInitializer)
                        .Element("result")
                            .atEndCall(TrainingBypassRuleHandler)
                            .Attribute("code", TrainingBypassRuleHandler.IntegerInput,-1)
                        .End("result")
                        .Element("header")
                            .atStartCall(HDBypassHeaderInitializer)
                            .atEndCall(HeaderDirectivesHandler)
                            .Attribute("name", HeaderDirectivesHandler.DirectiveInput.Header, "\n\n")
                            .Attribute("ordinal", HeaderDirectivesHandler.DirectiveInput.Ordinal, 0)
                            .Attribute("find", HeaderDirectivesHandler.DirectiveInput.Contains, "\n\n")
                        .End("header")
                    .End("bypass")
                    .Element("white")
                        .atStartCall(TrainingWhiteRuleInitializer)
                        .Element("result")
                            .atEndCall(TrainingWhiteRuleHandler)
                            .Attribute("code", TrainingWhiteRuleHandler.IntegerInput,-1)
                        .End("result")
                        .Element("header")
                            .atStartCall(HDWhiteHeaderInitializer)
                            .atEndCall(HeaderDirectivesHandler)
                            .Attribute("name", HeaderDirectivesHandler.DirectiveInput.Header, "\n\n")
                            .Attribute("ordinal", HeaderDirectivesHandler.DirectiveInput.Ordinal, 0)
                            .Attribute("find", HeaderDirectivesHandler.DirectiveInput.Contains, "\n\n")
                        .End("header")
                    .End("white")
                .End("training")
            .End("gbudb")
            .Element("rule-panics")
                .atStartCall(RulePanicInitializer)
                .Element("rule")
                    .atEndCall(RulePanicHandler)
                    .Attribute("id", RulePanicHandler.IntegerInput, -1)
                .End("rule")
            .End("rule-panics")
            .Element("platform", PlatformElementContents, "")
            .End("platform")
            .Element("msg-file")
                .Attribute("type", MessageFileTypeCGP_on_off, false)
                .Mnemonic("cgp", "true")
            .End("msg-file")
        .End("node")
    .End("snf");
}

void fixPathTermination(string& s) {                                            // Ensure s ends in a / or a \ as needed.

    if(0 == s.length()) return;                                                 // If the string is empty we do nothing.

    // Determine what our path terminator should be by looking to
    // see what separator has already been used.

    char Terminator;                                                            // This will be our terminator.
    if(string::npos == s.find('\\')) {                                          // If we're not using a backslash then
        Terminator = '/';                                                       // we will use the forward slash.
    } else {                                                                    // If we are using the backslash then
        Terminator = '\\';                                                      // we will remain consistent and terminate
    }                                                                           // with a backslash.

    // If the path that's given doesn't have a terminator then we will add
    // the appropriate separator to the end.

    if(                                                                         // If the string is
      '\\' != s.at(s.length()-1) &&                                             // not terminated by a backslash nor
      '/'  != s.at(s.length()-1)                                                // by a forward slash then
      ) {                                                                       // we will append an appropriate
        s.append(1,Terminator);                                                 // terminator. Otherwise we will
    }                                                                           // leave it as it is.
}

void snfCFGData::initializeFromFile(const char* FileName) {                     // Initialize from the provided file.
    ConfigurationData MyCFGData(FileName);                                      // Create a cfg data object from the file.
    if(0 == MyCFGData.Data(0)) throw false;                                     // If we didn't read a config file throw!
    MyCFGReader.initialize();                                                   // Initialize to defaults.
    MyCFGReader.interpret(MyCFGData);                                           // Interpret the data.
    fixPathTermination(paths_log_path);                                         // Automagically fix / or \ termination
    fixPathTermination(paths_rulebase_path);                                    // for the paths provided in the
    fixPathTermination(paths_workspace_path);                                   // configuration <path/> section.
    ConfigFilePath = FileName;                                                  // Set the ConfigFilePath for what we read.
}

snfIPRange snfCFGData::RangeEvaluation(GBUdbRecord& R) {                        // Returns the range for a GBUdbRecord.

    if(Good == R.Flag()) {                                                      // If the flag on the IP is Good
        return White;                                                           // then this IP is automatically white.
    } else
    if(Bad == R.Flag()) {                                                       // If the flag on this IP is Bad
        if(true == gbudb_regions_black_truncate_on_off) {                       // and truncate is turned on then
            return Truncate;                                                    // the IP is automatically in the
        } else {                                                                // truncate range. If truncate is off
            return Black;                                                       // then this IP is automatically black.
        }
    }
                                                                                // If it's not so simple then get a
    RangePoint P(R.Confidence(), R.Probability());                              // range point and evaluate it that way.
    return RangeEvaluation(P);
}

snfIPRange snfCFGData::RangeEvaluation(RangePoint& p) {                         // Returns the range for a RangePoint.
    if(                                                                         // If the IP is unknown, indicated
      0.0 == p.Confidence &&                                                    // by a zero confidence and
      0.0 == p.Probability                                                      // a zero probability, then
      ) {                                                                       // the range point cannot be "in"
        return New;                                                             // any range.
    }

    if(WhiteRangeHandler.isInWhite(p)) {                                        // If it's in the white range,
        return White;                                                           // return White.
    } else                                                                      // White has priority over all others.
    if(BlackRangeHandler.isInBlack(p)) {                                        // If it's in the black range then
        if(p.Probability >= gbudb_regions_black_truncate_probability) {         // determine if it's also in the truncate
            return Truncate;                                                    // range, and if so - send back Truncate.
        } else {                                                                // If not then we can send back a
            return Black;                                                       // normal black result.
        }
    } else                                                                      // Black takes precedence over caution.
    if(CautionRangeHandler.isInBlack(p)) {                                      // If we're in the caution range
        return Caution;                                                         // then return caution.
    }                                                                           // If none of those ranges matched then
    return Normal;                                                              // the IP is in the normal range.
}

//// snfCFGmgr /////////////////////////////////////////////////////////////////

void snfCFGmgr::initialize(                                                     // Initialize our configuration data.
  const char* FileName,
  const char* LicenseId,
  const char* Authentication) {

    // Check for NULLs and assign Init parameters

    InitFileName = (NULL==FileName)?"":FileName;                                // Initilization parameters are reused
    InitLicenseId = (NULL==LicenseId)?"":LicenseId;                             // any time load() is called.
    InitAuthentication = (NULL==Authentication)?"":Authentication;
}

void logCFGData(snfCFGData& D) {                                                // Log interpreted cfg data (debug aid).

    try {
        string CFGLogPath;                                                      // Build the snf_cfg log path.
        CFGLogPath = D.paths_log_path +
                     D.node_licenseid + "_snf_engine_cfg.log";
        ofstream cfgl(CFGLogPath.c_str(), ios::trunc);                          // Open and truncate the cfg log file.
        cfgl                                                                    // Report important cfg information.
          << "SNF Engine Configuration" << endl
          << "____________" << endl
          << "Fundamentals" << endl
          << "  License: " << D.node_licenseid << endl
          << "  ConfigFilePath: " << D.ConfigFilePath << endl
          << "  IdentityFilePath: " << D.node_identity << endl
          << "  SecurityKey: " << D.SecurityKey << endl
          << "_____" << endl
          << "Paths" << endl
          << "  Log Path: " << D.paths_log_path << endl
          << "  Rulebase Path: " << D.paths_rulebase_path << endl
          << "  Workspace Path: " << D.paths_workspace_path << endl
          << "  RuleFilePath: " << D.RuleFilePath << endl
          << "____" << endl
          << "Logs" << endl
          << endl
          << "  Rotation-Midnight: " << ((D.Logs_Rotation_LocalTime_OnOff)? "Local" : "UTC") << endl
          << "  ______" << endl
          << "  Status" << endl
          << "    PerSecond: "
            << ((D.Status_SecondReport_Log_OnOff)? "yes, " : "no, ")
            << "Append: "
            << ((D.Status_SecondReport_Append_OnOff)? "yes" : "no")
            << endl
          << "    PerMinute: "
            << ((D.Status_MinuteReport_Log_OnOff)? "yes, " : "no, ")
            << "Append: "
            << ((D.Status_MinuteReport_Append_OnOff)? "yes" : "no")
            << endl
          << "    PerHour: "
            << ((D.Status_HourReport_Log_OnOff)? "yes, " : "no, ")
            << "Append: "
            << ((D.Status_HourReport_Append_OnOff)? "yes" : "no")
            << endl
          << "  ____" << endl
          << "  Scan" << endl
          << "    Identifier: "
            << ((D.Scan_Identifier_Force_Message_Id)? "Force RFC822 Message-ID" : "Use Provided Identifier")
            << endl
          << "    Classic: Output-"
            << ((LogOutputMode_None == D.Scan_Classic_Mode)? "None, " :
                 ((LogOutputMode_API == D.Scan_Classic_Mode)? "API, " :
                   ((LogOutputMode_File == D.Scan_Classic_Mode)? "File, " : "Error!")))
            << ((D.Scan_Classic_Rotate)? "Rotating, ": "Non-Rotating, ")
            << ((D.Scan_Classic_Matches == ScanLogMatches_None) ? "No Mathes":
                 ((D.Scan_Classic_Matches == ScanLogMatches_Unique) ? "Unique Matches":
                   ((D.Scan_Classic_Matches == ScanLogMatches_All) ? "All Matches" : "Error!")))
            << endl
          << "    XML: Output-"
            << ((LogOutputMode_None == D.Scan_XML_Mode)? "None, " :
                 ((LogOutputMode_API == D.Scan_XML_Mode)? "API, " :
                   ((LogOutputMode_File == D.Scan_XML_Mode)? "File, " : "Error!")))
            << ((D.Scan_XML_Rotate)? "Rotating, ": "Non-Rotating, ")
            << ((D.Scan_XML_Matches == ScanLogMatches_None) ? "No Mathes, ":
                 ((D.Scan_XML_Matches == ScanLogMatches_Unique) ? "Unique Matches, ":
                   ((D.Scan_XML_Matches == ScanLogMatches_All) ? "All Matches, " : "Match Error! ")))
            << ((D.Scan_XML_Performance)? "Performance Metrics, " : "No Performance Metrics, ")
            << ((D.Scan_XML_GBUdb)? "GBUdb Data" : "No GBUdb Data")
            << endl
          << "    XHeaders:" << endl
            << "      Output: "
              << ((LogOutputMode_None == D.XHDROutput_Mode) ? "None" :
                   ((LogOutputMode_API == D.XHDROutput_Mode) ? "API" :
                     ((LogOutputMode_File == D.XHDROutput_Mode) ? "File" :
                       ((LogOutputMode_Inject == D.XHDROutput_Mode)? "Inject" : "Error!"))))
              << endl
            << "      Version: "
              << ((D.XHDRVersion_OnOff)? "On, " : "Off, ")
              << D.XHDRVersion_Header
              << endl
            << "      License: "
              << ((D.XHDRLicense_OnOff)? "On, " : "Off, ")
              << D.XHDRLicense_Header
              << endl
            << "      Rulebase: "
              << ((D.XHDRRulebase_OnOff)? "On, " : "Off, ")
              << D.XHDRRulebase_Header
              << endl
            << "      Identifier: "
              << ((D.XHDRIdentifier_OnOff)? "On, " : "Off, ")
              << D.XHDRIdentifier_Header
              << endl
            << "      GBUdb: "
              << ((D.XHDRGBUdb_OnOff)? "On, " : "Off, ")
              << D.XHDRGBUdb_Header
              << endl
            << "      Result: "
              << ((D.XHDRResult_OnOff)? "On, " : "Off, ")
              << D.XHDRResult_Header
              << endl
            << "      Matches: "
              << ((D.XHDRMatches_OnOff)? "On, " : "Off, ")
              << D.XHDRMatches_Header
              << endl
            << "      Black: "
              << ((D.XHDRBlack_OnOff)? "On, " : "Off, ")
              << D.XHDRBlack_Header
              << endl
            << "      White: "
              << ((D.XHDRWhite_OnOff)? "On, " : "Off, ")
              << D.XHDRWhite_Header
              << endl
            << "      Clean: "
              << ((D.XHDRClean_OnOff)? "On, " : "Off, ")
              << D.XHDRClean_Header
              << endl;

          for(
            set<XHDRSymbol>::iterator iH = D.XHDRSymbolHeaders.SymbolHeaders.begin();
            iH != D.XHDRSymbolHeaders.SymbolHeaders.end(); iH++
            ) {
              cfgl
                << "      Symbol: "
                << (*iH).Symbol << ", "
                << (*iH).Header
                << endl;
          }

        cfgl
          << "_______" << endl
          << "Network" << endl
          << "  Sync Host: " << D.network_sync_host << endl
          << "  Sync Port: " << D.network_sync_port << endl
          << "  Sync Secs: " << D.network_sync_secs << endl
          << "  _____________" << endl
          << "  Update-Script" << endl
          << "    On-Off: " << ((D.update_script_on_off) ? "On" : "Off") << endl
          << "    Script: " << D.update_script_call << endl
          << "    Guard-Time: " << D.update_script_guard_time << " seconds" << endl
          << "___" << endl
          << "XCI" << endl
          << "  " << ((D.XCI_OnOff)? "Enabled" : "Disabled") << endl
          << "  Port: " << D.XCI_Port << endl
          << "_____" << endl
          << "GBUdb" << endl
          << "  ____________" << endl
          << "  Condensation" << endl
          << "    Minimum-Seconds-Between = " << D.gbudb_database_condense_minimum_seconds_between << endl
          << "    Time-Trigger: "
            << ((D.gbudb_database_condense_time_trigger_on_off)? "on, " : "off, ")
            << D.gbudb_database_condense_time_trigger_seconds << " seconds" << endl
          << "    Posts-Trigger: "
            << ((D.gbudb_database_condense_posts_trigger_on_off)? "on, " : "off, ")
            << D.gbudb_database_condense_posts_trigger_posts << " posts" << endl
          << "    Records-Trigger: "
            << ((D.gbudb_database_condense_records_trigger_on_off) ? "on, " : "off, ")
            << D.gbudb_database_condense_records_trigger_records << " records" << endl
          << "    Size-Trigger: "
            << ((D.gbudb_database_condense_size_trigger_on_off) ? "on, " : "off, ")
            << D.gbudb_database_condense_size_trigger_megabytes << " megabytes" << endl
          << "  __________" << endl
          << "  Checkpoint" << endl
          << "    Checkpoint: "
            << ((D.gbudb_database_checkpoint_on_off) ? "on, " : "off, ")
            << D.gbudb_database_checkpoint_secs << " seconds" << endl
          << "  ______" << endl
          << "  Ranges" << endl
          << "    White: "
            << ((D.WhiteRangeHandler.On_Off) ? "on, " : "off, ")
            << "Symbol " << D.WhiteRangeHandler.Symbol << endl
          << "      Auto-Panic: "
            << ((D.gbudb_regions_white_panic_on_off) ? "on, " : "off, ")
            << "Range " << D.gbudb_regions_white_panic_rule_range << endl
          << endl
          << "    Caution: "
            << ((D.CautionRangeHandler.On_Off) ? "on, " : "off, ")
            << "Symbol " << D.CautionRangeHandler.Symbol << endl
          << endl
          << "    Black: "
            << ((D.BlackRangeHandler.On_Off) ? "on, " : "off, ")
            << "Symbol " << D.BlackRangeHandler.Symbol << endl
          << "      Truncate: "
            << ((D.gbudb_regions_black_truncate_on_off) ? "on, " : "off, ")
            << "Probability " << D.gbudb_regions_black_truncate_probability << ", "
            << "Peek-One-In " << D.gbudb_regions_black_truncate_peek_one_in << ", "
            << "Symbol " << D.gbudb_regions_black_truncate_symbol << endl
          << "      Sample: "
            << ((D.gbudb_regions_black_sample_on_off) ? "on, " : "off, ")
            << "Probability: " << D.gbudb_regions_black_sample_probability << ", "
            << "Grab-One-In: " << D.gbudb_regions_black_sample_grab_one_in << ", " << endl
          << "        Passthrough: "
            << ((D.gbudb_regions_black_sample_passthrough) ? "yes, " : "no, ")
            << "Passthrough Symbol " << D.gbudb_regions_black_sample_passthrough_symbol << endl
          << endl
          << "    Range Map - [W]hite [B]lack [C]aution [ ]undefined" << endl << endl
          << "    |-9876543210123456789+|" << endl;

        // Output GBUdb Range Map

        for(double c = 0; c < 1.01; c+=0.1) {                                   // Run through the confidence
            cfgl << "    |";
            for(double p = -1.0; p < 1.01; p+=0.1) {                            // and probability ranges.
                RangePoint t(c,p);                                              // Test the range point w/ c & p
                if(D.WhiteRangeHandler.isInWhite(t)) {                          // If it's in the white range
                    cfgl << "W";                                                // put in a W.
                } else
                if(D.BlackRangeHandler.isInBlack(t)) {                          // If it's in the black range
                    cfgl << "B";                                                // put in a B.
                } else
                if(D.CautionRangeHandler.isInBlack(t)) {                        // If it's in the caution range
                    cfgl << "C";                                                // put in a C.
                } else {
                    cfgl << " ";                                                // Otherwise put in a space.
                }
            }
            cfgl << "|" << c << endl;
        }
        cfgl << "    |---------------------|" << endl;

        cfgl
          << endl
          << "  ________" << endl
          << "  Training" << endl
          << "    GBUdb Updates: "
            << ((D.GBUdbTrainingOn_Off)? "Enabled" : "Disabled") << endl
          << endl;

        cfgl
          << "    Source Header Directives: " << endl;
        for(
          HeaderDirectiveSet::iterator iD = D.HeaderDirectivesHandler.HeaderDirectives.begin();
          iD != D.HeaderDirectivesHandler.HeaderDirectives.end(); iD++
          ) {
            const HeaderFinderPattern& Dx = *iD;
            if(HeaderDirectiveContext == Dx.Directive) {
                cfgl
                  << "      "
                  << "Context " << Dx.Context << " is a "
                  << Dx.Header << " header at"
                  << " Ordinal " << Dx.Ordinal
                  << " that Contains " << Dx.Contains << endl;
            } else
            if(HeaderDirectiveSource == Dx.Directive) {
                cfgl
                  << "      "
                  << "Context " << Dx.Context << " Source ip is in "
                  << Dx.Header << " header at"
                  << " Ordinal " << Dx.Ordinal << endl;
            }
        }
        cfgl << endl;

        cfgl
          << "    Drilldown Header Directives: " << endl;
        for(
          HeaderDirectiveSet::iterator iD = D.HeaderDirectivesHandler.HeaderDirectives.begin();
          iD != D.HeaderDirectivesHandler.HeaderDirectives.end(); iD++
          ) {
            const HeaderFinderPattern& Dx = *iD;
            if(HeaderDirectiveDrillDown == Dx.Directive) {
                cfgl
                  << "      "
                  << Dx.Header << " header at"
                  << " Ordinal " << Dx.Ordinal
                  << " Contains " << Dx.Contains << endl;
            }
        }
        cfgl << endl;

        cfgl
          << "    Bypass Header Directives: " << endl;
        for(
          HeaderDirectiveSet::iterator iD = D.HeaderDirectivesHandler.HeaderDirectives.begin();
          iD != D.HeaderDirectivesHandler.HeaderDirectives.end(); iD++
          ) {
            const HeaderFinderPattern& Dx = *iD;
            if(HeaderDirectiveBypass == Dx.Directive) {
                cfgl
                  << "      "
                  << Dx.Header << " header at"
                  << " Ordinal " << Dx.Ordinal
                  << " Contains " << Dx.Contains << endl;
            }
        }
        cfgl << endl;

        cfgl
          << "    White Rule Header Directives: " << endl;
        for(
          HeaderDirectiveSet::iterator iD = D.HeaderDirectivesHandler.HeaderDirectives.begin();
          iD != D.HeaderDirectivesHandler.HeaderDirectives.end(); iD++
          ) {
            const HeaderFinderPattern& Dx = *iD;
            if(HeaderDirectiveWhite == Dx.Directive) {
                cfgl
                  << "      "
                  << Dx.Header << " header at"
                  << " Ordinal " << Dx.Ordinal
                  << " Contains " << Dx.Contains << endl;
            }
        }
        cfgl << endl;

        cfgl
          << "    White Rule Symbols: ";

        // Output white rule symbols

        for(
          set<int>::iterator ix = D.TrainingWhiteRuleHandler.IntegerSet.begin();
          ix != D.TrainingWhiteRuleHandler.IntegerSet.end();
          ix ++) {
            if(D.TrainingWhiteRuleHandler.IntegerSet.begin() != ix) {
                cfgl << ", ";
            }
            cfgl << (*ix);
        }
        cfgl << endl;

        // Rule Panics

        cfgl
          << "___________" << endl
          << "Rule-Panics" << endl;

        for(
          set<int>::iterator ix = D.RulePanicHandler.IntegerSet.begin();
          ix != D.RulePanicHandler.IntegerSet.end();
          ix ++) {
            cfgl << "  Rule ID: " << (*ix) << endl;
        }
        cfgl << endl;

        cfgl
          << "___________" << endl
          << "Integration" << endl
          << endl
          << "  Message Format: "
          << ((D.MessageFileTypeCGP_on_off)? "CGP" : "RFC822")
          << endl;

#ifdef __BIG_ENDIAN__

        cfgl << "  Rulebase Conversion: BIG ENDIAN" << endl;

#else

        cfgl << "  Rulebase Conversion: LITTLE ENDIAN" << endl;

#endif

        cfgl
          << "________" << endl
          << "Platform" << endl
          << D.PlatformElementContents
          << endl;

        cfgl << endl;                                                           // End with a new line.
        cfgl.close();                                                           // Close the cfg log file.
    } catch (...) {}                                                            // Ignore any errors.
}

void snfCFGmgr::load() {

    // What shall we configure -- the inactive snfCFGData.

    snfCFGData& CFGData = InactiveData();

    // How shall we configure?
    // If FileName ends in .snf then find the .cfg file for details.
    // If the FileName ends some other way it _should_ be our cfg file.

    int PathLength = InitFileName.length();                                     // How long is the path?
    const int MinimumPathLength = 12;                                           // Must be at least licensid.snf long.
    if(MinimumPathLength > PathLength) throw LoadFailure();                     // Path length is impossible? throw!
    const string SNFExt = ".snf";                                               // The extension we are looking for.
    const string CFGExt = ".xml";                                               // The default cfg extension.
    const int SNFExtLength = SNFExt.length();                                   // The length of the extension.
    int SNFExtPosition = InitFileName.rfind(SNFExt,PathLength);                 // Find the extension at the end.

    bool InitPathIsRulebase = false;                                            // Was the init FileName the Rulebase?
    bool InitLicenseIdIsProvided = (0 < InitLicenseId.length());                // Was the init LicenseId provided?
    bool InitAuthenticationIsProvided = (0 < InitAuthentication.length());      // Was the authentication provided?

    if((PathLength - SNFExtLength) == SNFExtPosition) {                         // If path ends in .snf then
        InitPathIsRulebase = true;                                              // set our flag to keep track then set
        ConfigurationPath = InitFileName.substr(0,SNFExtPosition);              // our configuration path as the init
        ConfigurationPath.append(CFGExt);                                       // file name with the config extension.
    } else {                                                                    // If the init file is not a rulebase
        ConfigurationPath = InitFileName;                                       // then it is the config file name.
    }

    // At this point we know where to read our configuration from.

    try { CFGData.initializeFromFile(ConfigurationPath.c_str()); }              // Initialize the inactive config.
    catch(...) {                                                                // If that failed then throw.
        throw LoadFailure();
    }

    // Now that the main config has been read we create the derived cfg data.
    // Anything that was provided in Init takes precedence over the config.

    //// SecurityKey
    //// If an identity path has been provided we must load that data.

    if(0 < CFGData.node_identity.length()) {                                    // If an identity path was provided
        ConfigurationData Identity(CFGData.node_identity.c_str());              // then get the data from that file.
        ConfigurationElement IdentityReader("snf");                             // Create an Identity reader and
        IdentityReader                                                          // configure it.
            .Element("identity")
                .Attribute("licenseid", CFGData.node_licenseid)
                .Attribute("authentication", CFGData.node_authentication)
            .End("identity")
        .End("snf");
        IdentityReader.interpret(Identity);                                     // Then read the data.
    }

    //// The SecurityKey is built from the licenseID and the Authentication

    if(InitLicenseIdIsProvided) {                                               // If the LicenseID has been provided then
        CFGData.SecurityKey = InitLicenseId;                                    // the first part of our security key is that.
    } else {                                                                    // If it was not provided then we will get
        CFGData.SecurityKey = CFGData.node_licenseid;                           // the LicenseID from our config file.
    }

    if(InitAuthenticationIsProvided) {                                          // If the Authentication has been provided then
        CFGData.SecurityKey += InitAuthentication;                              // we use it for the second part of our
    } else {                                                                    // security key. Otherwise we will get the
        CFGData.SecurityKey += CFGData.node_authentication;                     // Authentication from the config file.
    }

    //// RuleFilePath

    if(InitPathIsRulebase) {                                                    // If the Rulebase path was provided
        CFGData.RuleFilePath = InitFileName;                                    // then we have our rulebase path.
    } else {                                                                    // If not then we must figure it out...
        CFGData.RuleFilePath =                                                  // We build the path from the base
            CFGData.paths_rulebase_path +                                       // rulebase path concattonated with
            CFGData.node_licenseid +                                            // the license id concattonated with
            SNFExt;                                                             // the rulebase extension.
    }

    // Once all of the configuration data is correct we make it active.

    swapCFGData();                                                              // Then swap it into the active state.

    // Log the configuration data as it was interpreted.

    logCFGData(ActiveData());

}

