/**********************************************************************

	--- TQt Architect generated file ---

	File: open_ksirc.cpp
	Last generated: Wed Jul 29 16:41:26 1998

 *********************************************************************/

#include "open_ksirc.h"
#include "serverDataType.h"
#include "serverFileParser.h"
#include "enter_combo.h"
#include "../ksircserver.h"
#include <tqlistbox.h>
#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqcheckbox.h>
#include <tqdict.h>
#include <stdlib.h>
#include <unistd.h>

#include <kdebug.h>
#include <tdeapplication.h>
#include <tdestandarddirs.h>
#include <tdelocale.h>
#include <tdeconfig.h>
#include <tdemessagebox.h>
#include <kmdcodec.h>

TQPtrList<Server> Groups;

#undef Inherited
#define Inherited open_ksircData

open_ksirc::open_ksirc
(
	TQWidget* parent,
	const char* name
)
	:
	Inherited( parent, name, true )
{
  setCaption( i18n("Connect to Server") );

  // check for existance of ~/.trinity/share/apps/ksirc/servers.txt
  // if it don't exist use $TDEDIR/share/apps/ksirc/servers.txt
  // changes are written to ~/.trinity/share/apps/ksirc/servers.txt

  TQString filename = locate("appdata", "servers.txt");
  serverFileParser::readDatafile( filename.ascii() );

  Groups.setAutoDelete(true);

  // TODO add "Recent" to global listing servers here..
  // Now we read in the Recent group from the config file
  // remove all recent servers first

  for(Server *s = Groups.first(); s != 0x0; s = Groups.next()){
    if(s->group() == i18n("Recent")){
      Groups.remove();
    }
  }

  // Add current ones
  TDEConfig *conf = tdeApp->config();
  conf->setGroup("ServerList");
  CheckB_StorePassword->setChecked( conf->readBoolEntry("StorePasswords") );
  TQStringList recent = conf->readListEntry("RecentServers");
  for(TQStringList::ConstIterator it = recent.begin(); it != recent.end(); ++it){
      if(conf->hasGroup("RecentServer-" + *it)){
          conf->setGroup("RecentServer-" + *it);
	  TQPtrList<port> rp;
          rp.inSort(new port(conf->readEntry("Port", "6667")));
          TQString password = decryptPassword(conf->readEntry("Password"));
          bool ssl = conf->readBoolEntry("SSL");
          Groups.insert(0, new Server(i18n("Recent"), *it, rp,
                                      i18n("Recent Server"), "", password,
                                      ssl));
      }
      else {
          TQStringList info = TQStringList::split(":", *it);
          if (info.isEmpty())
              continue;
          TQString name = info[0];
          TQPtrList<port> rp;
          if (info.count() > 1)
              rp.inSort(new port(info[1]));
          else
              rp.inSort(new port("6667"));
          TQString password;
          if (info.count() > 2)
              password = decryptPassword(info[2]);

          conf->setGroup("RecentServer-" + name);
          conf->writeEntry("Port", rp.first()->portnum());
          conf->writeEntry("Password", encryptPassword(password));
          conf->writeEntry("SSL", false);

          Groups.insert(0, new Server(i18n("Recent"), name, rp,
                                      i18n("Recent Server"), "", password));
      }
  }

  ComboB_ServerName->setAutoCompletion( true );
  ComboB_ServerPort->setAutoCompletion( true );

  insertGroupList();

  TQString blah = i18n("Recent");
  setGroup(blah);

  connect(ComboB_ServerGroup, TQ_SIGNAL(activated( const TQString& )),
          this, TQ_SLOT(setGroup( const TQString& )));
  connect(ComboB_ServerName,  TQ_SIGNAL(activated( const TQString& )),
          this, TQ_SLOT(setServer( const TQString& )));

  connect(PB_Connect, TQ_SIGNAL(clicked()), this, TQ_SLOT(clickConnect()));
  connect(PB_Edit, TQ_SIGNAL(clicked()), this, TQ_SLOT(clickEdit()));
  connect(PB_Cancel, TQ_SIGNAL(clicked()), this, TQ_SLOT(clickCancel()));

  PB_Connect->setDefault(true);
  PB_Connect->setAutoDefault(true);
  PB_Edit->setEnabled(false); // Not yet implemented.

  ComboB_ServerName->setFocus();
  connect(ComboB_ServerName, TQ_SIGNAL(enterPressed()), this, TQ_SLOT(clickConnect()));
}

// insert a sorted list of groups into ComboB_ServerGroup, note that
// we want to get the recent servers in first so we insert "Recent"
// in first, then we want Random.

void open_ksirc::insertGroupList()
{
  TQStrList tempgroups;
  Server *serv;

  for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
      if (tempgroups.find(serv->group().ascii()) == -1)
          tempgroups.inSort( serv->group().ascii() );
  }

  ComboB_ServerGroup->insertItem(i18n( "Recent") );
  ComboB_ServerGroup->insertItem(i18n( "Random") );
  for (const char* t = tempgroups.first(); t; t = tempgroups.next()) {
      ComboB_ServerGroup->insertItem( t );
  }
}

// insert a sorted list of servers from the group passed as an arg
// into ComboB_ServerName, if a list is already there delete it.
// note this does not check for multiple occurrances of the same server

void open_ksirc::insertServerList( const char * group )
{
  TQListBox *newListBox = new TQListBox();
  Server *serv;

  for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
      if ( !qstrcmp(serv->group().ascii(), group) ) {
          newListBox->insertItem( serv->server(), 0 );
      }
  }

  ComboB_ServerName->setListBox(newListBox);
//  ComboB_ServerName->setCurrentItem( 0 ); // this don't work =(
  if (newListBox->count() > 0)
      ComboB_ServerName->setEditText( newListBox->text( 0 ) );
}

// insert a sorted list of ports from the server passed as an arg
// into ComboB_ServerPort, if a list is already there delete it.
// note that this only takes the first occurrance if there is two
// entiies with the same server.

void open_ksirc::setServer( const TQString &serveraddress )
{
  TQListBox *newListBox  = new TQListBox();
  Server *serv;
  TQPtrList<port> portlist;
  port *p;
  bool defaultport = false;

  for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
    if (serv->server() == serveraddress) {
      setServerDesc( serv->serverdesc() );
      portlist = serv->ports();
      for ( p=portlist.last(); p != 0; p=portlist.prev() ) {
        newListBox->insertItem( p->portnum() );
        if (strcmp(p->portnum().ascii(), "6667") == 0)
          defaultport = true;
      }
      LineE_Password->setText( serv->password() );
      CheckB_StorePassword->setEnabled( !serv->password().isEmpty() );
      CheckB_UseSSL->setChecked(serv->usessl());
      break;
    }
  }
  ComboB_ServerPort->setListBox(newListBox);
//  ComboB_ServerPort->setCurrentItem( 0 ); // doesn't work
  if (defaultport) {
    ComboB_ServerPort->setEditText("6667");
  } else {
    if (newListBox->count() > 0)
      ComboB_ServerPort->setEditText( newListBox->text( 0 ) );
  }
}

// Sets the server description if the isn't one set it to "Not Available"

void open_ksirc::setServerDesc( TQString description )
{
  if (description.isNull() || description.isEmpty()) {
    Label_ServerDesc->setText( i18n("Not available"));
  } else {
    Label_ServerDesc->setText( description );
  }
}

// This has got nothing to do with real encryption, it just scrambles
// the password a little bit for saving it into the config file.
// A random string of the same length as the password in UTF-8 is generated
// and then each byte of the UTF-8 password is xored with the corresponding
// byte of the random string. The returned value is a base64 encoding of
// that random string followed by the scrambled password.
TQString open_ksirc::encryptPassword( const TQString &password )
{
  TQCString utf8 = password.utf8();
  // Can contain NULL bytes after XORing
  unsigned int utf8Length(utf8.length());
  TQByteArray result(utf8Length << 1);
  memcpy(result.data(), tdeApp->randomString(utf8Length).latin1(), utf8Length);
  for (unsigned int i = 0; i < utf8Length; ++i)
    result[i + utf8Length] = utf8[i] ^ result[i];
  return TQString::fromLatin1(KCodecs::base64Encode(result));
}

TQString open_ksirc::decryptPassword( const TQString &scrambled )
{
  TQByteArray base64, orig;
  base64.duplicate(scrambled.latin1(), scrambled.length());
  KCodecs::base64Decode(base64, orig);
  TQCString result;
  for (unsigned int i = 0; i < (orig.size() >> 1); ++i)
    result += orig[i] ^ orig[i + (orig.size() >> 1)];
  return TQString::fromUtf8(result);
}

void open_ksirc::setGroup( const TQString &group )
{
  insertServerList( group.ascii() );
  if (ComboB_ServerName->count() > 0) {
    TQString blah = TQString(ComboB_ServerName->text( 0 ));
    setServer(blah);
  } else {
    setServerDesc( "" );
    ComboB_ServerPort->setEditText("6667");
    ComboB_ServerPort->insertItem("6667");
  }
  if(ComboB_ServerPort->currentText() == 0x0){
      ComboB_ServerPort->setEditText("6667");
      ComboB_ServerPort->insertItem("6667");
  }
}

void open_ksirc::clickConnect()
{
  if ( ComboB_ServerName->currentText().isEmpty() )
  {
    KMessageBox::information( this, i18n( "Please enter a server name." ) );
    return;
  }

  TQString server;
  TQString port;
  TQString script;
  Server *serv;
  TDEConfig *conf = tdeApp->config();

  hide();

  server = ComboB_ServerName->currentText();
  port = ComboB_ServerPort->currentText();

  for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
    if (strcmp(serv->server().ascii(), server.ascii()) == 0) {
      script = serv->script();
    }
    break;
  }

  if(server.length() == 0)
    reject();

  if(port.isEmpty())
    port = "6667";

  TQString plain, scrambled;
  if (!LineE_Password->text().isEmpty())
  {
      plain = LineE_Password->text();
      if (CheckB_StorePassword->isChecked())
	  scrambled = encryptPassword(LineE_Password->text());
  }

  conf->setGroup("ServerList");
  conf->writeEntry("StorePasswords", CheckB_StorePassword->isChecked());
  TQStringList recent = conf->readListEntry("RecentServers");
  if(recent.contains(server)){
      TQStringList::Iterator it = recent.find(server);
      recent.remove(it);
  }

  /*
   * This is legacy code only
   */
  //str is now "server:port"
  //plain is now "server:port" or "server:port:pass" if a password was entered
  //scrambled is now "server:port" or "server:port:scrambledpass" if
  //a password was given and "store password" is checked

  for (TQStringList::Iterator it = recent.begin(); it != recent.end(); ) {
      if ((*it).startsWith(server)) // ignore password
      {
	  TQStringList::Iterator del = it++;
	  recent.remove(del);
      }
      else
	  ++it;
  }

  recent.prepend(server);
  conf->writeEntry("RecentServers", recent);

  conf->setGroup("RecentServer-" + server);
  conf->writeEntry("Port", port);
  conf->writeEntry("Password", scrambled);
  conf->writeEntry("SSL", CheckB_UseSSL->isChecked());

  conf->sync();

  KSircServer kss(server,
		  port,
		  script,
		  plain,
		  CheckB_UseSSL->isChecked());

  //  emit open_ksircprocess( server, port, script );
  emit open_ksircprocess(kss);

  accept();
}

void open_ksirc::clickCancel()
{
  reject();
}

void open_ksirc::clickEdit()
{
  // TODO open new server editor
}

void open_ksirc::passwordChanged( const TQString& password )
{
  CheckB_StorePassword->setEnabled( !password.isEmpty() );
}

open_ksirc::~open_ksirc()
{
  Groups.clear();
}

#include "open_ksirc.moc"
