/////////////////////////////////////////////////////////////////////////////////
// IPFilter Update Class - written by bluesonicboy of TK4
//
// Updates the IPFilter from ant HTTP source.
//
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.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 "afxinet.h"
#include "opcodes.h"
#include "IPFilter.h"
#include "ZipFile.h"
#include "GZipFile.h"
#include "Preferences.h"
#include "IPFilterUpdate.h" //[IPUP] IP update 
#include "OtherFunctions.h" //for thread debug
#include "ServerListCtrl.h" //for locking out server functions while update in another thread is in progress
#include "ServerWnd.h"      //for locking out server functions while update in another thread is in progress
#include "emuledlg.h"       //for locking out server functions while update in another thread is in progress
#include "emule.h"

CIPFilterUpdate theIPFilterUpdateClass;

UINT CIPFilterUpdate::RunStatus  = 0xff;  //Thread status indicator
bool CIPFilterUpdate::filtersupd = false; //Filters being updated


void CIPFilterUpdate::GetUpdate(void){
	//New in ver. 2.0a do not allow any code to run this update more than once
	if(RunStatus != 0) AfxBeginThread(RunProc, (LPVOID)this);
}


UINT AFX_CDECL CIPFilterUpdate::RunProc(LPVOID pParam) {
	DbgSetThreadName("IPFilterUpdate");
	InitThreadLocale();
	CIPFilterUpdate* IPFilterUpdate = (CIPFilterUpdate*)pParam;
	return IPFilterUpdate->RunInternal();
}

/*
This thread downloads, extracts if needed, and installs ipfilter.dat
Exit codes: 
[0] = All went well, No error  [1] = File error or download error 
[2] = Zip extraction failure   [3] = Zip file not found failure 
[4] = GZ  extraction failure   [5] = Update did not load any filters old file restored
[6] = Update did not load any filters old file not restored
*/
UINT CIPFilterUpdate::RunInternal()
{
 //when 0 a thread has been created and is runnning,use to lock out the IP Dialog
 RunStatus = 0;

 #define HTTPBUFFERLEN   512 // Size of HTTP Buffer...
 char httpbuffer[HTTPBUFFERLEN];
 int bytes;
 INTERNET_PORT Port;
 DWORD ServiceType;
 CString Server;
 CString Object;
 
 
 bytes = thePrefs.urlandfile.ReverseFind(_T('/')); //get filename use the 'bytes' int 
 bytes++; //do not include the '/'
 CString FileName=thePrefs.urlandfile.Mid( bytes,(thePrefs.urlandfile.GetLength()-bytes)); //get the filename
 
 TCHAR SavePathName[512]; //Save our file in the config folder
 CString configdir = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR); //config dir/folder
 _stprintf((wchar_t*)&SavePathName[0],_T("%s%s"),configdir,FileName); //create save path and name
 CString backupname = configdir + CString("IPFilter.bak"); //create backup file name
 CString ipfilter = configdir + CString("IPFilter.dat");   //create actual file name
 CString strUnzipFilePath;
 /*back-up ipfilter.dat*/
 try
   {
    CFile::Remove(backupname);//remove old backup file  
   }
 catch(CFileException* e )//catch and delete exceptions
      {
       #ifdef _DEBUG
        afxDump << "File " << backupname << " cannot be removed\n";
       #endif
       e->Delete();
       }
 try
   {
    CFile::Rename(ipfilter, backupname );//create new backup
   }
 catch(CFileException* e )//catch and delete exceptions
      {
       #ifdef _DEBUG
        afxDump << "File " << ipfilter << " not found, cause = "
            << e->m_cause << "\n"; 
       #endif
       e->Delete();
      }//back-up done

 AfxParseURL(thePrefs.urlandfile, ServiceType, Server, Object, Port);         //Parse URL returns Service type, Server Object and Port.
 CInternetSession session(_T("e M u l e  ") + theApp.m_strCurVersionLong, 1, PRE_CONFIG_INTERNET_ACCESS);//Create a session	set client name emule _ mod version -  New for Ver 2.0 space the word eMule to help prevent filtering - Based on an obsevation and ideas by leuk_he
 CFile* sf = NULL;

  TRY
     {
      //save the target file.
      CStdioFile *file = session.OpenURL(thePrefs.urlandfile,1,INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE);
      CFile savefile(SavePathName, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
      sf=&savefile;
	  while(bytes = file->Read(httpbuffer, HTTPBUFFERLEN))
	       {
			savefile.Write(httpbuffer, bytes);
		    }
	  savefile.Close();
	  CString ext =  CString(SavePathName).Right(4); //get the last four characters
	  ext.MakeLower();

	  /*do we need to unpack this file? */
	  if( ext==_T(".zip") || (ext[1]==_T('.') && ext[2]==_T('g') && ext[3]==_T('z')) )
	    {//Yes, unpack it
		    CZIPFile zip;		   
			strUnzipFilePath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
			strUnzipFilePath += DFLT_IPFILTER_FILENAME;
			if(zip.Open(SavePathName))
		      {
			    CZIPFile::File* zfile = zip.GetFile(DFLT_IPFILTER_FILENAME);
				if(zfile)
			      {//EXTRACT *.zip file
				   if(!zfile->Extract(strUnzipFilePath))
				        {
					      CString strError;
					      strError.Format(_T("Failed to extract IP filter file \"IPFilter.dat\" from ZIP file \"%s\"."), SavePathName);
					      AfxMessageBox(strError);
						  CFile::Remove(ipfilter);//remove any created file
                          CFile::Rename(backupname,ipfilter );//restore the backup
                          AfxEndThread(RunStatus = 0x2); 
				          }
			       } else
			              {
				           CString strError;
				           strError.Format(_T("Failed to find IP filter file \"IPFilter.dat\" in ZIP file \"%s\"."), SavePathName);
				           AfxMessageBox(strError);
			               CFile::Remove(ipfilter);//remove any created file
                           CFile::Rename(backupname,ipfilter );//restore the backup
						   AfxEndThread(RunStatus = 0x3); 
						   }
			       zip.Close();
		        } 	else {//EXTRACT *.gz file
			              CGZIPFile gz;
			              if(gz.Open(SavePathName))
			                {
		 	                 /* //Commented to allow for BLISS archives which contain a renamed IPFilter.dat eg nipfilter.dat
							  CString strUncompressedFileName = gz.GetUncompressedFileName();
				              if(!strUncompressedFileName.IsEmpty())
				                {
								 strUnzipFilePath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
					             strUnzipFilePath += //strUncompressedFileName;
				                }*/

				              if(!gz.Extract(strUnzipFilePath))	
								 {//extract failed - restore old IPFilter.dat & return false
								  gz.Close();
								  CFile::Remove(ipfilter);//remove any created file
                                  CFile::Rename(backupname,ipfilter );//restore the backup
								  AfxEndThread(RunStatus = 0x4); 
								  }
								  
			                }
			               gz.Close();
		                  }//end gz scope
        }
     }

  CATCH_ALL(err)
   {
    if(sf) sf->Abort();   // close file safely and quietly
	err->Delete();        //delete error

	try{//try to remove the new ip filter file if it exists
	    CFile::Remove(ipfilter);//remove any created file
        }
	catch(CFileException* e1 )//catch and delete exceptions
	    {
         e1->Delete();
         }
	try{//try to restore the original ip filter file
	    CFile::Rename(backupname,ipfilter );//restore the backup
        }
	catch(CFileException* e2 )//catch and delete exception
        {
         #ifdef _DEBUG
         afxDump << "IPFilter.dat restore may have failed \n"; 
         #endif
         e2->Delete();
         }
    AfxEndThread(RunStatus = 0x1);
	}
  END_CATCH_ALL;
 //Prevent connections while IP filters are being updated and hence unavailable
 filtersupd = true;
 //Update the IP Filters :o)
 if(!theApp.ipfilter->LoadFromDefaultFile(false))//returns filter count
   {//if filters count = 0 restore the backup and reload the old list!
	try{//try to remove the new ip filter file if any
	    CFile::Remove(ipfilter);//remove any created file
        }
	catch(CFileException* e1 )//catch and delete exceptions
        {
         e1->Delete();
         }
	 try{
         CFile::Rename(backupname,ipfilter );//restore the backup
		 theApp.ipfilter->LoadFromDefaultFile(false);//reload the old filters
	     }
	 catch(CFileException* e2 )//catch and delete exceptions
         {
	      #ifdef _DEBUG
	      afxDump << "A error occurred restoring backup IP Filter file after update failed to load any filters.\n";
		  #endif
		  e2->Delete();
		  filtersupd = false;
          AfxEndThread(RunStatus  = 0x06);
          }
   filtersupd = false;
   AfxEndThread(RunStatus  = 0x05);
   }
 //Thread ends no error occurred 
 //New in version 47c TK4 version 2.0a
 SYSTEMTIME systime;
 GetSystemTime(&systime);
 if(systime.wMonth < 12) systime.wMonth++;
  else                   systime.wMonth = 1;
 thePrefs.IPUPTimer = (systime.wMonth << 16) + (systime.wDay << 8) + systime.wHour;
 filtersupd = false; //enables connections again
 if(thePrefs.GetFilterServerByIP()) theApp.emuledlg->serverwnd->serverlistctrl.RemoveAllFilteredServers();//Filter Servers
 RunStatus  = 0xff;  //enables IP Filter dialog
 return 0x0;         //Thread Ends
}

