//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-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.

#include "StdAfx.h"
#include "IPFilter.h"
#include "emule.h"
#include "otherfunctions.h"

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

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

void CIPFilter::AddBannedIPRange(uint32 IPfrom,uint32 IPto,uint8 filter, CString 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(){
	CString sbuffer,sbuffer2,sbuffer3,sbuffer4;
	int pos,filtercounter;
	uint32 ip1,ip2;
	uint8 filter;
	char buffer[1024];
	int lenBuf = 1024;
	filtercounter=0;

	RemoveAllIPs();

	FILE* readFile= fopen(CString(theApp.glob_prefs->GetAppDir())+"ipfilter.dat", "r");
	if (readFile!=NULL) {
		while (!feof(readFile)) {
			if (fgets(buffer,lenBuf,readFile)==0) break;
			sbuffer=buffer;
			
			// ignore comments & too short lines
			if (sbuffer.GetAt(0) == '#' || sbuffer.GetAt(0) == '/' || sbuffer.GetLength()<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.GetLength()-pos-1).Trim();

			ip1=ip2=0;
			int counter = 0;
			CString temp;
			bool skip=false;

			for( int i = 0; i < 4; i++){
				sbuffer3.Tokenize(".",counter);
				if( counter == -1 ){ skip=true;break;}
			}
			counter=0;
			for( int i = 0; i < 4; i++){
				sbuffer4.Tokenize(".",counter);
				if( counter == -1 ){ skip=true;break;}
			}
			if (skip) continue;
			
			counter=0;
			for(int i=0; i<4; i++){ 
				temp = sbuffer3.Tokenize(".",counter);
				ip1 += atoi(temp) * pow(256,3-i);
			}
			counter=0;
			for(int i=0; i<4; i++){ 
				temp = sbuffer4.Tokenize(".",counter);
				ip2 += atoi(temp) * pow(256,3-i);
			}

			// filter
			pos=sbuffer.Find(",",pos+1);
			int pos2=sbuffer.Find(",",pos+1);
			if (pos2==-1) continue;
			sbuffer2=sbuffer.Mid(pos+1,pos2-pos-1).Trim();
			filter=atoi(sbuffer2);

			sbuffer2=sbuffer.Right(sbuffer.GetLength()-pos2-1);
			if (sbuffer2.GetAt(sbuffer2.GetLength()-1)==10) sbuffer2.Delete(sbuffer2.GetLength()-1);

			// add a filter
			AddBannedIPRange(ip1,ip2,filter,sbuffer2 );
			filtercounter++;

		}
		fclose(readFile);
	}
	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 IP2test){
	if (iplist.GetCount()==0) return false;

	//CSingleLock(&m_Mutex,TRUE); // will be unlocked on exit

	IPRange_Struct* search;
	uint32 IP2test_=(uint8)(IP2test>>24) | (uint8)(IP2test>>16)<<8 | (uint8)(IP2test>>8)<<16 | (uint8)(IP2test)<<24 ;

	uint16 lo=0;
	uint16 hi=iplist.GetCount()-1;
	uint16 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;
}
