/***************************************************************************
 *   Copyright (C) 2003 by Sylvain Joyeux                                  *
 *   sylvain.joyeux@m4x.org                                                *
 *   The forms are by Willy De la Court <wdl@linux-lovers.be>              *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/

#include "apt.h"
#include "regexps.h"

#include "dpkg.h"

#include "parsers/parsers.h"

#include <tqcstring.h>

#include <tdeapplication.h>
#include <kinstance.h>
#include <tdeglobal.h>
#include <tdeconfig.h>
#include <kstandarddirs.h>
#include <tdelocale.h>
#include <kurl.h>
#include <tdeio/slavebase.h>
#include <tdemessagebox.h>

#include <kdebug.h>

#include <tqregexp.h>

#include <stdlib.h>

#include <config.h>

using namespace TDEIO;

/*************************************************************************
* Common definitions of HTML fragments
*/

static const TQString
  html_preamble("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Strict//EN\"\n"
                "\t\"http://www.w3.org/TR/html4/strict.dtd\">\n"
                "<html>\n");
static const TQString
  html_redirect(html_preamble +
    TQString("<head>\n"
            "\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
            "\t<meta http-equiv=\"Refresh\" content=\"0 ; URL=%1\">\n"
            "</head>\n"
            "\n<body></body>\n"
            "</html>"));

static const TQString
  html_head(html_preamble +
    TQString("<head>\n"
            "\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
            "\t<link rel=\"stylesheet\" href=\"file:%1\">\n"
            "\t<title>%2</title>\n"
            "</head>\n\n"
            "<body>\n"));

static TQString close_html_head();
static TQString open_html_head(const TQString& title, bool links, AptProtocol const& config)
{

  static const TQString
    html_head_table(
              "<table class=\"header\" style=\"background-image: url(file:%1);\"\n"
                    "\t\tcellspacing=\"0\" cellpadding=\"0\">\n"
              "<tr>\n"
              "\t<td class=\"logo\" %2><img src=\"file:%3\" alt=\"%4\" style=\"border: 0px\" /></td>\n"
              "\t<td class=\"header-title\">%4</td>\n");

  TQString rowspan;
  if (links) rowspan = "rowspan=\"2\"";
  TQString ret =
   html_head
    .arg(config.stylesheet())
    .arg(title)
   + html_head_table
    .arg(config.header_background())
    .arg(rowspan)
    .arg(config.logo())
    .arg(config.logo_alt())
    .arg(title);

  if (links)
  {
    return ret +
      "</tr>\n"
      "<tr>\n"
      "\t<td class=\"links\">\n"
      "\t<table class=\"links\" cellspacing=\"0\" cellpadding=\"0\">\n"
      "\t<tr>\n";
  }
  else
  {
    return ret + "</tr>\n</table>\n\n";
  }
}
static TQString add_html_head_link(const TQString& url, const TQString& name, const TQString& long_desc)
{
  static const TQString format("\t\t<td><a href=\"%1\" title=\"%2\">%3</a></td>\n");
  return format.arg(url).arg(long_desc).arg(name);
}
static TQString close_html_head()
{
  return "\t</tr>\n"
         "\t</table>\n"
         "\t</td>\n"
         "</tr>"
         "</table>";
}

static const TQString
  html_tail("<div class=\"footer\">%1</div>\n"
            "</body>\n"
            "</html>");


TQString AptProtocol::make_html_tail(const TQString& note, bool with_form)
{
  with_form = m_search && with_form;

  TQString ret;
  if (with_form)
    ret = "<hr>\n" + make_html_form();

  if (!note.isEmpty())
    ret += html_tail.arg(note + ". " + i18n("Page generated by tdeio_apt."));
  else ret += html_tail.arg(i18n("Page generated by tdeio_apt."));

  return ret;
}

/**********************************************************************************
 * Search form
 */

static const TQString
  html_form_begin_apt("\n<form action=\"apt:/\" method=\"GET\">\n"
                  "<table class=\"query\">\n");
static const TQString
  html_form_end_apt("<tr>\n"
                "\t<td class=\"button\" colspan=\"2\"><input type=\"submit\" value=\"%1\"></td>\n"
                "</tr>\n"
                "</table>\n"
                "</form>\n");

static const TQString
  html_form_line("<tr>\n"
                 "\t<td><label for=\"%1\">%2</label></td>\n"
                 "\t<td><input type=\"text\" name=\"%3\" id=\"%4\"></td>\n"
                 "</tr>\n");

static TQString make_html_form_line(const TQString& type, const TQString& label)
{ return html_form_line.arg(type).arg(label).arg(type).arg(type); }


static TQString make_extform_cmd(bool ext_form, const KURL& query)
{
  TQString cmd = ext_form ? "0" : "1";
  TQString msg = ext_form ? i18n("Hide extended form") : i18n("Show extended form");

  KURL url(query);
  url.addQueryItem("extended_form", cmd);
  url.setRef("extformcmd");

  return 
    "<div class=\"command\" id=\"extformcmd\">\n"
    "\t<a href=\"" + url.htmlURL() + "\">[" + msg + "]</a>\n"
    "</div>\n";
}

/** Prints the HTML code for the query form */
TQString AptProtocol::make_html_form() const
{
  bool can_fsearch = false;
  bool ext_form = TDEGlobal::config() -> readBoolEntry("extended_form", true);
  // Only in config-file. Needed for some dpkg-based distros that are not Debian
  can_fsearch = can_searchfile(true);

  bool online = false;
  bool online_form = TDEGlobal::config() -> readBoolEntry("online_form", true);
  if (m_adept_batch)
    online = online_form && (!m_internal) && ext_form && m_adept_batch -> capabilities(PackageManager::ONLINE);

  TQString ret;
  TQTextOStream stream(&ret);
  stream << make_extform_cmd(ext_form, m_query);

  if (online)
    stream << "<table class=\"queryform\"><tr><td>\n";

  stream << html_form_begin_apt;
  stream << "<tr><td colspan=\"2\" class=\"title\">" + i18n("Offline search") + "</td></tr>" << endl;
  stream << make_html_form_line("search", i18n("Package search"));
  if (ext_form)
  {
    if (can_fsearch)
      stream << make_html_form_line("fsearch", i18n("File search"));
    stream << make_html_form_line("show", i18n("Package info"));
  }
  stream << html_form_end_apt.arg( i18n("Search") );

  if (online)
  {
    stream << "\n</td><td>\n";
    stream << m_adept_batch -> getOnlineForm();
    stream << "\n</td></tr>\n</table>";
  }

  return ret;
}

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

AptProtocol::AptProtocol( const TQCString &pool_socket, const TQCString &app_socket )
    : SlaveBase( "tdeio_apt", pool_socket, app_socket ),
      m_adept_batch(0), m_parser(0)

{
  TDEStandardDirs* dirs = TDEGlobal::dirs();
  m_stylesheet = dirs->findResource( "data", "tdeio_apt/tdeio_apt.css" );

  m_logo = dirs->findResource( "data", "tdeio_apt/" 
          + TDEGlobal::config() -> readEntryUntranslated("logo", "kdedeb_logo.png" ) );

  m_header_background = dirs->findResource( "data", "tdeio_apt/" 
          + TDEGlobal::config() -> readEntryUntranslated("background", "headerbg.png" ) );

  m_logo_alt = TDEGlobal::config() -> readEntryUntranslated("alt_tag", i18n("KDE on Debian") );

  connect(&m_process, TQT_SIGNAL(token(const TQString&, const TQString&)),
    this, TQT_SLOT(token_dispatch(const TQString&, const TQString&)));

  m_adept_batch = new Dpkg(this);

  if (m_adept_batch)
  {
    connect(m_adept_batch, TQT_SIGNAL(token(const TQString&, const TQString&)),
      this, TQT_SLOT(token_dispatch(const TQString&, const TQString&)));
  }
}

AptProtocol::~AptProtocol() {}

TQString AptProtocol::stylesheet() const { return m_stylesheet; }
TQString AptProtocol::logo() const { return m_logo; }
TQString AptProtocol::logo_alt() const { return m_logo_alt; }
TQString AptProtocol::header_background() const { return m_header_background; }

void AptProtocol::token_dispatch(const TQString& name, const TQString& val)
{
  if (m_parser.get())
    (*m_parser)(this, name, val);
}

void AptProtocol::data(const TQCString& string)
{
  using namespace Parsers;
  (*this) << string;
}

void AptProtocol::data(const TQString& string)
{
  using namespace Parsers;
  (*this) << string;
}

void AptProtocol::data(const char* string)
{
  using namespace Parsers;
  (*this) << string;
}

void AptProtocol::data(const TQByteArray& array)
{ SlaveBase::data(array); }

void AptProtocol::mimetype( const KURL & /*url*/ )
{
  mimeType( "text/html" );
  finished();
}

bool AptProtocol::check_validpackage(const TQString& query)
{
  static TQRegExp rx_pkgname(rxs_pkgname);
  if (!rx_pkgname.exactMatch(query))
  {
    error( ERR_SLAVE_DEFINED, i18n("\"%1\" is not a valid package name").arg(query) );
    return false;
  }
  return true;
}


/********************************************************************
 * Main entry point
 */

static TQString read_option(TQMap<TQString, TQString>& map, const TQString& name, const TQString& def)
{
  if (!map.contains(name)) return def;
  TQString ret = map[name];
  map.remove(name);
  return ret;
}

void AptProtocol::get ( const KURL& url )
{
  /* The queries have two possible formats :

   - clean way to call a command
    apt:/command?query&option=value&option=value&...
   - needed to simplify forms
    apt:/?command=query&command2=&command3=&option=value&option=value&...
   - calls only the query form page
    apt:/
  */

  typedef void (AptProtocol::*Command)(const TQString&, const QueryOptions&);
  static const TQString commands[] =
  { "search", "show", "policy",
    "fsearch", "list", "online",
    "get", TQString() };
  static const Command methods[] =
  { &AptProtocol::search, &AptProtocol::show, &AptProtocol::policy,
    &AptProtocol::searchfile, &AptProtocol::listfiles, &AptProtocol::online,
    &AptProtocol::adept_batch };

  TQString command, query;
  Command method = 0;
  QueryOptions options = url.queryItems(KURL::CaseInsensitiveKeys);

  // canonize the part before ? : remove the first /
  TQString path = url.path();
  TQString host = url.host();

  if ( path.isEmpty() && !host.isEmpty() )
  {
    path = host;
  }

  if (path [0] == '/')
    path = path.right(path.length() - 1);

  for (int cmd_idx = 0; !commands[cmd_idx].isNull(); ++cmd_idx)
  {
    const TQString cmd_it = commands[cmd_idx];

    // Look if the command is in the path part
    if (command.isEmpty() && cmd_it == path)
    {
      command = cmd_it;
      method = methods[cmd_idx];
    }
    if (options.contains(cmd_it))
    {

      if (options[cmd_it].isEmpty() && !options[cmd_it].isNull())
      { // we have a &command=& format, we remove it
        options.remove(cmd_it);
      }
      else if (command.isEmpty() && !options[cmd_it].isEmpty())
      { // the command is set in the options map
        command = cmd_it;
        method = methods[cmd_idx];
        query = options[cmd_it];
        options.remove(cmd_it);
      }
    }
  }

  // Well, we have no query for now, let's find it
  if (query.isEmpty())
  {
    for (QueryOptions::Iterator i = options.begin(); i != options.end(); ++i)
    {
      if ((*i).isNull())
      {
        query = KURL::decode_string(i.key());
        options.remove(i);
        break;
      }
    }
  }

  // Interpret the ioslave config options
  // and remove them from the options map
  TQString opt = read_option(options, "extended_form", TQString());
  if (!opt.isNull())
  {
    bool ext_form = (opt != "0");
    TDEGlobal::config() -> writeEntry("extended_form", ext_form);
  }

  // Enable install/remove/upgrade/...
  opt = read_option(options, "enable_actions", "1");
  m_act = (opt != "0");

  opt = read_option(options, "enable_search", "1");
  m_search = (opt != "0");

  // Allow links outside of apt:/ hierarchy
  opt = read_option(options, "stay_internal", "0");
  m_internal = (opt == "1");

  // Sync the config (must use kcfg sometime :p)
  TDEGlobal::config() -> sync();

  if (command.isEmpty() || query.isEmpty())
  {
    //If path isn't empty, then a package is to be installed via an apt:/ link
    if ( !path.isEmpty())
    {
      query = "install";
      options["package"] = path;
      options["weblinkinstall"] = 1;
      adept_batch(query, options);
      return;
    }

    // No query or no command, we go in help mode
    m_query = buildURL(KURL("apt:/"));
    help();
  }
  else
  {
    m_query = buildURL(command, query);
    m_query.setHTMLRef(url.htmlRef());
    for (QueryOptions::ConstIterator i = options.begin(); i != options.end(); ++i)
      m_query.addQueryItem(i.key(), i.data());

    kdDebug() << "Old url " << url << ", new url " << m_query << endl;

    if (m_query != url)
    {
      redirection(m_query);
      data(TQByteArray());
      finished();
      return;
    }

    (this->*method)(query, options);
  }
}


/***********************************************************************************
*
*  form
*
*/

void AptProtocol::help()
{
  mimeType("text/html");

  TQString buffer;
  TQTextOStream stream(&buffer);
  stream
        << open_html_head(i18n("Search Form"), false, *this)
        << make_html_form()
        << make_html_tail(TQString(), false);
  data(buffer);
  data(TQByteArray());
  finished();
}







/***********************************************************************************
 *   apt-cache search
 */

void AptProtocol::search( const TQString& query, const QueryOptions& /*options*/ )
{
  mimeType("text/html");

  data(open_html_head(i18n("Package search result for \"%1\"").arg(query), false, *this));

  m_parser.reset(new Parsers::Search);
  (*m_parser)(this, "begin", query);
  if (!m_process.search( query ))
  {
    error(ERR_SLAVE_DEFINED, i18n("Error launching the search").arg(query));
    return;
  }
  (*m_parser)(this, "end", TQString());

  data(make_html_tail( i18n("%1 results").arg(m_parser -> result_count())) );
  data(TQByteArray());
  finished();
}






/***********************************************************************************
 *   apt-cache show
 */

static TQString filelist_cmd(bool show_filelist, const KURL& query)
{
  TQString value = show_filelist ? "0" : "1";
  TQString msg = show_filelist ? i18n("Hide file list") : i18n("Show file list");

  KURL url(query);
  url.addQueryItem("show_filelist", value);
  url.setRef("filelistcmd");

  return
    "<div class=\"command\" id=\"filelistcmd\">\n"
    "\t<a href=\"" + url.htmlURL() + "\">"
    "[" + msg + "]"
    "</a>\n"
    "</div>";
}

void AptProtocol::show(const TQString& package, const QueryOptions& options)
{
  if (!check_validpackage(package)) return;

  if (options.contains("show_filelist"))
  {
    TDEGlobal::config() -> writeEntry("show_filelist", options["show_filelist"] != "0");
    TDEGlobal::config() -> sync();
  }

  mimeType("text/html");

  TQString installed_version;

  /** First, we parse policy
   * We use here the fact that HTML is generated
   * during the call of (*policy)(...,"end",...),
   * since the header changes when the package
   * is installed or not */
  Parsers::Policy* policy = new Parsers::Policy(package, m_act);
  m_parser.reset(policy);
  (*m_parser)(this, "begin", TQString());
  {
    if (!m_process.policy( package ))
    {
      error(ERR_SLAVE_DEFINED, i18n("Can't launch \"apt-cache policy %1\"").arg(package));
      return;
    }

    installed_version = policy->getInstalled();
    bool can_list = can_listfiles(!installed_version.isEmpty());
    TQString buffer;
    TQTextOStream s(&buffer);
    if (can_list)
    {
      KURL url = buildURL("list", package);
      s << open_html_head(i18n("Package description for \"%1\"").arg(package), true, *this)
        <<   add_html_head_link(url.htmlURL(), i18n("List package files"), "")
        << close_html_head();
    }
    else
    {
      s << open_html_head(i18n("Package description for \"%1\"").arg(package), false, *this);
    }
    data(buffer);
  }
  (*m_parser)(this, "end", TQString());


  /** Add package description section */
  m_parser.reset(new Parsers::Show(package, installed_version, m_act));
  (*m_parser)(this, "begin", TQString());
  {
    if (!m_process.show(package))
    {
      error(ERR_SLAVE_DEFINED, i18n("Can't launch \"apt-cache show %1\"").arg(package));
      return;
    }
    if (!m_parser -> result_count())
    {
      data("<div class=\"error\">" + i18n("No package found named \"%1\"").arg(package) + "</div>\n");
      data(make_html_tail());
      data(TQByteArray());
      finished();
      return;
    }
  }
  (*m_parser)(this, "end", TQString());



  /** Add file list (if enabled) */
  bool show_filelist = TDEGlobal::config() -> readBoolEntry("show_filelist", false);
  if ( show_filelist )
  {
    if (can_listfiles(!installed_version.isEmpty()))
    {
      data(
        "<hr>\n"
        + filelist_cmd(show_filelist, m_query)
        + "<div class=\"filelist\">\n");

      m_parser.reset(new Parsers::List(!m_internal));
      (*m_parser)(this, "begin", TQString());
      if (!m_adept_batch -> list(package))
      {
        error(ERR_SLAVE_DEFINED, i18n("Error listing files of %1").arg(package));
        return;
      }
      (*m_parser)(this, "end", TQString());

      data("\n</div>\n");
    }
    else // cannot list files
    {
      data(
        "<hr>\n"
        + filelist_cmd(show_filelist, m_query)
        + "<div class=\"error\">" + i18n("Cannot list files for non-installed packages") + "</div>\n");
    }
  }
  else
  {
    data("<hr>\n" + filelist_cmd(show_filelist, m_query));
  }


  data(make_html_tail());
  data(TQByteArray());
  finished();
}




/***********************************************************************************
 *   apt-cache policy
 */

void AptProtocol::policy( const TQString& query, const QueryOptions& /*options*/ )
{
  if (!check_validpackage(query)) return;

  mimeType("text/html");

  data( open_html_head(i18n("Apt policy for \"%1\"").arg(query), false, *this) );

  m_parser.reset(new Parsers::Policy(query, m_act));
  (*m_parser)(this, "begin", TQString());
  if (!m_process.policy( query ))
  {
    error(ERR_SLAVE_DEFINED, i18n("Can't launch the policy for %1").arg(query));
    return;
  }
  (*m_parser)(this, "end", TQString());

  data(make_html_tail());
  data(TQByteArray());
  finished();
}



/***********************************************************************************
*   Search the package which contains a specific file
*/

static const TQString
  html_dpkgs_begin("\n\n<table>\n"),
  html_dpkgs_end("\n\n</table>\n");


bool AptProtocol::can_searchfile(bool is_installed) const
{
  if (!m_adept_batch) return false;
  int caps = m_adept_batch -> capabilities(PackageManager::SEARCH_FILE | PackageManager::OFFLINE);
  if (!caps) return false;
  return is_installed || !(caps & PackageManager::INSTALLED_ONLY);
}
void AptProtocol::searchfile(const TQString& query, const QueryOptions& /*options*/)
{
  if (!can_searchfile(true)) return;

  mimeType("text/html");
  data( open_html_head(i18n("File search for \"%1\"").arg(query), false, *this) + html_dpkgs_begin );

  m_parser.reset(new Parsers::FileSearch);
  (*m_parser)(this, "begin", TQString());
  if (!m_adept_batch -> search( query ))
  {
    error(ERR_SLAVE_DEFINED, i18n("Can't launch the package manager").arg(query));
    return;
  }
  (*m_parser)(this, "end", TQString());

  data( html_dpkgs_end + make_html_tail(i18n("%1 files found").arg(m_parser -> result_count())) );
  data(TQByteArray());
  finished();
}




/***********************************************************************************
*   List the files of a package
*/

bool AptProtocol::can_listfiles(bool is_installed) const
{
  if (!m_adept_batch) return false;
  int caps = m_adept_batch -> capabilities(PackageManager::LIST_FILES | PackageManager::OFFLINE);
  if (!caps) return false;
  return is_installed || !(caps & PackageManager::INSTALLED_ONLY);
}

void AptProtocol::listfiles(const TQString& query, const QueryOptions& /*options*/)
{
  if (!can_listfiles(true)) return;
  if (!check_validpackage(query)) return;

  mimeType("text/html");

  KURL ret_url = buildURL("show", query);

  TQString buffer;
  TQTextOStream stream(&buffer);
  stream
        << open_html_head(i18n("Files in \"%1\"").arg(query), true, *this)
        <<   add_html_head_link(ret_url.htmlURL(), i18n("Show package info"), "")
        << close_html_head()
        << endl;
  data(buffer);

  m_parser.reset(new Parsers::List(!m_internal));
  (*m_parser)(this, "begin", TQString());
  if (!m_adept_batch -> list( query ))
  {
    error(ERR_SLAVE_DEFINED, i18n("Can't launch the package manager").arg(query));
    return;
  }
  (*m_parser)(this, "end", TQString());

  data(make_html_tail());
  data(TQByteArray());
  finished();
}




/***********************************************************************************
 * Go use online search services (like packages.debian.org for instance)
 */

//bool AptProtocol::can_online(int mode) const
//{
////  if (!m_adept_batch) return false;
////  return m_adept_batch -> capabilities(PackageManager::ONLINE | mode);
//  return false;
//}

void AptProtocol::online(const TQString& query, const QueryOptions& options)
{
  TQString url = m_adept_batch -> getOnlineURL(query, options);
  redirection(url);
  finished();
  return;
}

/***********************************************************************************
 * Send commands for adept_batch
 */
void AptProtocol::adept_batch(const TQString& query, const QueryOptions& options)
{
  p=NULL;

  TQString command;
  TQString url;
  TQStringList plist;
  TQStringList puninst;
  TQStringList pinst;
  int pcount;
  int ip;

  if (query == "install" || query.isEmpty()) {
    command = "tdesu adept_batch install ";
  } else if (query == "remove") {
    command = "tdesu adept_batch remove ";
  }

  if (command.isEmpty())
  {
    error(ERR_SLAVE_DEFINED, i18n("No package manager command specified"));
    return;
  }

  if (!options.contains("package"))
  {
    error(ERR_SLAVE_DEFINED, i18n("No package specified"));
    return;
  }

  plist = TQStringList::split(", ", options["package"], false);
  pcount = plist.count();
  command += plist.join(" ");

  if (pcount == 1)
  {
    if (query == "install")
      ip =  SlaveBase::messageBox(QuestionYesNo, i18n("Do you want to install %1 ?").arg(plist[0]), i18n("Package Installation"));
    else
      ip =  SlaveBase::messageBox(QuestionYesNo, i18n("Do you want to remove %1 ?").arg(plist[0]), i18n("Package Removal"));
  }
  else
  {
    if (query == "install")
      ip = SlaveBase::messageBox(QuestionYesNo,i18n("Do you want to install the following %1 packages ?\n%2").arg(pcount).arg(options["package"]));
    else
      ip = SlaveBase::messageBox(QuestionYesNo,i18n("Do you want to remove the following %1 packages ?\n").arg(pcount).arg(options["package"]));
  }

  kdDebug(DEBUG_ZONE) << command << endl;

  if (ip == KMessageBox::Yes)
  {
    p = new KShellProcess;
    p->clearArguments();
    *p << command;
    p->start( TDEProcess::Block, TDEProcess::All );

    for(int i = 0; i != pcount; ++i)
    {
      TQString installed_version;

      Parsers::Policy* policy = new Parsers::Policy(plist[i], m_act);
      m_parser.reset(policy);
      (*m_parser)(this, "begin", TQString());
      {
        if (!m_process.policy( plist[i] ))
        {
          error(ERR_SLAVE_DEFINED, i18n("Can't launch \"apt-cache policy %1\"").arg(plist[i]));
          return;
        }

        installed_version = policy->getInstalled();
        if (installed_version.isEmpty())
        {
          puninst += plist[i];
        }
        else
        {
          pinst += plist[i];
        }
      }
    }

    if (options.contains("weblinkinstall"))
    {
      if (puninst.count() == 0)
      {
        messageBox(Information,i18n("Installation successfull."));
      }
      else
      {
        TQString toto = puninst.join(" ");
        messageBox(Information,i18n("There was a problem installing %1.").arg(toto));
      }
      return;
    }
    else
    {
      url = "apt:/show?";
      // Outside of a weblink, only one package can be installed at time
      url += plist[0];
      redirection(url);
      data(TQByteArray());
      finished();
      return;
    }
  }
  else
  {
    return;
  }
}

KURL AptProtocol::buildURL( const TQString & command, const TQString & query ) const
{
  KURL url;
  url.setProtocol("apt");
  if (!command.startsWith("/"))
    url.setPath("/" + command);
  else
    url.setPath(command);
  url.setQuery(query);
  return buildURL(url);
}

KURL AptProtocol::buildURL( const KURL& query ) const
{
  KURL url(query);

  if (!m_act)
    url.addQueryItem("enable_actions", "0");
  if (!m_search)
    url.addQueryItem("enable_search", "0");
  if (m_internal)
    url.addQueryItem("stay_internal", "1");

  return url;
}

/***********************************************************************************
*
*   kdemain
*
*/

extern "C" { KDE_EXPORT int kdemain(int argc, char **argv); }

extern "C" {
  int kdemain( int argc, char **argv ) {
    TDEInstance instance( "tdeio_apt" );

    if ( argc != 4 ) {
      kdDebug( DEBUG_ZONE ) << "Usage: tdeio_apt  protocol domain-socket1 domain-socket2" << endl;
      exit ( -1 );
    }

    AptProtocol slave( argv[ 2 ], argv[ 3 ] );
    slave.dispatchLoop();

   return 0;
  }
}

#include "apt.moc"