/***************************************************************************
** $Id: configdialog.cpp,v 1.51 2008/07/31 19:56:25 hoganrobert Exp $
*   Copyright (C) 2006 - 2008 Robert Hogan                                *
*   robert@roberthogan.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.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
 ***************************************************************************/
//Adapted from configdialog.cpp in amaroK:
/***************************************************************************
begin                : 2004/02/07
copyright            : (C) Mark Kretschmann
email                : markey@web.de
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <tqcombobox.h>
#include <tqgroupbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqlineedit.h>
#include <tqmessagebox.h>
#include <tqobjectlist.h>
#include <tqpushbutton.h>
#include <tqradiobutton.h>
#include <tqspinbox.h>
#include <tqtextcodec.h>
#include <tqtooltip.h>
#include <tqvbox.h>
#include <tqlistview.h>
#include <tqcheckbox.h>

#include <tdeapplication.h> //kapp
#include <kcombobox.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <dcopref.h>
#include <tdeconfig.h>
#include <tdemessagebox.h>

#include "configdialog.h"
#include "konqueror.h"
#include "firewallsproxies.h"
#include "paranoia.h"
#include "maxmin.h"
#include "running.h"
#include "torservers.h"
#include "usability.h"
#include "torkconfig.h"
#include "server.h"
#include "quickconfig.h"
#include "hiddensrvs.h"
#include "portsandnames.h"
#include "tork.h"
#include "crypto.h"


//////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC
//////////////////////////////////////////////////////////////////////////////////////////

TorkConfigDialog::TorkConfigDialog( TQWidget *parent, const char* name, TDEConfigSkeleton *config )
        : TDEConfigDialog( parent, name, config ),m_parent(parent)
{
    setWFlags( WDestructiveClose );

    // IMPORTANT Don't simply change the page names, they are used as identifiers in other parts of the app.
        m_firewallsproxies = new FirewallsProxies( 0, "Firewall/Censor Evasion" );
        m_usability = new Usability( 0, "Usability" );
        m_torservers = new TorServers( 0, "My Network View" );
	    m_maxmin = new MaxMin( 0, "My Server Bandwidth" );
	    m_running = new Running( 0, "My Tor Client" );
        m_myserver = new MyServer( this, "My Tor Server" );
        m_myhidden = new MyHidden( 0, "My Hidden" );
        m_quickconfig = new QuickConfig( 0, "Quick Configure" );
        m_konq = new Konq( 0, "Konqueror" );
        m_filtertable = new FilterTable( 0, "FailSafe" );

    // add pages
    addPage( m_quickconfig, i18n( "Quick Configure" ), "cache", i18n( "Quick Configuration" ) );
#ifndef LIVECD
    addPage( m_konq, i18n( "Konqueror" ), "tork_konqueror_play", i18n( "Konqueror and Privacy Proxy" ) );
#endif

#ifndef LIVECD
    addPage( m_running, i18n( "My Tor Client" ), "launch", i18n( "Configure My Client" ) );
#endif
    addPage( m_firewallsproxies, i18n( "Firewall/Censor Evasion" ), "proxy", i18n( "Configure Firewalls Proxies" ) );

    if (TorkConfig::advancedMode()){
#ifndef LIVECD
#ifdef USE_FAILSAFE
      addPage( m_filtertable, i18n( "FailSafe" ), "gv", i18n( "Configure FailSafe Settings" ) );
#endif
#endif
      addPage( m_usability,   i18n( "Usability" ), "idea", i18n( "Configure Usability" ) );
    }
    if ((!TorkConfig::excludeNodes().isEmpty()) ||
        (!TorkConfig::exitNodes().isEmpty())){
        addPage( m_torservers, i18n( "My Network View" ), "network", 
                 i18n( "Configure My Network View" ) );
    }
    if (!TorkConfig::clientOnly()){
        addPage( m_myserver, i18n( "My Tor Server" ), "computer", i18n( "Configure My Server" ) );
        addPage( m_maxmin, i18n( "My Server Bandwidth" ), "filter", i18n( "Configure My Bandwidth" ) );
    }
    if (!TorkConfig::hiddenServices().isEmpty())
        addPage( m_myhidden, i18n( "My Hidden Services" ), "tork_agent", 
                         i18n( "Configure My Hidden Services" ) );
    

    TQObjectList *list = queryList( "TQLabel", "infoPixmap" );
    for( TQObject *label = list->first(); label; label = list->next() )
        static_cast<TQLabel*>(label)->setPixmap( TQMessageBox::standardIcon( TQMessageBox::Information ) );
    delete list;

    //stop TDEFont Requesters getting stupidly large
    list = queryList( "TQLabel", "m_sampleLabel" );
    for( TQObject *label = list->first(); label; label = list->next() )
        static_cast<TQLabel*>(label)->setMaximumWidth( 250 );
    delete list;

    connect( m_usability->LongLivedPorts, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_torservers->ExitNodes, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_torservers->ExcludeNodes, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_torservers->MapAddress, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_torservers->AllowUnverifiedNodes, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_firewallsproxies->ReachableAddresses, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_filtertable->FilterRules, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_running->SOCKSPolicy, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_running->SOCKSBindAddressMany, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_running->PushAdd, TQ_SIGNAL( clicked() ), this, TQ_SLOT( enableApply() ) );
    connect( m_running->PushAdd2, TQ_SIGNAL( clicked() ), this, TQ_SLOT( enableApply() ) );
    connect( m_myserver->kcfg_ClientOnly, TQ_SIGNAL( toggled(bool) ), this, TQ_SLOT( showServerOpts(bool) ) );
    connect( m_usability->TrackHostExits, TQ_SIGNAL( selectionChanged() ), this, TQ_SLOT( enableApply() ) );
    connect( m_usability->PushAdd, TQ_SIGNAL( clicked() ), this, TQ_SLOT( enableApply() ) );

    connect( m_quickconfig, TQ_SIGNAL( configChanged(const int &) ), this, TQ_SLOT( showHidePages(const int &) ) );
    //connect( m_usability, TQ_SIGNAL(settingsChanged()), TQ_SLOT(updateButtons()) ); 

    // Always apply settings when OK or Apply is pressed.
    //connect( this, TQ_SIGNAL(settingsChanged()), this,
    //               TQ_SLOT(updateCustomSettings()) );
    connect( this, TQ_SIGNAL(okClicked()), this,
                   TQ_SLOT(updateCustomSettings()) );
    connect( this, TQ_SIGNAL(applyClicked()), this,
                   TQ_SLOT(updateCustomSettings()) );
    connect( this, TQ_SIGNAL(updateServerButton( )), parent,
                    TQ_SLOT(updateServerButton( )) );

    connect( m_firewallsproxies, TQ_SIGNAL(uncensorSelected( bool )), parent,
                                 TQ_SLOT(toggleServerButton( bool )) );

    if (TorkConfig::currentTorVersion().left(3) == "0.1"){
        m_filtertable->setEnabled(false);
    }
    showHidePages(m_quickconfig->QuickConfigure->currentItem());

}

void TorkConfigDialog::showHidePages( const int &type )
{
    switch (type) {
            case 0 : //Tor client and server with default settings
            case 1 : //Tor client and relay server with default settings
            case 2 : //Tor client and relay server with default settings
            case 3 : //Tor client and relay server with default settings
            case 4 : //Tor client and relay server with default settings
               m_running->setEnabled(false); 
               m_usability->setEnabled(false); 
               m_torservers->setEnabled(false); 
               m_maxmin->setEnabled(false); 
               m_firewallsproxies->setEnabled(true); 
               m_myserver->setEnabled(false); 
               break;
            case 5 : //Use custom settings
            case 6 : //Use custom settings
            case 7 : //Use custom settings
               m_running->setEnabled(true); 
               m_usability->setEnabled(true); 
               m_torservers->setEnabled(true); 
               m_maxmin->setEnabled(true); 
               m_firewallsproxies->setEnabled(true); 
               m_myserver->ServerInfo->setEnabled(!TorkConfig::clientOnly());
               break;

    }

    show();

}

TorkConfigDialog::~TorkConfigDialog()
{
    emit updateServerButton( );
}

void TorkConfigDialog::showServerOpts( bool state)
{
    m_myserver->ServerInfo->setEnabled(!state);
}


/** Show page by object name */
void TorkConfigDialog::showPage( const TQCString& page )
{
    for( uint index = 0; index < m_pageList.count(); index++ ) {
        if ( m_pageList[index]->name() == page ) {
            TDEConfigDialog::showPage( index );
            return;
        }
    }
}

/** Reimplemented from TDEConfigDialog */
void TorkConfigDialog::addPage( TQWidget *page, const TQString &itemName, const TQString &pixmapName, const TQString &header, bool manage )
{
    // Add the widget pointer to our list, for later reference
    m_pageList << page;

    TDEConfigDialog::addPage( page, itemName, pixmapName, header, manage );
}


void TorkConfigDialog::enableApply()
{
    enableButtonApply(true);
}

void TorkConfigDialog::updateCustomSettings()
{

    kdDebug() << "applied config" << endl;

    //When settings are changed in the config dialog, this is called
    //to update all possibly changed values and apply them to Tor.

    //TQListViews need to be handled outside of tdeconfigxt
    TorkConfig::setQuickConfigure( m_quickconfig->QuickConfigure->currentItem() );

    TorkConfig::setAccountingStart(m_myserver->AccountingStart->currentText());
//     TorkConfig::setStatusFetchPeriodUnit(m_torservers->StatusFetchPeriodUnit->currentText());
//     TorkConfig::setDirFetchPeriodUnit(m_torservers->DirFetchPeriodUnit->currentText());

    //Unverified Servers
    if ( m_torservers->AllowUnverifiedNodes->childCount() > 0 ) {
        TQStringList v_allowUnverifiedNodes;
        TQListViewItemIterator it( m_torservers->AllowUnverifiedNodes, TQListViewItemIterator::Selected );
        while ( it.current() ) {
            v_allowUnverifiedNodes.append(it.current()->text(0));
	        ++it;
        }
        TorkConfig::setAllowUnverifiedNodes( v_allowUnverifiedNodes );
    }

    //Friendly Servers
    if ( m_torservers->MapAddress->childCount() > 0 ) {
        TQStringList v_mapAddress;
        TQListViewItemIterator it( m_torservers->MapAddress );
        while ( it.current() ) {
            TQString s_mapAddress = it.current()->text(0) + " " + it.current()->text(0) + "." +
                it.current()->text(1) + "." + it.current()->text(2);
            v_mapAddress.append(s_mapAddress);
	        ++it;
        }
        TorkConfig::setMapAddress( v_mapAddress );
    }else
        TorkConfig::setMapAddress( "" );

    //Exclude Countries
    TQStringList cclist; 
    for (unsigned int index = 0; index != m_torservers->CountryList->count(); ++index){
        cclist.append(m_torservers->ccode(m_torservers->CountryList->item(index)->text()));
    }
    TorkConfig::setExcludeCountries(cclist);

//     Preferred Countries
//     cclist.clear();
//     for (unsigned int index = 0; index != m_torservers->PreferredCountryList->count(); ++index){
//         cclist.append(m_torservers->ccode(m_torservers->PreferredCountryList->item(index)->text()));
//     }
//     TorkConfig::setPreferredCountries(cclist);

    //Enemy Servers
    if ( m_torservers->ExcludeNodes->childCount() > 0 ) {
        TQStringList v_excludeNodes;
        TQStringList v_excludeServersHistory;
        TQListViewItemIterator it( m_torservers->ExcludeNodes );
        while ( it.current() ) {
            v_excludeNodes.append("$"+getFPFromFPDigest(it.current()->text(2)));
            v_excludeServersHistory.append(it.current()->text(1) + "-" + 
                                           it.current()->text(2) + "-" + it.current()->text(3));
	        ++it;
        }
        TorkConfig::setExcludeNodes( v_excludeNodes );
        TorkConfig::setExcludeServersHistory( v_excludeServersHistory );
    }else{
        TorkConfig::setExcludeNodes( TQStringList() );
        TorkConfig::setExcludeServersHistory( TQStringList() );
    }

    //Exit Servers
    if ( m_torservers->ExitNodes->childCount() > 0 ) {
        TQStringList v_exitNodes;
        TQStringList v_includeServersHistory;
        TQListViewItemIterator it( m_torservers->ExitNodes );
        while ( it.current() ) {
            v_exitNodes.append("$"+getFPFromFPDigest(it.current()->text(2)));
            v_includeServersHistory.append(it.current()->text(1) + "-" + 
                                           it.current()->text(2) + "-" + it.current()->text(3));

	        ++it;
        }
        TorkConfig::setExitNodes( v_exitNodes );
        TorkConfig::setIncludeServersHistory( v_includeServersHistory );
    }else{
        TorkConfig::setExitNodes( TQStringList() );
        TorkConfig::setIncludeServersHistory( TQStringList() );
    }

    //Family Servers
    if ( m_myserver->MyFamily->childCount() > 0 ) {
        TQStringList v_myFamily;
        TQListViewItemIterator it( m_myserver->MyFamily, TQListViewItemIterator::Selected );
        while ( it.current() ) {
            v_myFamily.append(it.current()->text(1) + "-" + 
                              it.current()->text(2) + "-" + it.current()->text(3));
	        ++it;
        }
        TorkConfig::setMyFamily( v_myFamily );
    }else{
        TorkConfig::setMyFamily( TQStringList() );
    }

    //Track Host Exits
    if ( m_usability->TrackHostExits->childCount() > 0 ) {
        TQStringList v_trackHostExits;
        TQListViewItemIterator it( m_usability->TrackHostExits );
        while ( it.current() ) {
            v_trackHostExits.append(it.current()->text(0));
	        ++it;
        }
        TorkConfig::setTrackHostExits( v_trackHostExits );
    }else
        TorkConfig::setTrackHostExits( "" );

    //Long Lived Ports
    if ( m_usability->LongLivedPorts->childCount() > 0 ) {
        TQStringList v_longLivedPorts;
        TQListViewItemIterator it( m_usability->LongLivedPorts, TQListViewItemIterator::Selected );
        while ( it.current() ) {
            int i;
            for (i = 0; _port_name[i].port; ++i) {
                portsandnames_t *pics = &_port_name[i];
                if (it.current()->text(0) == pics->name){
                    v_longLivedPorts.append(pics->port);
                }
            }

	        ++it;
        }
        TorkConfig::setLongLivedPorts( v_longLivedPorts );
    }

    //Socks Bind Addresses
    if ( m_running->SOCKSBindAddressMany->childCount() > 0 ) {
        TQStringList v_sOCKSBindAddressMany;
        TQListViewItemIterator it( m_running->SOCKSBindAddressMany );
        while ( it.current() ) {
            TQString s_sOCKSBindAddressMany = it.current()->text(0) + ":" + it.current()->text(1);
            v_sOCKSBindAddressMany.append(s_sOCKSBindAddressMany);
	        ++it;
        }
        TorkConfig::setSOCKSBindAddressMany( v_sOCKSBindAddressMany );
    }else
        TorkConfig::setSOCKSBindAddressMany( "" );

    //Exit Policy
    if ( m_myserver->ExitPolicy->childCount() > 0 ) {
        TQStringList v_exitPolicy;
        TQListViewItemIterator it( m_myserver->ExitPolicy );
        while ( it.current() ) {
            TQString s_exitPolicy = it.current()->text(0) + " " + it.current()->text(1) + ":" + it.current()->text(2);
            v_exitPolicy.append(s_exitPolicy);
	        ++it;
        }
        TorkConfig::setExitPolicy( v_exitPolicy );
    }else
        TorkConfig::setExitPolicy( "" );

    //Socks Policy
    if ( m_running->SOCKSPolicy->childCount() > 0 ) {
        TQStringList v_sOCKSPolicy;
        TQListViewItemIterator it( m_running->SOCKSPolicy );
        while ( it.current() ) {
            TQString s_sOCKSPolicy = it.current()->text(0) + " " + it.current()->text(1) + ":" + it.current()->text(2);
            v_sOCKSPolicy.append(s_sOCKSPolicy);
	        ++it;
        }
        TorkConfig::setSOCKSPolicy( v_sOCKSPolicy );
    }else
        TorkConfig::setSOCKSPolicy( "" );

    //Filter Rules
    if ( m_filtertable->FilterRules->childCount() > 0 ) {
        TQStringList v_filterRules;
        TQListViewItemIterator it( m_filtertable->FilterRules );
        while ( it.current() ) {
            TQString s_filterRules = it.current()->text(0) + "%:%" + it.current()->text(1)+ "%:%" + it.current()->text(2);
            v_filterRules.append(s_filterRules);
	        ++it;
        }
        TorkConfig::setFilterRules( v_filterRules );
    }else
        TorkConfig::setFilterRules( "" );

    //Reachable Address
    if ( m_firewallsproxies->ReachableAddresses->childCount() > 0 ) {
        TQStringList v_reachableAddresses;
        TQListViewItemIterator it( m_firewallsproxies->ReachableAddresses );
        while ( it.current() ) {
            TQString s_reachableAddresses = "*:" + it.current()->text(0);
            v_reachableAddresses.append(s_reachableAddresses);
	        ++it;
        }
        TorkConfig::setReachableAddresses( v_reachableAddresses );
    }else
        TorkConfig::setReachableAddresses( "" );

    //Bridge Addresses
    if ( m_firewallsproxies->Bridge->childCount() > 0 ) {
        TQStringList v_bridges;
        TQListViewItemIterator it( m_firewallsproxies->Bridge );
        while ( it.current() ) {
            TQString s_bridges = it.current()->text(0) + ":" + it.current()->text(1)
                                + " " + it.current()->text(2);
            v_bridges.append(s_bridges);
	        ++it;
        }
        TorkConfig::setBridge( v_bridges );
    }else
        TorkConfig::setBridge( TQStringList() );

    //Hidden Services
//     if ( m_myhidden->servicesList->childCount() > 0 ) {
//         TQStringList v_hiddenServices;
//         TQListViewItemIterator it( m_myhidden->servicesList );
//         while ( it.current() ) {
//             TQString s_hiddenServices = it.current()->text(0) + "\n" + it.current()->text(1)
//                                         + "\n" + it.current()->text(2) + "\n" + it.current()->text(3)
//                                         + "\n" + it.current()->text(4)+ "\n" + it.current()->text(5);
//             v_hiddenServices.append(s_hiddenServices);
// 	        ++it;
//         }
//         TorkConfig::setHiddenServices( v_hiddenServices );
//     }else
//         TorkConfig::setHiddenServices( "" );

    //Bandwidth Slots
    if ( m_maxmin->timedBandwidthList->childCount() > 0 ) {
        TQStringList v_bandwidthSlots;
        TQListViewItemIterator it( m_maxmin->timedBandwidthList );
        while ( it.current() ) {
            TQString s_bandwidthSlots = it.current()->text(0) + "\n" + it.current()->text(1)
                                        + "\n" + it.current()->text(2) + "\n" + it.current()->text(3)
                                        + "\n" + it.current()->text(4);
            v_bandwidthSlots.append(s_bandwidthSlots);
	        ++it;
        }
        TorkConfig::setBandwidthSlots( v_bandwidthSlots );
    }else
        TorkConfig::setBandwidthSlots( "" );

    // If we are to use bridges then TunnelDirConns must be set as well.
    if (m_firewallsproxies->kcfg_UseBridges->isChecked())
      TorkConfig::setTunnelDirConns(true);
    else
      TorkConfig::setTunnelDirConns(false);

    TorkConfig::writeConfig();


    //If you're going to disable this again, explain why here. You have a crap
    //memory.
    //emit settingsChanged(); 
    static_cast<tork*>(m_parent)->applySettingsToRunningTor();
}




#include "configdialog.moc"
