/***************************************************************************
*                                                                         *
*   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.                                   *
*                                                                         *
***************************************************************************/
/*
Author: Christian Hubinger <chubinger@irrsinnig.org>, (C) 2001
*/


#include "kmfinstallerplugin.h"


// QT includes
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqmultilineedit.h>
#include <tqiconset.h>
#include <tqdatetime.h>

// KDE includes
#include <kinstance.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <ktrader.h>
#include <kstandarddirs.h>
#include <kio/netaccess.h>

// Project includes
#include "../core/kmfconfig.h"
#include "../core/kmfdoc.h"
#include "../core/kmfprotocol.h"
#include "../core/kmfrulesetdoc.h"
#include "../core/kmftarget.h"
#include "../core/kmftargetconfig.h"
#include "../core/kmfnetwork.h"
#include "../core/kmfiptdoc.h"
#include "../core/kmferror.h"
#include "../core/kmferrorhandler.h"
#include "../core/kmfgenericdoc.h"
#include "../core/kmfpluginfactory.h"
#include "../core/kmfcompilerinterface.h"
#include "../core/kmfinstallerinterface.h"
#include "../core/kprocesswrapper.h"
#include "../core/xmlnames.h"

#include "../kmfwidgets/kmfmainwindow.h"
#include "../kmfwidgets/kmfprocout.h"
#include "../kmfwidgets/kmfselectactivetarget.h"

#include "linux/kmfiptinstaller.h"

namespace KMF {

KMFInstallerPlugin::KMFInstallerPlugin( TQObject *parent, const char *name )
	: KMFPlugin( parent, name ) {

	m_docType = -1;
	KMFMainWindow* app = 0;
	app = dynamic_cast<KMFMainWindow*>( parent );
	if ( ! app ) {
		KMessageBox::error( 0, "Oops wrong parent class found for kmfinstallerplugin!!!" );
	}
	m_doc = app->network()->currentDoc();

// 	m_installerPlugin = 0;
	m_execWidget = 0;
	m_actionStopFw = new KAction( i18n( "&Reset IPTables" ), "decrypted",
	                              0, this, TQT_SLOT( slotStopFirewall() ), actionCollection(), "reset_iptables" );

	m_actionRunFw = new KAction( i18n( "Run Fir&ewall" ), "encrypted",
	                             0, this, TQT_SLOT( slotStartFirewall() ), actionCollection(), "run_firewall" );

	m_actionPreviewScript = new KAction( i18n( "&Preview Script" ), "mime_txt",
	                                     0 , this, TQT_SLOT( slotShowScript() ), actionCollection(), "preview_script" );

	m_generateInstallPackage  = new KAction( i18n( "&Generate Linux Installation Package" ), "fileexport",
			0 , this, TQT_SLOT( slotGenerateInstallerPackage() ), actionCollection(), "generate_install_package" );
	
	m_actionShowConfig = new KAction( i18n( "Show &All Tables" ), "messagebox_info",
	                                  0 , this, TQT_SLOT( slotShowConfig() ), actionCollection(), "show_ipt_config" );

	m_actionShowFilter = new KAction( i18n( "Show &Filter Table" ), "messagebox_info",
	                                  0 , this, TQT_SLOT( slotShowFilter() ), actionCollection(), "show_filter" );

	m_actionShowNat = new KAction( i18n( "Show &Nat Table" ), "messagebox_info",
	                               0 , this, TQT_SLOT( slotShowNat() ), actionCollection(), "show_nat" );

	m_actionShowMangle = new KAction( i18n( "Show &Mangle Table" ), "messagebox_info",
	                                  0 , this, TQT_SLOT( slotShowMangle() ), actionCollection(), "show_mangle" );

	m_actionMenu = new KActionMenu( i18n( "Show IPTables Configuration" ), "messagebox_info", this , "show_menu" );

	m_actionMenu->insert( m_actionShowConfig );
	m_actionMenu->insert( m_actionShowFilter );
	m_actionMenu->insert( m_actionShowNat );
	m_actionMenu->insert( m_actionShowMangle );
	m_actionMenu->setDelayed( false );
	m_actionMenu->setStickyMenu( true );
	actionCollection() ->insert( m_actionMenu );

	m_actionInstallFW = new KAction( i18n( "&Install Firewall" ), "down",
	                                 0 , this, TQT_SLOT( slotInstallFW() ), actionCollection(), "install_firewall" );

	m_actionUninstallFW = new KAction( i18n( "&Uninstall Firewall" ), "up",
	                                   0 , this, TQT_SLOT( slotUninstallFW() ), actionCollection(), "uninstall_firewall" );
	setXMLFile( "kmfinstallerpluginui.rc" );

	slotEnableActions( false );
	connect( app,TQT_SIGNAL( sigEnableActions( bool ) ),
         this, TQT_SLOT( slotEnableActions(bool ) ) );

	kdDebug() << "KMFInstallerPlugin: Finished Initialisationn " << endl;
}

KMFInstallerPlugin::~KMFInstallerPlugin() {}

bool KMFInstallerPlugin::isConfigValid() {
	bool configValid = false;
	if ( rulesetDoc() ) {
		configValid = rulesetDoc()->target()->config()->isValid();
		
		if ( ! configValid ) {
			if(  KMessageBox::questionYesNo ( 0, 
				i18n( "<qt><p>Do you want KMyFirewall to try to auto configure %1 settings</p></qt>" ).arg( rulesetDoc()->target()->toFriendlyString() ),
	                                        i18n( "Auto Configure Target" ), KStdGuiItem::yes(), KStdGuiItem::no() ) == KMessageBox::Yes ) {
				KMFError* err = rulesetDoc()->target()->tryAutoConfiguration();
				KMFErrorHandler* errH = new KMFErrorHandler( "Target Autoconfiguration" );
				errH->showError( err );
				
				if ( ! rulesetDoc()->target()->config()->isValid() ) {
					KMessageBox::error( KApplication::kApplication()->mainWidget(), i18n("<qt><p>Auto Confguration of: %1 could not determinate all needed setting. You'll need to configure the mmissing settings.</p></qt>").arg( rulesetDoc()->target()->toFriendlyString() ) );
				} else {
					KMessageBox::information( KApplication::kApplication()->mainWidget(), i18n("<qt><p>Auto Confguration of: %1 finished successfully.</p></qt>").arg( rulesetDoc()->target()->toFriendlyString() ) );
				}
				
				configValid = rulesetDoc()->target()->config()->isValid();
				delete errH;
				delete err;
			}
		}
	}
	return configValid;
}
KMFProcOut* KMFInstallerPlugin::execWidget() {
	if ( m_execWidget )
		return m_execWidget;
	kdDebug() << "Need to create new execWidget." << endl;
	m_execWidget = new KMFProcOut( (KMFMainWindow*) parent(), "KMFProcOut" );
	return m_execWidget;
}


void KMFInstallerPlugin::generateInstallerPackage( KMFTarget* tg ) {
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}
	
	if ( rulesetDoc() ) {
		
	
		KMFInstallerInterface *inst2 = tg->installer(); 
		if ( ! inst2 )
			return;
		
		
		TQString remDir = rulesetDoc()->target()->getFishUrl();
		remDir.append( "/tmp/" );
		
		TQString path = remDir;
		path.append( "kmfpackage.kmfpkg" );
		KURL url( path );
		KURL remDirUrl( remDir );
		
		if ( url.fileName().isEmpty() )
			return;
		
		if ( KIO::NetAccess::exists( url, false, KApplication::kApplication()->mainWidget() ) ) {
			TQDateTime now = TQDateTime::currentDateTime();
			
			TQString backUp;
			backUp.append( url.url() );
			backUp.append( "_backup_" );
			backUp.append( now.toString( "dd.MM.yyyy.hh:mm:ss" ) );
			KURL newUrl( backUp );
			
			
			TQString backFileName = "kmfpackage.kmfpkg";
			backUp.append( "_backup_" );
			backUp.append( now.toString( "dd.MM.yyyy.hh:mm:ss" ) );
			
			
			KIO::NetAccess::file_move( url, newUrl, 700, true, true, KApplication::kApplication()->mainWidget() );
			KIO::NetAccess::fish_execute( remDir, "chmod 400 /tmp/" + backFileName, KApplication::kApplication()->mainWidget() );
		}
		
		inst2->generateInstallerPackage( tg, url );
		KIO::NetAccess::fish_execute( remDir, "chmod 700 /tmp/kmfpackage.kmfpkg", KApplication::kApplication()->mainWidget() );
	}
}



// ########## Slots for the Actions ###############
void KMFInstallerPlugin::slotShowScript() {
	kdDebug() << "void KMFInstallerPlugin::slotShowScript()" << endl;
	setOutputWidget( execWidget() );
	TQString script = rulesetDoc()->compile();
	kdDebug() << "\n\nCompiled Script: " << script << "\n\n" << endl;
	execWidget()->setText( script, i18n("Show firewall script...") );
	showOutput();
}

void KMFInstallerPlugin::slotShowConfig() {
	kdDebug() << "void KMFInstallerPlugin::slotShowConfig()" << endl;
	cmdShowRunningConfig( "all" );
}

void KMFInstallerPlugin::slotShowFilter() {
	kdDebug() << "void KMFInstallerPlugin::slotShowFilter()" << endl;
	cmdShowRunningConfig( Constants::FilterTable_Name );
}

void KMFInstallerPlugin::slotShowNat() {
	kdDebug() << "void KMFInstallerPlugin::slotShowNat()" << endl;
	cmdShowRunningConfig( Constants::NatTable_Name );
}

void KMFInstallerPlugin::slotShowMangle() {
	kdDebug() << "void KMFInstallerPlugin::slotShowMangle()" << endl;
	cmdShowRunningConfig( Constants::MangleTable_Name );
}

void KMFInstallerPlugin::cmdShowRunningConfig( const TQString& para ) {
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}
	
	KMFInstallerInterface *inst2 = rulesetDoc()->target()->installer(); 
	if ( ! inst2 )
		return;
	
	inst2->cmdShowRunningConfig( para );
}


void KMFInstallerPlugin::slotStopFirewall() {
	kdDebug() << "void KMFInstallerPlugin::slotStopFirewall() " << endl;
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}
	

	KMFInstallerInterface *inst2 =  rulesetDoc()->target()->installer(); 
	if ( ! inst2 ) {
		return;
	}
			
	inst2->cmdStopFW();
}

void KMFInstallerPlugin::slotStartFirewall() {
	kdDebug() << "void KMFInstallerPlugin::slotStartFirewall()" << endl;
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}
	if ( rulesetDoc() ) {
		
		KMFInstallerInterface *inst2 =  rulesetDoc()->target()->installer(); 
		if ( ! inst2 ) {
			return;
		}
		inst2->cmdRunFW();
	}
}


void KMFInstallerPlugin::slotInstallFW() {
	kdDebug() << "void KMFInstallerPlugin::slotInstallFW()" << endl;
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}
	
	
	KMFInstallerInterface *inst2 = rulesetDoc()->target()->installer();
	if ( ! inst2 ) {
		return;
	}
	inst2->cmdInstallFW();
}

void KMFInstallerPlugin::slotUninstallFW() {
	kdDebug() << "void KMFInstallerPlugin::slotUninstallFW()" << endl;
	if ( ! isConfigValid() ) {
		const TQString & msg = i18n( "The curemnt target configurations seems to be invalid" );
		const TQString& cap = i18n("Invalid Configuration");
		KMessageBox::error( 0, msg, cap );
		return;
	}

	KMFInstallerInterface *inst2 = rulesetDoc()->target()->installer(); 
	if ( ! inst2 ) {
		return;
	}
	inst2->cmdUninstallFW();
}

void KMFInstallerPlugin::slotGenerateInstallerPackage() {
	kdDebug() << "void KMFInstallerPlugin::slotGenerateInstallPackage()" << endl;
	if ( rulesetDoc() ) {
		KMFTarget* tg = KMFSelectActiveTarget::selectTarget( network(), i18n("<qt><p>Please select target from which the configuration should be exported into an installation package.</p></qt>") );
		
		if ( ! tg ) {
			return;
		}
		
		
	
		if ( ! tg->config()->isValid() ) {
			const TQString & msg = i18n( "The target configurations seems to be invalid" );
			const TQString& cap = i18n("Invalid Configuration");
			KMessageBox::error( 0, msg, cap );
			return;
		}
	
		KMFInstallerInterface *inst2 =  tg->installer(); 
		if ( ! inst2 )
			return;
		
		TQString msg = i18n( "<qt><p>KMyFirewall will create a shell script (*.sh) for you that includes a compressed archieve containing the scripts needed to install the firewall scripts into the boot system of the target computer<br>To install the package make it executabe <b>(e.g. chmod +x mypackage.kmfpkg</b> call the script without any parameter <b>(./mypackage.kmfpkg)</b><br>For other options (e.g. uninstall, extracting etc.) please call the script using the --help parameter <b>(e.g. ./mypackage.kmfpkg --help)</b> to display a detailed option list.</p></qt>" );
		TQString cap = i18n( "Generate Installation Package" );
		KMessageBox::information( 0, msg, cap, "generate_intsllation_package_howto", 0 );
		
		
		KURL url = KFileDialog::getSaveURL( ":", "*.kmfpkg|KMyFirewall Installer Package (*.kmfpkg)"  );

		
		
		
		
		if ( url.fileName().isEmpty() )
			return;
		
		int answer = 0;
		
		if ( KIO::NetAccess::exists( url, false, KApplication::kApplication()->mainWidget() ) ) {
			answer = KMessageBox::warningYesNo( 0, i18n( "<qt>File <b>%1</b> already exists!</p>"
					"<p><b>Overwrite the existing file?</b></p></qt>" ).arg( url.url() ) );
			if ( answer == KMessageBox::No ) {
					return;
			} 
		}
		inst2->generateInstallerPackage( tg, url );
		
		
		
		TQString remPath = url.protocol();
		if ( url.isLocalFile() ) {
			KProcess *proc = new KProcess();
			*proc << "chmod";
			*proc << "700" << url.path();
			proc->start( KProcess::Block );
			delete proc;
			proc = 0;
			kdDebug() << "Set perms for: " << url.path() << endl;
		}
	}

}


void KMFInstallerPlugin::slotEnableActions( bool ) {
// 	if ( on ) {
// 		m_actionStopFw->setEnabled( true );
// 		m_actionRunFw->setEnabled( true );
// 		m_actionPreviewScript->setEnabled( true );
// 		m_actionShowConfig->setEnabled( true );
// 		m_actionShowFilter->setEnabled( true );
// 		m_actionShowNat->setEnabled( true );
// 		m_actionShowMangle->setEnabled( true );
// 		m_actionMenu->setEnabled( true );
// 		m_actionInstallFW->setEnabled( true );
// 		m_actionUninstallFW->setEnabled( true );
// 		m_generateInstallPackage->setEnabled( true );
// 	} else {
// 		m_actionStopFw->setEnabled( false );
// 		m_actionRunFw->setEnabled( false );
// 		m_actionPreviewScript->setEnabled( false );
// /*		m_actionShowConfig->setEnabled( false );
// 		m_actionShowFilter->setEnabled( false );
// 		m_actionShowNat->setEnabled( false );
// 		m_actionShowMangle->setEnabled( false );
// 		m_actionMenu->setEnabled( false );*/
// 		m_actionInstallFW->setEnabled( false );
// 		m_actionUninstallFW->setEnabled( false );
// 		m_generateInstallPackage->setEnabled( false );
// 	}
}


// It's usually safe to leave the factory code alone.. with the
// notable exception of the KAboutData data
#include <kaboutdata.h>
#include <klocale.h>

KInstance* KMFInstallerPluginFactory::s_instance = 0L;

KMFInstallerPluginFactory::KMFInstallerPluginFactory( TQObject* parent, const char* name )
		: KLibFactory( parent, name ) {
	s_instance = new KInstance( "KMFInstallerPluginFactory" );
}



TQObject* KMFInstallerPluginFactory::createObject( TQObject* parent, const char* name,
        const char*, const TQStringList & ) {
	TQObject * obj = new KMFInstallerPlugin( parent, name );
	emit objectCreated( obj );
	return obj;
}


extern "C" {
	void* init_libkmfinstallerplugin() {
		return new KMFInstallerPluginFactory;
	}
}

}
#include "kmfinstallerplugin.moc"
