/*
 * This file is part of the KFTPGrabber project
 *
 * Copyright (C) 2003-2004 by the KFTPGrabber developers
 * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
 * Copyright (C) 2004 Markus Brueffer <markus@brueffer.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.
 *
 * This program is distributed in the hope that it will be useful, but
 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
 * NON-INFRINGEMENT.  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 Steet, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so.  If you
 * do not wish to do so, delete this exception statement from your
 * version.  If you delete this exception statement from all source
 * files in the program, then also delete it here.
 */

#include "widgets/quickconnect.h"
#include "bookmarks/editortls.h"
#include "misc/config.h"
#include "kftpbookmarks.h"
#include "misc.h"

#include "engine/thread.h"
#include "engine/ftpsocket.h"

#include <kglobal.h>
#include <kcharsets.h>
#include <kcombobox.h>
#include <klocale.h>
#include <klineedit.h>
#include <kpassdlg.h>
#include <kmessagebox.h>
#include <kpushbutton.h>

/* KSSL includes */
#include <ksslpkcs12.h>

#include <qcheckbox.h>
#include <qspinbox.h>

using namespace KFTPGrabberBase;

namespace KFTPWidgets {

QuickConnectDialog::QuickConnectDialog(QWidget *parent, const char *name)
 : KDialogBase(parent, name, true, i18n("Quick Connect"), Ok|Cancel, Ok),
   m_noUrlChange(false),
   m_protocolAdvancedDialog(0L),
   m_portChanged(false)
{
  // Create the main widget
  m_layout = new KFTPQuickConnectLayout(this);

  // Set the dialog options
  setMainWidget(m_layout);
  resize(QSize(200,300));

  m_layout->clearRecent->setIconSet(loadSmallIcon("clear_left"));
  m_layout->protoAdvanced->setIconSet(loadSmallIcon("configure"));
  
  // Connect the slots
  connect(m_layout->urlBox, SIGNAL(textChanged(const QString&)), this, SLOT(slotUrlChanged(const QString &)));
  connect(m_layout->hostBox, SIGNAL(textChanged(const QString&)), this, SLOT(slotHostChanged(const QString&)));
  connect(m_layout->protocolBox, SIGNAL(activated(int)), this, SLOT(slotProtocolChanged(int)));
  connect(m_layout->protoAdvanced, SIGNAL(clicked()), this, SLOT(slotProtoAdvancedClicked()));
  connect(m_layout->usernameBox, SIGNAL(textChanged(const QString&)), this, SLOT(slotUserChanged()));
  connect(m_layout->passwordBox, SIGNAL(textChanged(const QString&)), this, SLOT(slotPassChanged()));
  connect(m_layout->portBox, SIGNAL(valueChanged(int)), this, SLOT(slotPortChanged(int)));
  connect(m_layout->anonLogin, SIGNAL(clicked()), this, SLOT(slotAnonClicked()));
  connect(m_layout->recentConnections, SIGNAL(activated(int)), this, SLOT(slotRecentConnectionActivated(int)));
  connect(m_layout->clearRecent, SIGNAL(clicked()), this, SLOT(slotClearRecentClicked()));

  // Init url
  m_url.setProtocol("ftp");
  m_url.setPort(21);
  m_url.setPath("/");
  m_layout->urlBox->setURL(m_url);
  
  // Use anonymous account by default
  m_layout->anonLogin->setChecked(true);
  slotAnonClicked();
  
  // Init the protocol advanced button
  m_layout->protoAdvanced->setEnabled(false);
  
  // Populate charsets
  QStringList charsets = KGlobal::charsets()->descriptiveEncodingNames();
  m_layout->serverEncoding->insertStringList(charsets);
  
  QString defEncoding = KFTPCore::Config::defEncoding();
  defEncoding = QString("%1 ( %2 )").arg(KGlobal::charsets()->languageForEncoding(defEncoding)).arg(defEncoding);
  m_layout->serverEncoding->setCurrentText(defEncoding);
  
  // Populate recent sites
  int index = 0;
  QStringList recentSites = KFTPCore::Config::recentSites();
  for (QStringList::Iterator i = recentSites.begin(); i != recentSites.end(); ++i) {
    KURL siteUrl = KURL(*i);
    
    m_recentSites[index] = siteUrl;
    m_layout->recentConnections->insertItem(siteUrl.prettyURL(), index++);
  }
  
  slotRecentConnectionActivated(0);
}

QuickConnectDialog::~QuickConnectDialog()
{
  if (m_protocolAdvancedDialog)
    delete m_protocolAdvancedDialog;
}

void QuickConnectDialog::slotRecentConnectionActivated(int index)
{
  KURL url = m_recentSites[index];
  m_layout->urlBox->setText(url.url());
  
  if (m_url.user() == "anonymous") {
    m_layout->anonLogin->setChecked(true);
    slotAnonClicked();
  }
}

void QuickConnectDialog::slotClearRecentClicked()
{
  if (KMessageBox::questionYesNo(0, i18n("Clear list of recently accessed sites ?")) == KMessageBox::No)
    return;
  
  m_layout->recentConnections->clear();
  m_recentSites.clear();
  KFTPCore::Config::setRecentSites(QStringList());
}

void QuickConnectDialog::slotUrlChanged(const QString &text)
{
  if (m_noUrlChange)
    return;
  
  m_layout->anonLogin->setChecked(false);
  m_layout->usernameBox->setEnabled(true);
  m_layout->passwordBox->setEnabled(true);
  
  KURL tmpUrl = text;
  if (!tmpUrl.isValid())
    return;
  else
    m_url = tmpUrl;

  m_noUrlChange = true;
  
  if (m_url.protocol() == "ftp")
    m_layout->protocolBox->setCurrentItem(SP_FTP);
  else if (m_url.protocol() == "sftp")
    m_layout->protocolBox->setCurrentItem(SP_SFTP);
  else {
    // Force FTP protocol
    m_url.setProtocol("ftp");
    m_layout->protocolBox->setCurrentItem(SP_FTP);
  }
  
  m_layout->hostBox->setText(m_url.host());
  m_layout->usernameBox->setText(m_url.user());
  
  if (m_url.hasPass()) {
    m_layout->passwordBox->erase();
    m_layout->passwordBox->insert(m_url.pass());
  }
  
  if (m_url.port() == 0) {
    switch (m_layout->protocolBox->currentItem()) {
      case SP_SFTP: {
        m_layout->portBox->setValue(22);
        m_url.setPort(22);
        break;
      }
      default: {
        m_layout->portBox->setValue(21);
        m_url.setPort(21);
        break;
      }
    }
  } else {
    m_layout->portBox->setValue(m_url.port());
  }
  
  m_layout->urlBox->setText(m_url.prettyURL());
  m_noUrlChange = false;
}

void QuickConnectDialog::slotHostChanged(const QString &text)
{
  if (m_noUrlChange) return;

  m_noUrlChange = true;
  m_url.setHost(text);
  m_layout->urlBox->setURL(m_url);
  m_noUrlChange = false;
}

void QuickConnectDialog::slotPortChanged(int port)
{
  if (m_noUrlChange) return;

  m_noUrlChange = true;
  m_url.setPort(port);
  m_layout->urlBox->setURL(m_url);
  m_portChanged = true;
  m_noUrlChange = false;
}

void QuickConnectDialog::slotUserChanged()
{
  if (m_noUrlChange) return;

  m_noUrlChange = true;
  m_url.setUser(m_layout->usernameBox->text());
  m_layout->urlBox->setURL(m_url);
  m_noUrlChange = false;
}

void QuickConnectDialog::slotPassChanged()
{
  if (m_noUrlChange) return;

  m_noUrlChange = true;
  m_url.setPass(m_layout->passwordBox->password());
  m_layout->urlBox->setURL(m_url);
  m_noUrlChange = false;
}

void QuickConnectDialog::slotAnonClicked()
{
  static QString tmpUser, tmpPass;
  
  if (m_layout->anonLogin->isChecked()) {
    m_layout->usernameBox->setEnabled(false);
    m_layout->passwordBox->setEnabled(false);
    tmpUser = m_layout->usernameBox->text();
    tmpPass = m_layout->passwordBox->text();
    m_layout->usernameBox->setText("anonymous");
    m_layout->passwordBox->erase();
    
    // Use the appropriate e-mail address for anonymous accounts
    if (!KFTPCore::Config::anonMail().isEmpty())
      m_layout->passwordBox->insert(KFTPCore::Config::anonMail());
    else
      m_layout->passwordBox->insert("userlogin@anonymo.us");
  } else {
    m_layout->usernameBox->setText(tmpUser);
    m_layout->passwordBox->erase();
    m_layout->passwordBox->insert(tmpPass);
    m_layout->usernameBox->setEnabled(true);
    m_layout->passwordBox->setEnabled(true);
  }
  
  slotUserChanged();
  slotPassChanged();
}

void QuickConnectDialog::slotOk()
{
  // Construct a nice error message
  QString errorMessage;
  
  if (m_url.host().isEmpty())
    errorMessage = i18n("a hostname");
     
  if (m_url.port() < 1)
    errorMessage += (errorMessage.isEmpty() ? QString::null : QString::fromLatin1(", ")) + i18n("a valid port");
  
  if (m_url.user().isEmpty())
    errorMessage += (errorMessage.isEmpty() ? QString::null : QString::fromLatin1(", ")) + i18n("your username");
   
  if (m_url.pass().isEmpty())
    errorMessage += (errorMessage.isEmpty() ? QString::null : QString::fromLatin1(", ")) + i18n("your password");
  
  if (errorMessage.findRev(",") != -1)
    errorMessage = errorMessage.replace(errorMessage.findRev(","), 1 , i18n(" and"));
  
  if (!errorMessage.isEmpty()) {
    KMessageBox::sorry(0, i18n("Please enter ") +  errorMessage + ".");
    return;
  }
  
  if (m_layout->addBookmark->isChecked()) {
    // Add the current connection to bookmarks. Use hostname as the bookmark name.
    KFTPBookmarks::Site *root = KFTPBookmarks::Manager::self()->findCategory("root");
    KFTPBookmarks::Site *site = root->addSite();
    site->setAttribute("name", m_url.host());
    
    site->setProperty("host", m_url.host());
    site->setProperty("port", m_url.port());
    site->setProperty("username", m_url.user());
    site->setProperty("password", encodePassword(m_url.pass()));
    site->setProperty("defremotepath", "/");
    site->setProperty("protocol", m_layout->protocolBox->currentItem() == SP_SFTP ? "sftp" : "ftp");
    site->setProperty("use_tls", m_layout->protocolBox->currentItem() == SP_SSL_EXPLICIT);
    site->setProperty("use_implicit", m_layout->protocolBox->currentItem() == SP_SSL_IMPLICIT);
    site->setProperty("encoding", KGlobal::charsets()->encodingForName(m_layout->serverEncoding->currentText()));
    
    // Save TLS options
    if (m_protocolAdvancedDialog) {
      site->setProperty("tls_data_mode", m_protocolAdvancedDialog->getTLSMode());
      site->setProperty("use_cert", m_protocolAdvancedDialog->isCertChecked());
    
      if (m_protocolAdvancedDialog->isCertChecked())
        site->setProperty("tls_cert_path", m_protocolAdvancedDialog->getCertPath());
    }
    
    KFTPBookmarks::Manager::self()->emitUpdate();
  }
  
  // Save to recent sites
  QStringList recentSites = KFTPCore::Config::recentSites();
  if (m_url.user() == "anonymous")
    m_url.setPass("");
      
  if (recentSites.findIndex(m_url.url()) == -1) {
    recentSites.prepend(m_url.url());
    
    if (recentSites.count() > 10)
      recentSites.pop_back();
  
    KFTPCore::Config::setRecentSites(recentSites);
  }

  // Close the dialog
  accept();
}

void QuickConnectDialog::setupClient(KFTPEngine::Thread *client)
{
  // First activate the correct socket and reset the old flags
  client->selectSocketForProtocol(KURL(QString("%1://test/").arg(m_layout->protocolBox->currentItem() == SP_SFTP ? "sftp" : "ftp")));
  client->socket()->initConfig();
  
  client->socket()->setConfig("retry", 0);
  
  client->socket()->setConfig("ssl.use_tls", m_layout->protocolBox->currentItem() == SP_SSL_EXPLICIT);
  client->socket()->setConfig("ssl.use_implicit", m_layout->protocolBox->currentItem() == SP_SSL_IMPLICIT);
  client->socket()->setConfig("encoding", KGlobal::charsets()->encodingForName(m_layout->serverEncoding->currentText()));
  
  // Set TLS options
  if (m_protocolAdvancedDialog) {
    client->socket()->setConfig("ssl.prot_mode", m_protocolAdvancedDialog->getTLSMode());
  
    // Should we use a X509 certificate ?
    if (m_protocolAdvancedDialog->isCertChecked() && m_layout->protocolBox->currentItem() == SP_FTP) {
      // Ask the user for the decryption password
      QCString certPass;
      KPasswordDialog::getPassword(certPass, i18n("Please provide your X509 certificate decryption password."));

      static_cast<KFTPEngine::FtpSocket*>(client->socket())->setSslClientCertificate(KSSLPKCS12::loadCertFile(m_protocolAdvancedDialog->getCertPath(), certPass));
    }
  }
}

void QuickConnectDialog::slotProtocolChanged(int item)
{
  if (m_noUrlChange) return;
  
  // Enable/Disable the SSL/TLS settings if needed
  m_layout->protoAdvanced->setEnabled( item == SP_SSL_EXPLICIT || item == SP_SSL_IMPLICIT );
  
  // Set the default port
  if (!m_portChanged) {
    switch (item) {
      case SP_SSL_IMPLICIT:
        if (m_layout->portBox->value() == 21 || m_layout->portBox->value() == 22)
          m_layout->portBox->setValue(993);
        break;
      case SP_SFTP:
        if (m_layout->portBox->value() == 21 || m_layout->portBox->value() == 993)
          m_layout->portBox->setValue(22);
        break;
      default:
        if (m_layout->portBox->value() == 22 || m_layout->portBox->value() == 993)
          m_layout->portBox->setValue(21);
        break;
    }
    
    m_portChanged = false;
  }
   
  m_noUrlChange = true;
  m_url.setProtocol( item == SP_SFTP ? "sftp" : "ftp");
  m_url.setPort( m_layout->portBox->value() );
  m_layout->urlBox->setURL(m_url);
  m_noUrlChange = false;
}

void QuickConnectDialog::slotProtoAdvancedClicked()
{
  if (!m_protocolAdvancedDialog)
    m_protocolAdvancedDialog = new KFTPWidgets::Bookmarks::BookmarkEditorTLS(this);
    
  QChar tlsMode = m_protocolAdvancedDialog->getTLSMode();
  bool certChecked = m_protocolAdvancedDialog->isCertChecked();
  QString certPath = m_protocolAdvancedDialog->getCertPath();
  m_protocolAdvancedDialog->slotChangeActiveX509Group();
  
  if (!m_protocolAdvancedDialog->exec()) {
    m_protocolAdvancedDialog->setTLSMode(tlsMode);
    m_protocolAdvancedDialog->setCertChecked(certChecked);
    m_protocolAdvancedDialog->setCertPath(certPath);
    m_protocolAdvancedDialog->slotChangeActiveX509Group();
  }
}

QChar QuickConnectDialog::getTLSMode()
{
  if (!m_protocolAdvancedDialog)
    return false;
    
  return m_protocolAdvancedDialog->getTLSMode();
}

bool QuickConnectDialog::isCertChecked()
{
  if (!m_protocolAdvancedDialog)
    return false;
    
  return m_protocolAdvancedDialog->isCertChecked();
}

QString QuickConnectDialog::getCertPath()
{
  if (!m_protocolAdvancedDialog)
    return QString::null;
    
  return m_protocolAdvancedDialog->getCertPath();
}

int QuickConnectDialog::getFTPMode()
{
  return m_layout->protocolBox->currentItem();
}

void QuickConnectDialog::setHost(const QString &host)
{
  m_layout->hostBox->setText(host);
}

void QuickConnectDialog::setPort(int port)
{
  m_layout->portBox->setValue(port);
}

void QuickConnectDialog::setFocusToUser()
{
  m_layout->usernameBox->setFocus();
}

}

#include "quickconnect.moc"
