/*************************************************************************** File: kio_sword.cpp Project: Kio-Sword -- An ioslave for SWORD and KDE Copyright: Copyright (C) 2004-2005 Luke Plant File info: ***************************************************************************/ /*************************************************************************** * 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 WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ // Mine #include "renderer.h" #include "kio_sword.h" #include "utils.h" #include "template.h" #include "option.h" // KDE #include #include #include #include #include // Qt #include #include // Standard C++ /C #include #include using namespace KIO; using std::list; using std::vector; // main -------------------------------------------------------------------------------------------------------- extern "C" { int kdemain(int argc, char **argv) { KInstance instance("kio_sword"); kdDebug(7101) << "*** Starting kio_sword " << endl; if (argc != 4) { kdDebug(7101) << "Usage: kio_sword protocol domain-socket1 domain-socket2" << endl; exit(-1); } KioSword::SwordProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); kdDebug(7101) << "*** kio_sword Done" << endl; return 0; } } namespace KioSword { class SwordOptions; // HTML fragments that will be initialised at run time ------------------------------------------------------------------------- static QString search_form; static QString help_page; SwordProtocol::SwordProtocol(const QCString & pool_socket, const QCString & app_socket) : SlaveBase("kio_sword", pool_socket, app_socket) { kdDebug() << "SwordProtocol::SwordProtocol()" << endl; m_config = KGlobal::config(); } SwordProtocol::~SwordProtocol() { kdDebug() << "SwordProtocol::~SwordProtocol()" << endl; } void SwordProtocol::get(const KURL & url) { QString modname; QString query; QString error; kdDebug() << "SwordProtocol::get(const KURL& url)" << endl; /* kdDebug() << "Seconds: " << url.query() << endl; QString remoteServer = url.host(); int remotePort = url.port(); kdDebug() << "myURL: " << url.prettyURL() << endl; */ // Send the mimeType as soon as it is known mimeType("text/html"); // Set user defaults from user config file // (with internal defaults supplied if any options // are missing from users config file) readUserConfig(); // Get options/actions from URL parseURL(url); if (!m_path.isEmpty() && m_path != "/") { if (!m_path.startsWith("/")) { // sword:xxx is a shortcut for bible verses modname = m_options.defaultBible(); if (modname.isEmpty()) { error = i18n("No default Bible has been specified."); } else { // do redirection query = m_path; KURL newurl(url); newurl.setPath('/' + modname + '/' + query); redirection(newurl); finished(); return; } } else { modname = m_path.section('/', 0, 0, QString::SectionSkipEmpty); query = m_path.section('/', 1, -1, QString::SectionSkipEmpty); } } // handle redirections first if (m_action == REDIRECT_QUERY) { if (!m_redirect.module.isEmpty()) modname = m_redirect.module; if (!m_redirect.query.isEmpty()) query = m_redirect.query; if (modname.isEmpty()) { switch (m_moduletype) { case DEFBIBLE: modname = m_options.defaultBible(); error = i18n("No default Bible has been specified."); break; case GREEKSTRONGS: modname = m_options.defaultGreekStrongs(); error = i18n("No default Greek Strongs module has been specified."); break; case HEBREWSTRONGS: modname = m_options.defaultHebrewStrongs(); error = i18n("No default Hebrew Strongs module has been specified."); break; case GREEKMORPH: modname = m_options.defaultGreekMorph(); error = i18n("No default Greek morphological module has been specified."); break; case HEBREWMORPH: modname = m_options.defaultHebrewMorph(); error = i18n("No default Hebrew morphological module has been specified."); break; case DEFMODULETYPE_NONE: error = i18n("No module specified."); } } if (modname.isEmpty()) { error = "

" + error + "


"; m_action = QUERY; // revert back to displaying list of modules } else { KURL newurl(url); // Remove anything that will trigger a redirection newurl.removeQueryItem("module"); newurl.removeQueryItem("query"); newurl.removeQueryItem("testsettings"); newurl.removeQueryItem("modtype"); newurl.setPath('/' + modname + '/' + query); redirection(newurl); finished(); return; } } // Send the data Template* tmplt = new Template(); tmplt->setCurrentPath(m_path); switch (m_action) { case QUERY: if (!modname.isEmpty()) { m_renderer.moduleQuery(modname, query, m_options, tmplt); } else { QString body; tmplt->setTitle(i18n("Modules - Kio-Sword")); if (!error.isEmpty()) { body = error; } body += m_renderer.listModules(m_options); tmplt->setContent(body); } break; case SEARCH_FORM: tmplt->setTitle(i18n("Search - Kio-Sword")); tmplt->setContent(searchForm(m_options)); break; case SEARCH_QUERY: tmplt->setTitle(i18n("Search Results - Kio-Sword")); tmplt->setContent(m_renderer.search(m_redirect.module, m_redirect.query, m_stype, m_options)); break; case SETTINGS_FORM: tmplt->setTitle(i18n("Settings - Kio-Sword")); tmplt->setContent(settingsForm()); break; case SETTINGS_SAVE: tmplt->setTitle(i18n("Settings saved - Kio-Sword")); tmplt->setContent(saveUserConfig()); break; case HELP: tmplt->setTitle(i18n("Kio-Sword Help")); tmplt->setContent(helpPage()); break; default: break; } sendPage(tmplt); delete tmplt; } void SwordProtocol::mimetype(const KURL& url) { mimeType("text/html"); finished(); } /* redefine data for QCStrings so we don't send the trailing null */ void SwordProtocol::data(const QCString& text) { QByteArray nonull; nonull.setRawData(text.data(), text.size()-1); SlaveBase::data(nonull); nonull.resetRawData(text.data(), text.size()-1); } void SwordProtocol::data(const QByteArray& array) { SlaveBase::data(array); } void SwordProtocol::readUserConfig() { m_options.readFromConfig(m_config); } QString SwordProtocol::saveUserConfig() { QString message; m_options.saveToConfig(m_config); m_config->sync(); // search form depends on settings, so force it to be recreated search_form.truncate(0); message = "

" + i18n("Settings saved.") + "

"; return message; } #define ENUM_OPTION(option, tag, v) \ if (!strcasecmp(key, tag)) { \ option = v; \ } void SwordProtocol::parseURL(const KURL& url) { // Reset data members that should always be // retrieved from URL m_action = QUERY; m_path = QString::null; m_redirect.module = QString::null; m_redirect.query = QString::null; m_previous.module = QString::null; m_previous.query = QString::null; m_moduletype = DEFMODULETYPE_NONE; if (url.hasPath()) m_path = url.path(); m_options.readFromQueryString(url.queryItems(KURL::CaseInsensitiveKeys)); // URLs will be encoded in UTF-8 since they are sometimes // generated from the search form, and the browser will // encode in UTF-8 since the whole page has UTF-8 charset QMap items = url.queryItems(KURL::CaseInsensitiveKeys, 106); QMap::const_iterator it; QMap::const_iterator it_end = items.end(); QString val; const char *key; for(it = items.begin(); it != it_end; it++) { key = it.key().latin1(); val = it.data(); if (!strcasecmp(key, "query")) { m_redirect.query = val; } else if (!strcasecmp(key, "module")) { m_redirect.module = val; } else if (!strcasecmp(key, "modtype")) { if (!strcasecmp(val, "bible")) { m_moduletype = DEFBIBLE; m_action = REDIRECT_QUERY; } else if (!strcasecmp(val, "greekstrongs")) { m_moduletype = GREEKSTRONGS; m_action = REDIRECT_QUERY; } else if (!strcasecmp(val, "hebrewstrongs")) { m_moduletype = HEBREWSTRONGS; m_action = REDIRECT_QUERY; } else if (!strcasecmp(val, "greekmorph")) { m_moduletype = GREEKMORPH; m_action = REDIRECT_QUERY; } else if (!strcasecmp(val, "hebrewmorph")) { m_moduletype = HEBREWMORPH; m_action = REDIRECT_QUERY; } } // search else if (!strcasecmp(key, "stype")) { if (!strcasecmp(val, "words")) { m_stype = Renderer::SEARCH_WORDS; } else if (!strcasecmp(val, "phrase")) { m_stype = Renderer::SEARCH_PHRASE; } else if (!strcasecmp(val, "regex")) { m_stype = Renderer::SEARCH_REGEX; } else { m_stype = Renderer::SEARCH_WORDS; } } // Actions else ENUM_OPTION(m_action, "help", HELP) else ENUM_OPTION(m_action, "search", SEARCH_FORM) else ENUM_OPTION(m_action, "searchq", SEARCH_QUERY) else ENUM_OPTION(m_action, "settings", SETTINGS_FORM) else ENUM_OPTION(m_action, "savesettings", SETTINGS_SAVE) else ENUM_OPTION(m_action, "testsettings", REDIRECT_QUERY) else if (!strcasecmp(key, "previouspath")) { m_previous.module = val.section('/', 0, 0, QString::SectionSkipEmpty); m_previous.query = val.section('/', 1, -1, QString::SectionSkipEmpty); } } // Once all the URL is parsed: if ((m_action == QUERY) && ( !m_redirect.query.isEmpty() || !m_redirect.module.isEmpty())) m_action = REDIRECT_QUERY; } #undef ENUM_OPTION void SwordProtocol::sendPage(const Template* tplt) { data(tplt->render(m_options)); data(QByteArray()); // empty array means we're done sending the data finished(); } /** Returns a string representing notes about an option for the settings page */ template QString optionNotes(const Option& option) { QString output; if (!option.m_propagate) { output += "1"; } if (option.m_configName.isNull()) { if (output.length() > 0) { output += ","; } output += "2"; } return output; } /** HTML for a boolean option */ QString settingsBooleanOptionRow(const QString& description, const Option& option) { static const QString boolean_option_row( "%1%4   %6%2, %7"); return boolean_option_row .arg(description + optionNotes(option)) .arg(option.m_qsShortName) .arg(option.m_qsShortName) .arg(option.m_qsShortName) .arg(option() ? "checked" : "") .arg(i18n("On")) .arg(option() ? "" : "checked") .arg(i18n("Off")) .arg(option.m_qsLongName); } /** */ /** HTML for a general option row * * @param description User visible description of option * @param option option metadata * @param optionList HTML containing the