diff options
Diffstat (limited to 'src/apt.cpp')
-rw-r--r-- | src/apt.cpp | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/src/apt.cpp b/src/apt.cpp new file mode 100644 index 0000000..9a68991 --- /dev/null +++ b/src/apt.cpp @@ -0,0 +1,946 @@ +/*************************************************************************** + * Copyright (C) 2003 by Sylvain Joyeux * + * [email protected] * + * The forms are by Willy De la Court <[email protected]> * + * * + * 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 <qcstring.h> + +#include <kapplication.h> +#include <kinstance.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kurl.h> +#include <kio/slavebase.h> +#include <kmessagebox.h> + +#include <kdebug.h> + +#include <qregexp.h> + +#include <stdlib.h> + +#include <config.h> + +using namespace KIO; + +/************************************************************************* +* Common definitions of HTML fragments +*/ + +static const QString + 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 QString + html_redirect(html_preamble + + QString("<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 QString + html_head(html_preamble + + QString("<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 QString close_html_head(); +static QString open_html_head(const QString& title, bool links, AptProtocol const& config) +{ + + static const QString + 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"); + + QString rowspan; + if (links) rowspan = "rowspan=\"2\""; + QString 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 QString add_html_head_link(const QString& url, const QString& name, const QString& long_desc) +{ + static const QString format("\t\t<td><a href=\"%1\" title=\"%2\">%3</a></td>\n"); + return format.arg(url).arg(long_desc).arg(name); +} +static QString close_html_head() +{ + return "\t</tr>\n" + "\t</table>\n" + "\t</td>\n" + "</tr>" + "</table>"; +} + +static const QString + html_tail("<div class=\"footer\">%1</div>\n" + "</body>\n" + "</html>"); + + +QString AptProtocol::make_html_tail(const QString& note, bool with_form) +{ + with_form = m_search && with_form; + + QString ret; + if (with_form) + ret = "<hr>\n" + make_html_form(); + + if (!note.isEmpty()) + ret += html_tail.arg(note + ". " + i18n("Page generated by kio_apt.")); + else ret += html_tail.arg(i18n("Page generated by kio_apt.")); + + return ret; +} + +/********************************************************************************** + * Search form + */ + +static const QString + html_form_begin("\n<form action=\"apt:/\" method=\"GET\">\n" + "<table class=\"query\">\n"); +static const QString + html_form_end("<tr>\n" + "\t<td class=\"button\" colspan=\"2\"><input type=\"submit\" value=\"%1\"></td>\n" + "</tr>\n" + "</table>\n" + "</form>\n"); + +static const QString + 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 QString make_html_form_line(const QString& type, const QString& label) +{ return html_form_line.arg(type).arg(label).arg(type).arg(type); } + + +static QString make_extform_cmd(bool ext_form, const KURL& query) +{ + QString cmd = ext_form ? "0" : "1"; + QString 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 */ +QString AptProtocol::make_html_form() const +{ + bool can_fsearch = false; + bool ext_form = KGlobal::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 = KGlobal::config() -> readBoolEntry("online_form", true); + if (m_adept_batch) + online = online_form && (!m_internal) && ext_form && m_adept_batch -> capabilities(PackageManager::ONLINE); + + QString ret; + QTextOStream stream(&ret); + stream << make_extform_cmd(ext_form, m_query); + + if (online) + stream << "<table class=\"queryform\"><tr><td>\n"; + + stream << html_form_begin; + 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.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 QCString &pool_socket, const QCString &app_socket ) + : SlaveBase( "kio_apt", pool_socket, app_socket ), + m_adept_batch(0), m_parser(0) + +{ + KStandardDirs* dirs = KGlobal::dirs(); + m_stylesheet = dirs->findResource( "data", "kio_apt/kio_apt.css" ); + + m_logo = dirs->findResource( "data", "kio_apt/" + + KGlobal::config() -> readEntryUntranslated("logo", "kdedeb_logo.png" ) ); + + m_header_background = dirs->findResource( "data", "kio_apt/" + + KGlobal::config() -> readEntryUntranslated("background", "headerbg.png" ) ); + + m_logo_alt = KGlobal::config() -> readEntryUntranslated("alt_tag", i18n("KDE on Debian") ); + + connect(&m_process, SIGNAL(token(const QString&, const QString&)), + this, SLOT(token_dispatch(const QString&, const QString&))); + + m_adept_batch = new Dpkg(this); + + if (m_adept_batch) + { + connect(m_adept_batch, SIGNAL(token(const QString&, const QString&)), + this, SLOT(token_dispatch(const QString&, const QString&))); + } +} + +AptProtocol::~AptProtocol() {} + +QString AptProtocol::stylesheet() const { return m_stylesheet; } +QString AptProtocol::logo() const { return m_logo; } +QString AptProtocol::logo_alt() const { return m_logo_alt; } +QString AptProtocol::header_background() const { return m_header_background; } + +void AptProtocol::token_dispatch(const QString& name, const QString& val) +{ + if (m_parser.get()) + (*m_parser)(this, name, val); +} + +void AptProtocol::data(const QCString& string) +{ + using namespace Parsers; + (*this) << string; +} + +void AptProtocol::data(const QString& string) +{ + using namespace Parsers; + (*this) << string; +} + +void AptProtocol::data(const char* string) +{ + using namespace Parsers; + (*this) << string; +} + +void AptProtocol::data(const QByteArray& array) +{ SlaveBase::data(array); } + +void AptProtocol::mimetype( const KURL & /*url*/ ) +{ + mimeType( "text/html" ); + finished(); +} + +bool AptProtocol::check_validpackage(const QString& query) +{ + static QRegExp 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 QString read_option(QMap<QString, QString>& map, const QString& name, const QString& def) +{ + if (!map.contains(name)) return def; + QString 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 QString&, const QueryOptions&); + static const QString commands[] = + { "search", "show", "policy", + "fsearch", "list", "online", + "get", QString::null }; + static const Command methods[] = + { &AptProtocol::search, &AptProtocol::show, &AptProtocol::policy, + &AptProtocol::searchfile, &AptProtocol::listfiles, &AptProtocol::online, + &AptProtocol::adept_batch }; + + QString command, query; + Command method = 0; + QueryOptions options = url.queryItems(KURL::CaseInsensitiveKeys); + + // canonize the part before ? : remove the first / + QString path = url.path(); + QString 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 QString 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 + QString opt = read_option(options, "extended_form", QString::null); + if (!opt.isNull()) + { + bool ext_form = (opt != "0"); + KGlobal::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) + KGlobal::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(QByteArray()); + finished(); + return; + } + + (this->*method)(query, options); + } +} + + +/*********************************************************************************** +* +* form +* +*/ + +void AptProtocol::help() +{ + mimeType("text/html"); + + QString buffer; + QTextOStream stream(&buffer); + stream + << open_html_head(i18n("Search Form"), false, *this) + << make_html_form() + << make_html_tail(QString::null, false); + data(buffer); + data(QByteArray()); + finished(); +} + + + + + + + +/*********************************************************************************** + * apt-cache search + */ + +void AptProtocol::search( const QString& 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", QString::null); + + data(make_html_tail( i18n("%1 results").arg(m_parser -> result_count())) ); + data(QByteArray()); + finished(); +} + + + + + + +/*********************************************************************************** + * apt-cache show + */ + +static QString filelist_cmd(bool show_filelist, const KURL& query) +{ + QString value = show_filelist ? "0" : "1"; + QString 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 QString& package, const QueryOptions& options) +{ + if (!check_validpackage(package)) return; + + if (options.contains("show_filelist")) + { + KGlobal::config() -> writeEntry("show_filelist", options["show_filelist"] != "0"); + KGlobal::config() -> sync(); + } + + mimeType("text/html"); + + QString 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", QString::null); + { + 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()); + QString buffer; + QTextOStream 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", QString::null); + + + /** Add package description section */ + m_parser.reset(new Parsers::Show(package, installed_version, m_act)); + (*m_parser)(this, "begin", QString::null); + { + 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(QByteArray()); + finished(); + return; + } + } + (*m_parser)(this, "end", QString::null); + + + + /** Add file list (if enabled) */ + bool show_filelist = KGlobal::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", QString::null); + if (!m_adept_batch -> list(package)) + { + error(ERR_SLAVE_DEFINED, i18n("Error listing files of %1").arg(package)); + return; + } + (*m_parser)(this, "end", QString::null); + + 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(QByteArray()); + finished(); +} + + + + +/*********************************************************************************** + * apt-cache policy + */ + +void AptProtocol::policy( const QString& 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", QString::null); + if (!m_process.policy( query )) + { + error(ERR_SLAVE_DEFINED, i18n("Can't launch the policy for %1").arg(query)); + return; + } + (*m_parser)(this, "end", QString::null); + + data(make_html_tail()); + data(QByteArray()); + finished(); +} + + + +/*********************************************************************************** +* Search the package which contains a specific file +*/ + +static const QString + 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 QString& 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", QString::null); + if (!m_adept_batch -> search( query )) + { + error(ERR_SLAVE_DEFINED, i18n("Can't launch the package manager").arg(query)); + return; + } + (*m_parser)(this, "end", QString::null); + + data( html_dpkgs_end + make_html_tail(i18n("%1 files found").arg(m_parser -> result_count())) ); + data(QByteArray()); + 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 QString& query, const QueryOptions& /*options*/) +{ + if (!can_listfiles(true)) return; + if (!check_validpackage(query)) return; + + mimeType("text/html"); + + KURL ret_url = buildURL("show", query); + + QString buffer; + QTextOStream 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", QString::null); + if (!m_adept_batch -> list( query )) + { + error(ERR_SLAVE_DEFINED, i18n("Can't launch the package manager").arg(query)); + return; + } + (*m_parser)(this, "end", QString::null); + + data(make_html_tail()); + data(QByteArray()); + 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 QString& query, const QueryOptions& options) +{ + QString url = m_adept_batch -> getOnlineURL(query, options); + redirection(url); + finished(); + return; +} + +/*********************************************************************************** + * Send commands for adept_batch + */ +void AptProtocol::adept_batch(const QString& query, const QueryOptions& options) +{ + p=NULL; + + QString command; + QString url; + QStringList plist; + QStringList puninst; + QStringList pinst; + int pcount; + int ip; + + if (query == "install" || query.isEmpty()) { + command = "kdesu adept_batch install "; + } else if (query == "remove") { + command = "kdesu 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 = QStringList::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( KProcess::Block, KProcess::All ); + + for(int i = 0; i != pcount; ++i) + { + QString installed_version; + + Parsers::Policy* policy = new Parsers::Policy(plist[i], m_act); + m_parser.reset(policy); + (*m_parser)(this, "begin", QString::null); + { + 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 + { + QString 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(QByteArray()); + finished(); + return; + } + } + else + { + return; + } +} + +KURL AptProtocol::buildURL( const QString & command, const QString & 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" { + int kdemain( int argc, char **argv ) { + KInstance instance( "kio_apt" ); + + if ( argc != 4 ) { + kdDebug( DEBUG_ZONE ) << "Usage: kio_apt protocol domain-socket1 domain-socket2" << endl; + exit ( -1 ); + } + + AptProtocol slave( argv[ 2 ], argv[ 3 ] ); + slave.dispatchLoop(); + + return 0; + } +} + +#include "apt.moc" |