//////////////////////////////////////////////////////////////////////
//      $Id: kpPty.cpp,v 1.26.2.1 2002/12/13 15:20:22 toivo Exp $ 
// File  : kpackage.cpp
// Author: Toivo Pedaste
// 
//////////////////////////////////////////////////////////////////////

#include "../config.h"
#include <stdlib.h>     

#include <kpPty.h>
#include <kpackage.h>
#include <kpTerm.h>
#include <options.h>

extern Opts *opts;   
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

kpPty::kpPty() : QObject()
{
  //  kdDebug() << "kpPty::kpPty\n";
  pty = new TEPty();
  connect(pty, SIGNAL(block_in(const char*,int)), this,
		   SLOT(block_in(const char*,int)));
  connect(pty, SIGNAL(done(int)), this,
		   SLOT(done(int)));
  pty->setSize(0,80);
  tm = new QTimer(this);
  connect(tm, SIGNAL(timeout()), this, SLOT(slotTimeout()));

  eventLoop = FALSE;
  started = FALSE;
  pUnterm = FALSE;
}


kpPty::~kpPty()
{
}

bool kpPty::start(bool needRoot)
{
  kdDebug() << "kpPty::start " << started << "\n";
  pUnterm = FALSE;

  if (!started && (!hostName.isEmpty() || !(getuid() == 0 || !needRoot))) {
    int ret;
    QStrList cs;
    QString s = "echo START=$?\n";
    terminator.setPattern("START=\\d+");

    retList.clear();

    if (opts->useSSH || !hostName.isEmpty()) {
      kdDebug() << "/usr/bin/ssh\n";
      cs.append("/usr/bin/ssh");
      cs.append("-t");
      cs.append("-l");
      cs.append("root");
      if (hostName.isEmpty()) {
	cs.append("localhost");
      } else {
	cs.append(hostName.local8Bit());
      }
      cs.append("PATH='/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin'; PS1='# '; export PS1 PATH; /bin/sh -i");  

      pty->run("/usr/bin/ssh",cs,"dumb",FALSE);
    } else {
      kdDebug() << "su\n";
      setenv("PS1", "# ", 1);
      cs.append("su");
      cs.append("-s");
      cs.append("/bin/sh");
      pty->run("su",cs,"dumb",FALSE);
    }

    timeout = FALSE;
    tm->start(3*1000, TRUE); 
    eventLoop = TRUE;
    kdDebug() << "Loopst\n";
    kapp->enter_loop();
    kdDebug() << "Loopfn t=" << timeout << " p=" << gotPrompt << "\n";
    tm->stop();
    if (timeout) {
      //      kdDebug() << "Start " << retList.count() <<" \n";
      kpstart->addText(retList);
      kpstart->run("", i18n("ROOT Login"));
      //      QString s = "cx\n";
      //      pty->send_bytes(s.ascii(),s.length());
      //      s = "echo RESULT=0\n";
      //      pty->send_bytes(s.ascii(),s.length());
      ret = kpstart->exec();
      kdDebug() << "Sret=" << ret << "\n";
      if (ret) {
	started = FALSE;
      } else {
	started = TRUE;
      }
    } else {
      if (!gotPrompt) {
	started = FALSE;
	pty->send_byte('\04');  // SU doesn't listen to ^C
      } else {
	started = TRUE;
      }
    }
    return started;
  }
  return TRUE;
}


QStringList kpPty::run(QString cmd, bool inLoop, bool needRoot)
{
  bool quote = FALSE;
  Result = 0;
  QString s;

  terminator.setPattern("RESULT=\\d+");
  pUnterm = FALSE;
  gotPrompt = FALSE;

  if (hostName.isEmpty() && !started && (getuid() == 0 || !needRoot)) {
    kdDebug() << "CMD=\""<< cmd <<"\"\n";
    QStringList cl = QStringList::split(" ", cmd);
    QStrList cs;
    for ( QStringList::Iterator it = cl.begin(); it != cl.end(); ++it ) {
      int lastPt = (*it).length() - 1;
      if ((*it)[0] == '\'') { // Start of quoted string
	s = *it;
	if ((*it)[lastPt] == '\'') { // Also End of quoted string
	  s.replace(QRegExp("'"),"");
	  cs.append(s.latin1());
	  //	  kdDebug() << "C1=" << s << "\n";
	  quote = FALSE;
	} else {
	  s += " ";
	  quote = TRUE;
	}
      } else if ((*it)[lastPt] == '\'') { // End of quoted string
	s += *it;
	s.replace(QRegExp("'"),"");
	cs.append(s.latin1());
	//	kdDebug() << "C=" << s << "\n";
	quote = FALSE;
      }	else if (quote) {
	s += *it;
	s += " ";
      } else {
	cs.append((*it).latin1());
	//	kdDebug() << "Cc=" << *it << "\n";
      }
    }
    int res = pty->run(cs.first(),cs,"dumb",FALSE);
    // kdDebug() << "PTYrun="<< res <<"\n";
  } else {
    if (start(needRoot)) {
      kdDebug() << "CMDroot='"<< cmd <<"'\n";
      QString s = cmd + ";echo RESULT=$?\n";
      pty->send_bytes(s.ascii(),s.length());
    } else {
      return 0;
    }
  }

  retList.clear();

  if (inLoop) {
    eventLoop = TRUE;
    kapp->enter_loop();
    
    return retList;
  } else {
    return 0;
  }
}

void kpPty::close() {
  pty->donePty();
  started = false;
}

void kpPty::finish(int ret)
{
  //kdDebug() << "kpPty::finish " << ret << "\n";

  QStringList::Iterator l;

  if (ret == -1) {  // Called program executed
    if (!retList.empty()) {
      l = retList.fromLast();
      if ((*l).right(2) == "# ") {
	retList.remove(l);                  // Remove prompt
      }
    }

    if (!retList.empty()) {
      int p;
      l = retList.fromLast();
      if ((p = (*l).find("RESULT=")) >= 0) {
	ret = (*l).mid(p+7).toInt(0,10);
	retList.remove(l);                  // Remove return code
      } else {
	ret = 666;
      }
    }

    if (!retList.empty()) {
      l = retList.begin();
      if ( l !=  retList.end()) {
	if ((*l).find("RESULT=") >= 0) {
	  retList.remove(l);                  // Remove command at start
	}
      }
    } 
  }

  Result = ret;
  kdDebug() << "Result=" << Result << " C=" << retList.count() << "\n";
  emit result(retList,ret);

  if (eventLoop) {
    eventLoop = FALSE;
    kapp->exit_loop();
  }
}

void kpPty::block_in(const char* txt, int len)
{
  bool unterm = FALSE;

  if (len < 0) len = 0;
  QCString text( txt, len+1 );
  text[len] = 0;
  if (text[len-1] != '\n') {
    unterm = TRUE;
  }

  // kdDebug() << "L=" << text << "\n";

  QString stext =  QString::fromLocal8Bit(text);

  emit textIn(stext);

  QStringList sl = QStringList::split("\r\n",stext,TRUE);
  //  kdDebug() << "L=" << stext.length() << ":" <<sl.count() << " " << pUnterm << "\n";

  if (sl.count() > 0) {
    QStringList::Iterator l = sl.fromLast();
    if ((*l).isEmpty()) {
      //      kdDebug() << "removeLast:" << *l << "\n";
      sl.remove(l);
    }
  }

  if (sl.count() > 0) {
    if (pUnterm) {

      QStringList::Iterator lst =  retList.fromLast();
      QStringList::Iterator fst =  sl.begin();

      //      kdDebug() << "BBrk=" << (*lst) << "=" << (*fst) << "\n";

      if ((*lst).right(1) == "\r" && (*fst).left(1) == "\n") {
	// handle /r/n split between blocks
	(*lst).truncate((*lst).length() - 1);
	(*fst) = (*fst).mid(1);
      } else {
	if ((*fst).left(1) != "\r") {
	  (*lst) = (*lst) + (*fst);
	} else {
	  // Remove line that is overwritten on screen
	  //	  kdDebug() << "ERASE=[" << *fst << "]\n";
	}
	sl.remove(fst);
      }
      //            kdDebug() << "PU=" << stext.length() << ":" <<sl.count() << "\n";
    }

    for ( QStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) {
      //          kdDebug() << "L=" << *it << "\n";
      retList << (*it);
    }
  }
  pUnterm = unterm;

  if (stext.right(2) == "# ") {
    //    kdDebug() << "ST=" << stext << "=\n";
    gotPrompt = TRUE;
    emit textIn("\r \n");
    finish(-1);
  }
}

void kpPty::keyOut(char ch)
{
  pty->send_byte(ch);
}

void kpPty::done(int ret)
{
  //  kdDebug() << "Done\n";

  finish(ret);
}

void kpPty::slotTimeout()
{
  kdDebug() << "Timeout..............\n";
  if (eventLoop) {
    timeout = TRUE;
    eventLoop = FALSE;
    kapp->exit_loop();
  }
}
#include "kpPty.moc"
