/*
  Copyright (c) 2002 Laurent Montel <lmontel@mandrakesoft.com>
  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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <unistd.h>

#include <tqlayout.h>
#include <tqvbuttongroup.h>
#include <tqvgroupbox.h> 
#include <tqlabel.h>
#include <tqdir.h>
#include <tqradiobutton.h>
#include <tqcheckbox.h>
#include <tqtooltip.h>
#include <tqvbox.h>

#include <kpushbutton.h>
#include <kdebug.h>
#include <kdialog.h>
#include <kdialogbase.h>
#include <kgenericfactory.h>
#include <tdelistview.h>
#include <kiconloader.h>
#include <knfsshare.h>
#include <ksambashare.h>
#include <tdefileshare.h>
#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <tdemessagebox.h>
#include <tdeapplication.h>
#include <kuser.h>
#include <kurl.h>
#include <kprocess.h>
#include <krichtextlabel.h>

#include "../advanced/propsdlgplugin/propertiespage.h"
#include "../advanced/nfs/nfsfile.h"
#include "../advanced/kcm_sambaconf/sambafile.h"

#include "controlcenter.h"
#include "fileshare.h"
#include "groupconfigdlg.h"

typedef KGenericFactory<KFileShareConfig, TQWidget > ShareFactory;
K_EXPORT_COMPONENT_FACTORY (kcm_fileshare, ShareFactory("kcmfileshare") )


#define FILESHARECONF "/etc/security/fileshare.conf"
#define FILESHARE_DEBUG 5009

KFileShareConfig::KFileShareConfig(TQWidget *parent, const char *name, const TQStringList &):
    TDECModule(ShareFactory::instance(), parent, name)
{
  TDEGlobal::locale()->insertCatalogue("tdefileshare");                            

  TQBoxLayout* layout = new TQVBoxLayout(this,0,
				       KDialog::spacingHint());

/*  
  TQVButtonGroup *box = new TQVButtonGroup( i18n("File Sharing"), this );
  box->layout()->setSpacing( KDialog::spacingHint() );
  layout->addWidget(box);
  noSharing=new TQRadioButton( i18n("Do &not allow users to share files"), box );
  sharing=new TQRadioButton( i18n("&Allow users to share files from their HOME folder"),  box);
*/
  m_ccgui = new ControlCenterGUI(this);
  connect( m_ccgui, TQT_SIGNAL( changed()), this, TQT_SLOT(configChanged()));
  connect( m_ccgui->allowedUsersBtn, TQT_SIGNAL( clicked()), 
           this, TQT_SLOT(allowedUsersBtnClicked()));

  TQString path = TQString::fromLocal8Bit( getenv( "PATH" ) );
  path += TQString::fromLatin1(":/usr/sbin");
  TQString sambaExec = TDEStandardDirs::findExe( TQString::fromLatin1("smbd"), path );
  TQString nfsExec = TDEStandardDirs::findExe( TQString::fromLatin1("rpc.nfsd"), path );

  if ( nfsExec.isEmpty() && sambaExec.isEmpty())
  {
      TQMessageBox::critical( 0, "File Sharing", TQString("SMB and NFS servers are not installed on this machine, to enable this module the servers must be installed."));
      m_ccgui->shareGrp->setDisabled(true);
      m_ccgui->sharedFoldersGroupBox->setDisabled(true);
  }
  else
  {   
      if (nfsExec.isEmpty()) {
        m_ccgui->nfsChk->setDisabled(true);
        m_ccgui->nfsChk->setChecked(false);
        TQToolTip::add(m_ccgui->nfsChk,i18n("No NFS server installed on this system"));
      } 
      
      if (sambaExec.isEmpty()) {
        m_ccgui->sambaChk->setDisabled(true);
        m_ccgui->sambaChk->setChecked(false);
        TQToolTip::add(m_ccgui->sambaChk,i18n("No Samba server installed on this system"));
      }
          
      m_ccgui->infoLbl->hide();      
      layout->addWidget(m_ccgui);
      updateShareListView();
      connect( KNFSShare::instance(), TQT_SIGNAL( changed()), 
               this, TQT_SLOT(updateShareListView()));
      connect( KSambaShare::instance(), TQT_SIGNAL( changed()), 
               this, TQT_SLOT(updateShareListView()));

               
  }
  
  if((getuid() == 0) || 
     ((KFileShare::shareMode() == KFileShare::Advanced) &&
      (KFileShare::authorization() == KFileShare::Authorized)))
  {
      connect( m_ccgui->addShareBtn, TQT_SIGNAL(clicked()),
               this, TQT_SLOT(addShareBtnClicked()));
      connect( m_ccgui->changeShareBtn, TQT_SIGNAL(clicked()),
               this, TQT_SLOT(changeShareBtnClicked()));
      connect( m_ccgui->removeShareBtn, TQT_SIGNAL(clicked()),
               this, TQT_SLOT(removeShareBtnClicked()));
      m_ccgui->listView->setSelectionMode(TQListView::Extended);       
      m_ccgui->shareBtnPnl->setEnabled(true);        
  }
  
  
  if (getuid()==0) {               
      setButtons(Help|Apply);
  } else {
      setButtons(Help);
      m_ccgui->shareGrp->setDisabled( true );
  }

  load();
}

void KFileShareConfig::updateShareListView() 
{
      m_ccgui->listView->clear();
      KNFSShare* nfs = KNFSShare::instance();
      KSambaShare* samba = KSambaShare::instance();
      
      TQStringList dirs = nfs->sharedDirectories();
      TQStringList sambaDirs = samba->sharedDirectories();
      
      for ( TQStringList::ConstIterator it = sambaDirs.begin(); it != sambaDirs.end(); ++it ) {
        // Do not insert duplicates
        if (nfs->isDirectoryShared(*it))
            continue;
            
        dirs += *it;            
      }

      TQPixmap folderPix = SmallIcon("folder",0,TDEIcon::ShareOverlay);
      TQPixmap okPix = SmallIcon("button_ok");
      TQPixmap cancelPix = SmallIcon("button_cancel");
      
      for ( TQStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it ) {
        TDEListViewItem* item = new TDEListViewItem(m_ccgui->listView);
        item->setText(0,*it);
        item->setPixmap(0, folderPix);
        
        if (samba->isDirectoryShared(*it))
          item->setPixmap(1,okPix);
        else 
          item->setPixmap(1,cancelPix);
          
        if (nfs->isDirectoryShared(*it))
          item->setPixmap(2,okPix);
        else          
          item->setPixmap(2,cancelPix);

      }
      
}

void KFileShareConfig::allowedUsersBtnClicked() {
  GroupConfigDlg dlg(this,m_fileShareGroup,m_restricted,m_rootPassNeeded,
                     m_ccgui->simpleRadio->isChecked());
  if (dlg.exec() == TQDialog::Accepted) {
      m_fileShareGroup = dlg.fileShareGroup().name();
      m_restricted = dlg.restricted();
      m_rootPassNeeded = dlg.rootPassNeeded();      
      configChanged();
  }      

}


void KFileShareConfig::load()
{
    KSimpleConfig config(TQString::fromLatin1(FILESHARECONF),true);

    m_ccgui->shareGrp->setChecked( config.readEntry("FILESHARING", "yes") == "yes" );
    
    m_restricted = config.readEntry("RESTRICT", "yes") == "yes";
    
    if (config.readEntry("SHARINGMODE", "simple") == "simple")
        m_ccgui->simpleRadio->setChecked(true);
    else        
        m_ccgui->advancedRadio->setChecked(true);
          
    m_fileShareGroup = config.readEntry("FILESHAREGROUP", "fileshare");

    m_ccgui->sambaChk->setChecked( 
          config.readEntry("SAMBA", "yes") == "yes");

    m_ccgui->nfsChk->setChecked( 
          config.readEntry("NFS", "yes") == "yes");

    m_rootPassNeeded = config.readEntry("ROOTPASSNEEDED", "yes") == "yes";
                    
    m_smbConf = KSambaShare::instance()->smbConfPath();
}

bool KFileShareConfig::addGroupAccessesToFile(const TQString & file) {
  TDEProcess chgrp;
  chgrp << "chgrp" << m_fileShareGroup << file;
  TDEProcess chmod;
  chmod << "chmod" << "g=rw" << file;
  
  if (!chgrp.start(TDEProcess::Block) && chgrp.normalExit()) {
      kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::addGroupAccessesToFile: chgrp failed" << endl;
      return false;
      
  }      
      
  if(!chmod.start(TDEProcess::Block) && chmod.normalExit()) {
      kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::addGroupAccessesToFile: chmod failed" << endl;
      return false;
  }
  
  return true;
  
}

bool KFileShareConfig::removeGroupAccessesFromFile(const TQString & file) {
  TDEProcess chgrp;
  chgrp << "chgrp" << "root" << file;
  TDEProcess chmod;
  chmod << "chmod" << "g=r" << file;
  
  if (!chgrp.start(TDEProcess::Block) && chgrp.normalExit()) {
      kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::removeGroupAccessesFromFile: chgrp failed" << endl;
      return false;
      
  }      
      
  if(!chmod.start(TDEProcess::Block) && chmod.normalExit()) {
      kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::removeGroupAccessesFromFile: chmod failed" << endl;
      return false;
  }
  
  return true;
}  


bool KFileShareConfig::setGroupAccesses() {
  if (m_rootPassNeeded || ! m_ccgui->sambaChk->isChecked()) {
      if (!removeGroupAccessesFromFile(KSambaShare::instance()->smbConfPath()))
          return false;
  }
  
  if (m_rootPassNeeded || ! m_ccgui->nfsChk->isChecked()) {          
      if (!removeGroupAccessesFromFile(KNFSShare::instance()->exportsPath()))
          return false;
  }
  
  if (! m_rootPassNeeded && m_ccgui->sambaChk->isChecked()) {
      if (!addGroupAccessesToFile(KSambaShare::instance()->smbConfPath()))
          return false;
  }

  if (! m_rootPassNeeded && m_ccgui->nfsChk->isChecked()) {
      if (!addGroupAccessesToFile(KNFSShare::instance()->exportsPath()))
          return false;
  }
  

  return true;
}

void KFileShareConfig::save()
{
    setGroupAccesses();

    TQDir dir("/etc/security");
    if ( !dir.exists())
        dir.mkdir("/etc/security");

    TQFile file(FILESHARECONF);
    if ( ! file.open(IO_WriteOnly)) {
        KMessageBox::detailedError(this, 
            i18n("Could not save settings."),
            i18n("Could not open file '%1' for writing: %2").arg(FILESHARECONF).arg(
             file.errorString() ),
            i18n("Saving Failed"));
        return;
    }        
        
    
    TQTextStream stream(&file);
    
    stream << "FILESHARING=";
    stream << (m_ccgui->shareGrp->isChecked() ? "yes" : "no");        
    
    stream << "\nRESTRICT=";
    stream << (m_restricted ? "yes" : "no");        
        
    stream << "\nSHARINGMODE=";
    stream << (m_ccgui->simpleRadio->isChecked() ? "simple" : "advanced");        

    stream << "\nFILESHAREGROUP=";
    stream << m_fileShareGroup;    
    
    stream << "\nSAMBA=";
    stream << (m_ccgui->sambaChk->isChecked() ? "yes" : "no");        
        
    stream << "\nNFS=";
    stream << (m_ccgui->nfsChk->isChecked() ? "yes" : "no");        
                
    stream << "\nROOTPASSNEEDED=";
    stream << (m_rootPassNeeded ? "yes" : "no");        
    
    stream << "\nSMBCONF=";
    stream << m_smbConf;
    
    file.close();
}

void KFileShareConfig::defaults()
{
    m_ccgui->shareGrp->setChecked( false );
}

TQString KFileShareConfig::quickHelp() const
{
    return i18n("<h1>File Sharing</h1><p>This module can be used "
    		    "to enable file sharing over the network using "
				"the \"Network File System\" (NFS) or SMB in Konqueror. "
				"The latter enables you to share your files with Windows(R) "
				"computers on your network.</p>");
}

void KFileShareConfig::addShareBtnClicked() {
  showShareDialog(KFileItemList());
}


PropertiesPageDlg::PropertiesPageDlg(TQWidget*parent, KFileItemList files)
  : KDialogBase(parent, "sharedlg", true,
                i18n("Share Folder"), Ok|Cancel, Ok, true)
{
  TQVBox* vbox = makeVBoxMainWidget();
  
  m_page = new PropertiesPage(vbox,files,true);
}  

bool PropertiesPageDlg::hasChanged() {
  return m_page->hasChanged();
}

void PropertiesPageDlg::slotOk() {
  if (hasChanged()) {
    if (!m_page->save())
        return;
  }

  KDialogBase::slotOk();
}



void KFileShareConfig::showShareDialog(const KFileItemList & files) {
  PropertiesPageDlg* dlg = new PropertiesPageDlg(this,files);              
  if (dlg->exec() == TQDialog::Accepted) {
    if ( dlg->hasChanged() ) {
         updateShareListView();
    }
  }  
  delete dlg;
}

void KFileShareConfig::changeShareBtnClicked() {
  KFileItemList files;
  TQPtrList<TQListViewItem> items = m_ccgui->listView->selectedItems();
  
  TQListViewItem* item;
  for ( item = items.first(); item; item = items.next() ) {
      files.append(new KFileItem(KURL::fromPathOrURL(item->text(0)),"",0));
  }
  
  showShareDialog(files);
}

void KFileShareConfig::removeShareBtnClicked() {
  
  TQPtrList<TQListViewItem> items = m_ccgui->listView->selectedItems();
  TQListViewItem *item;
  
  bool nfs = false;
  bool samba = false;
  
  for ( item = items.first(); item; item = items.next() ) {
      
      if (KNFSShare::instance()->isDirectoryShared(item->text(0)))
          nfs = true;
  
      if (KSambaShare::instance()->isDirectoryShared(item->text(0)))
          samba = true;
  }

  NFSFile nfsFile(KNFSShare::instance()->exportsPath());
  if (nfs) {
    kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::removeShareBtnClicked: nfs = true" << endl;
    nfsFile.load();
    for ( item = items.first(); item; item = items.next() ) {
        nfsFile.removeEntryByPath(item->text(0));
    }
  }
  
  SambaFile smbFile(KSambaShare::instance()->smbConfPath(),false);
  if (samba) {
    kdDebug(FILESHARE_DEBUG) << "KFileShareConfig::removeShareBtnClicked: samba = true" << endl;  
    smbFile.load();
    for ( item = items.first(); item; item = items.next() ) {
        smbFile.removeShareByPath(item->text(0));
    }
  }    

  PropertiesPage::save(&nfsFile, &smbFile, nfs,samba);
    
  updateShareListView();
}

#include "fileshare.moc"