// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-project.net )
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// 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.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#	include "IPFilter.h"
#	include "otherfunctions.h"
#include "Preferences.h"                    // CPreferences::GetIPFilterLevel
#	include "wintypes.h"
#	include "xmule.h"
#	include "xmuleDlg.h"
#endif

#include <DynPrefs/DynPrefs.h>              // Needed for DynamicPreferences

CIPFilter::CIPFilter()
{
    lasthit = "";
    LoadFromFile();
}

CIPFilter::~CIPFilter()
{
    RemoveAllIPs();
}

void CIPFilter::AddBannedIPRange(uint32_t IPfrom, uint32_t IPto, uint8_t filter, wxString desc)
{
    IPRange_Struct *newFilter = new IPRange_Struct();
    IPRange_Struct *search;
    bool inserted = false;
    newFilter->IPstart = IPfrom;
    newFilter->IPend = IPto;
    newFilter->filter = filter;
    newFilter->description = desc;
    if (iplist.GetCount() == 0) iplist.InsertAt(0, newFilter);
    else
    {
        for (int i = 0 ; i < iplist.GetCount() ; i++)
        {
            search = iplist.GetAt(i);
            if (search->IPstart > IPfrom)
            {
                iplist.InsertAt(i, newFilter);
                inserted = true;
                break;
            }
        }
        if (!inserted) iplist.Add(newFilter);
    }
}

int CIPFilter::LoadFromFile()
{
    wxString sbuffer, sbuffer2, sbuffer3, sbuffer4;
    int pos, filtercounter;
    uint32_t ip1, ip2;
    uint8_t filter;
    char buffer[1024];
    int lenBuf = 1024;
    filtercounter = 0;
    RemoveAllIPs();
    FILE *readFile = fopen(static_cast<const char *>(wxString(theApp.dynprefs->Get<wxString>("app-directory") + "ipfilter.dat").c_str()), "r");
    if (readFile != NULL)
    {
        while (!feof(readFile))
        {
            if (fgets(buffer, lenBuf, readFile) == 0) break;
            sbuffer = buffer;
            // ignore comments & too short lines
            if (sbuffer.GetChar(0) == '#' || sbuffer.GetChar(0) == '/' || sbuffer.Length() < 5)
            continue;
            // get & test & process IP range
            pos = sbuffer.Find(",");
            if (pos == - 1) continue;
            sbuffer2 = sbuffer.Left(pos) .Trim();
            pos = sbuffer2.Find("-");
            if (pos == - 1) continue;
            sbuffer3 = sbuffer2.Left(pos) .Trim();
            sbuffer4 = sbuffer2.Right(sbuffer2.Length() - pos - 1) .Trim();
            ip1 = ip2 = 0;
            wxString temp;
            bool skip = false;
            unsigned int s3[4];
            unsigned int s4[4];
            memset(s3, 0, sizeof(s3));
            memset(s4, 0, sizeof(s4));
            sscanf(sbuffer3.GetData(), "%d.%d.%d.%d", &s3[0], &s3[1], &s3[2], &s3[3]);
            sscanf(sbuffer4.GetData(), "%d.%d.%d.%d", &s4[0], &s4[1], &s4[2], &s4[3]);
            if ((s3[0] == s3[1] == s3[2] == s3[3] == 0) || (s4[0] == s4[1] == s4[2] == s4[3] == 0))
            {
                skip = true;
            }
            for (int i = 0 ; i < 4 ; i++)
            {
                ip1 |= (uint32_t)(s3[i] << (8 * (3 - i)));
                ip2 |= (uint32_t)(s4[i] << (8 * (3 - i)));
            }
#if 0
            for (int i = 0 ; i < 4 ; i++)
            {
                //sbuffer3.Tokenize(".",counter);
                Tokenize(sbuffer3, ".", counter);
                if (counter == - 1)
                {
                    skip = true;
                    break;
                }
            }
            counter = 0;
            for (int i = 0 ; i < 4 ; i++)
            {
                //sbuffer4.Tokenize(".",counter);
                Tokenize(sbuffer4, counter);
                if (counter == - 1)
                {
                    skip = true;
                    break;
                }
            }
            if (skip) continue;
            counter = 0;
            for (int i = 0 ; i < 4 ; i++)
            {
                //sbuffer3.Tokenize(".",counter);:
                temp = Tokenize(sbuffer3, ".", counter);
                ip1 |= (uint32_t)(atoi(temp) << (8 * (3 - i)));
                //sbuffer4.Tokenize(".",counter);:
                temp = Tokenize(sbuffer4, ".", counter);
                ip2 |= (uint32_t)(atoi(temp) << (8 * (3 - i)));
            }
#endif
            // filter
            bool found = false;
            for (unsigned int m = pos + 1 ; m < sbuffer.Length() ; m++)
            {
                if (sbuffer.GetChar(m) == ',')
                {
                    pos = m;
                    found = true;
                    break;
                }
            }
            if (!found) pos = - 1;
            //pos=sbuffer.Find(",",pos+1);
            //int pos2=sbuffer.Find(",",pos+1);
            int pos2 = ( - 1);
            found = false;
            for (unsigned int m = pos + 1 ; m < sbuffer.Length() ; m++)
            {
                if (sbuffer.GetChar(m) == ',')
                {
                    pos2 = m;
                    found = true;
                    break;
                }
            }
            if (pos2 == - 1) continue;
            sbuffer2 = sbuffer.Mid(pos + 1, pos2 - pos - 1) .Trim();
            filter = atoi(sbuffer2);
            sbuffer2 = sbuffer.Right(sbuffer.Length() - pos2 - 1);
            if (sbuffer2.GetChar(sbuffer2.Length() - 1) == 10) sbuffer2.Remove(sbuffer2.Length() - 1);
            // add a filter
            AddBannedIPRange(ip1, ip2, filter, wxString(sbuffer2.GetData()));
            filtercounter++;
        }
        fclose(readFile);
    }
    theApp.xmuledlg->AddLogLine(true, "Loaded ipfilter with %d IP addresses.", filtercounter);
    return filtercounter;
}

void CIPFilter::SaveToFile()
{
}

void CIPFilter::RemoveAllIPs()
{
    IPRange_Struct *search;
    while (iplist.GetCount() > 0)
    {
        search = iplist.GetAt(0);
        iplist.RemoveAt(0);
        delete search;
    }
}

bool CIPFilter::IsFiltered(uint32_t IP2test)
{
    if (iplist.GetCount() == 0) return false;
    //CSingleLock(&m_Mutex,TRUE); // will be unlocked on exit
    IPRange_Struct *search;
    uint32_t IP2test_ = (uint8_t)(IP2test >> 24) | (uint8_t)(IP2test >> 16) << 8 | (uint8_t)(IP2test >> 8) << 16 | (uint8_t)(IP2test) << 24;
    uint16_t lo = 0;
    uint16_t hi = iplist.GetCount() - 1;
    uint16_t mi;
    while (true)
    {
        mi = ((hi - lo) /2) + lo;
        search = iplist.GetAt(mi);
        if (search->IPstart <= IP2test_ &&search->IPend >= IP2test_)
        {
            if (search->filter < theApp.glob_prefs->GetIPFilterLevel())
            {
                lasthit = search->description;
                return true;
            }
            return false;
        }
        if (lo == hi) return false;
        if (IP2test_ < search->IPstart) hi = mi;
        else lo = mi + 1;
    }
    return false;
}

