subs;
++ subs['Q'] = (const char *)m_query.query.toUtf8();
++ subs['C'] = catgq;
++ subs['S'] = "";
++ pcSubst(welcomedata, tmp, subs);
++ data(tmp.c_str());
++}
++
++void RecollProtocol::queryDetails()
++{
++ mimeType("text/html");
++ QByteArray array;
++ QTextStream os(&array, QIODevice::WriteOnly);
++
++ os << "" << endl;
++ os << "" << endl;
++ os << "" << "Recoll query details" << "\n" << endl;
++ os << "" << endl;
++ os << "Query details:
" << endl;
++ os << "" << m_pager.queryDescription().c_str() <<"
"<< endl;
++ os << "Return to results" << endl;
++ os << "" << endl;
++ data(array);
++}
++
++class PlainToRichKio : public PlainToRich {
++public:
++ PlainToRichKio(const string& nm)
++ : m_name(nm)
++ {
++ }
++
++ virtual string header() {
++ if (m_inputhtml) {
++ return cstr_null;
++ } else {
++ return string("
"
++ "").
++ append(m_name).
++ append("");
++ }
++ }
++
++ virtual string startMatch(unsigned int)
++ {
++ return string("");
++ }
++
++ virtual string endMatch()
++ {
++ return string("");
++ }
++
++ const string &m_name;
++};
++
++void RecollProtocol::showPreview(const Rcl::Doc& idoc)
++{
++ FileInterner interner(idoc, o_rclconfig, FileInterner::FIF_forPreview);
++ Rcl::Doc fdoc;
++ string ipath = idoc.ipath;
++ if (!interner.internfile(fdoc, ipath)) {
++ error(KIO::ERR_SLAVE_DEFINED, "Cannot convert file to internal format");
++ return;
++ }
++ if (!interner.get_html().empty()) {
++ fdoc.text = interner.get_html();
++ fdoc.mimetype = "text/html";
++ }
++
++ mimeType("text/html");
++
++ string fname = path_getsimple(fdoc.url).c_str();
++ PlainToRichKio ptr(fname);
++ ptr.set_inputhtml(!fdoc.mimetype.compare("text/html"));
++ list otextlist;
++ HighlightData hdata;
++ if (m_source)
++ m_source->getTerms(hdata);
++ ptr.plaintorich(fdoc.text, otextlist, hdata);
++
++ QByteArray array;
++ QTextStream os(&array, QIODevice::WriteOnly);
++ for (list::iterator it = otextlist.begin();
++ it != otextlist.end(); it++) {
++ os << (*it).c_str();
++ }
++ os << "" << endl;
++ data(array);
++}
++
++void RecollProtocol::htmlDoSearch(const QueryDesc& qd)
++{
++ kDebug() << "q" << qd.query << "option" << qd.opt << "page" << qd.page <<
++ "isdet" << qd.isDetReq << endl;
++
++ mimeType("text/html");
++
++ if (!syncSearch(qd))
++ return;
++ // syncSearch/doSearch do the setDocSource when needed
++ if (m_pager.pageNumber() < 0) {
++ m_pager.resultPageNext();
++ }
++ if (qd.isDetReq) {
++ queryDetails();
++ return;
++ }
++
++ // Check / adjust page number
++ if (qd.page > m_pager.pageNumber()) {
++ int npages = qd.page - m_pager.pageNumber();
++ for (int i = 0; i < npages; i++)
++ m_pager.resultPageNext();
++ } else if (qd.page < m_pager.pageNumber()) {
++ int npages = m_pager.pageNumber() - qd.page;
++ for (int i = 0; i < npages; i++)
++ m_pager.resultPageBack();
++ }
++ // Display
++ m_pager.displayPage(o_rclconfig);
++}
+diff --git a/kde/kioslave/kio_recoll-kde4/kio_recoll.cpp b/kde/kioslave/kio_recoll-kde4/kio_recoll.cpp
+new file mode 100644
+index 0000000..a7db617
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/kio_recoll.cpp
+@@ -0,0 +1,381 @@
++/* Copyright (C) 2005 J.F.Dockes
++ * 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.
++ */
++
++#include
++#include
++#include
++#include
++
++#include
++using namespace std;
++
++#include
++#include
++#include
++#include
++
++#include
++#include
++#include
++
++#include "rclconfig.h"
++#include "rcldb.h"
++#include "rclinit.h"
++#include "pathut.h"
++#include "searchdata.h"
++#include "rclquery.h"
++#include "wasatorcl.h"
++#include "kio_recoll.h"
++#include "docseqdb.h"
++#include "readfile.h"
++#include "smallut.h"
++#include "textsplit.h"
++#include "guiutils.h"
++
++using namespace KIO;
++
++RclConfig *RecollProtocol::o_rclconfig;
++
++RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app)
++ : SlaveBase("recoll", pool, app), m_initok(false), m_rcldb(0),
++ m_alwaysdir(false)
++{
++ kDebug() << endl;
++ if (o_rclconfig == 0) {
++ o_rclconfig = recollinit(0, 0, m_reason);
++ if (!o_rclconfig || !o_rclconfig->ok()) {
++ m_reason = string("Configuration problem: ") + m_reason;
++ return;
++ }
++ }
++ if (o_rclconfig->getDbDir().empty()) {
++ // Note: this will have to be replaced by a call to a
++ // configuration building dialog for initial configuration? Or
++ // do we assume that the QT GUO is always used for this ?
++ m_reason = "No db directory in configuration ??";
++ return;
++ }
++ rwSettings(false);
++
++ m_rcldb = new Rcl::Db(o_rclconfig);
++ if (!m_rcldb) {
++ m_reason = "Could not build database object. (out of memory ?)";
++ return;
++ }
++
++ // Decide if we allow switching between html and file manager
++ // presentation by using an end slash or not. Can also be done dynamically
++ // by switching proto names.
++ const char *cp = getenv("RECOLL_KIO_ALWAYS_DIR");
++ if (cp) {
++ m_alwaysdir = stringToBool(cp);
++ } else {
++ o_rclconfig->getConfParam("kio_always_dir", &m_alwaysdir);
++ }
++
++ cp = getenv("RECOLL_KIO_STEMLANG");
++ if (cp) {
++ m_stemlang = cp;
++ } else {
++ m_stemlang = "english";
++ }
++ m_pager.setParent(this);
++ m_initok = true;
++ return;
++}
++
++// There should be an object counter somewhere to delete the config when done.
++// Doesn't seem needed in the kio context.
++RecollProtocol::~RecollProtocol()
++{
++ kDebug();
++ delete m_rcldb;
++}
++
++bool RecollProtocol::maybeOpenDb(string &reason)
++{
++ if (!m_rcldb) {
++ reason = "Internal error: initialization error";
++ return false;
++ }
++ if (!m_rcldb->isopen() && !m_rcldb->open(Rcl::Db::DbRO)) {
++ reason = "Could not open database in " + o_rclconfig->getDbDir();
++ return false;
++ }
++ return true;
++}
++
++// This is never called afaik
++void RecollProtocol::mimetype(const KUrl &url)
++{
++ kDebug() << url << endl;
++ mimeType("text/html");
++ finished();
++}
++
++UrlIngester::UrlIngester(RecollProtocol *p, const KUrl& url)
++ : m_parent(p), m_slashend(false), m_alwaysdir(false),
++ m_retType(UIRET_NONE), m_resnum(0), m_type(UIMT_NONE)
++{
++ kDebug() << "Url" << url;
++ m_alwaysdir = !url.protocol().compare("recollf");
++ QString path = url.path();
++ if (url.host().isEmpty()) {
++ if (path.isEmpty() || !path.compare("/")) {
++ m_type = UIMT_ROOTENTRY;
++ m_retType = UIRET_ROOT;
++ return;
++ } else if (!path.compare("/help.html")) {
++ m_type = UIMT_ROOTENTRY;
++ m_retType = UIRET_HELP;
++ return;
++ } else if (!path.compare("/search.html")) {
++ m_type = UIMT_ROOTENTRY;
++ m_retType = UIRET_SEARCH;
++ // Retrieve the query value for preloading the form
++ m_query.query = url.queryItem("q");
++ return;
++ } else if (m_parent->isRecollResult(url, &m_resnum, &m_query.query)) {
++ m_type = UIMT_QUERYRESULT;
++ m_query.opt = "l";
++ m_query.page = 0;
++ } else {
++ // Have to think this is some search string
++ m_type = UIMT_QUERY;
++ m_query.query = url.path();
++ m_query.opt = "l";
++ m_query.page = 0;
++ }
++ } else {
++ // Non empty host, url must be something like :
++ // //search/query?q=query¶m=value...
++ kDebug() << "host" << url.host() << "path" << url.path();
++ if (url.host().compare("search") || url.path().compare("/query")) {
++ return;
++ }
++ m_type = UIMT_QUERY;
++ // Decode the forms' arguments
++ m_query.query = url.queryItem("q");
++
++ m_query.opt = url.queryItem("qtp");
++ if (m_query.opt.isEmpty()) {
++ m_query.opt = "l";
++ }
++ QString p = url.queryItem("p");
++ if (p.isEmpty()) {
++ m_query.page = 0;
++ } else {
++ sscanf(p.toAscii(), "%d", &m_query.page);
++ }
++ p = url.queryItem("det");
++ m_query.isDetReq = !p.isEmpty();
++
++ p = url.queryItem("cmd");
++ if (!p.isEmpty() && !p.compare("pv")) {
++ p = url.queryItem("dn");
++ if (!p.isEmpty()) {
++ // Preview and no docnum ??
++ m_resnum = atoi((const char *)p.toUtf8());
++ // Result in page is 1+
++ m_resnum--;
++ m_type = UIMT_PREVIEW;
++ }
++ }
++ }
++ if (m_query.query.startsWith("/"))
++ m_query.query.remove(0,1);
++ if (m_query.query.endsWith("/")) {
++ kDebug() << "Ends with /";
++ m_slashend = true;
++ m_query.query.chop(1);
++ } else {
++ m_slashend = false;
++ }
++ return;
++}
++
++bool RecollProtocol::syncSearch(const QueryDesc &qd)
++{
++ kDebug();
++ if (!m_initok || !maybeOpenDb(m_reason)) {
++ string reason = "RecollProtocol::listDir: Init error:" + m_reason;
++ error(KIO::ERR_SLAVE_DEFINED, reason.c_str());
++ return false;
++ }
++ if (qd.sameQuery(m_query)) {
++ return true;
++ }
++ // doSearch() calls error() if appropriate.
++ return doSearch(qd);
++}
++
++// This is used by the html interface, but also by the directory one
++// when doing file copies for exemple. This is the central dispatcher
++// for requests, it has to know a little about both models.
++void RecollProtocol::get(const KUrl& url)
++{
++ kDebug() << url << endl;
++
++ if (!m_initok || !maybeOpenDb(m_reason)) {
++ string reason = "Recoll: init error: " + m_reason;
++ error(KIO::ERR_SLAVE_DEFINED, reason.c_str());
++ return;
++ }
++
++ UrlIngester ingest(this, url);
++ UrlIngester::RootEntryType rettp;
++ QueryDesc qd;
++ int resnum;
++ if (ingest.isRootEntry(&rettp)) {
++ switch(rettp) {
++ case UrlIngester::UIRET_HELP:
++ {
++ QString location =
++ KStandardDirs::locate("data", "kio_recoll/help.html");
++ redirection(location);
++ }
++ goto out;
++ default:
++ searchPage();
++ goto out;
++ }
++ } else if (ingest.isResult(&qd, &resnum)) {
++ // Url matched one generated by konqueror/Dolphin out of a
++ // search directory listing: ie:
++ // recoll:/some search string/recollResultxx
++ //
++ // This happens when the user drags/drop the result to another
++ // app, or with the "open-with" right-click. Does not happen
++ // if the entry itself is clicked (the UDS_URL is apparently
++ // used in this case
++ //
++ // Redirect to the result document URL
++ if (!syncSearch(qd)) {
++ return;
++ }
++ Rcl::Doc doc;
++ if (resnum >= 0 && m_source && m_source->getDoc(resnum, doc)) {
++ mimeType(doc.mimetype.c_str());
++ redirection(KUrl::fromLocalFile((const char *)(doc.url.c_str()+7)));
++ goto out;
++ }
++ } else if (ingest.isPreview(&qd, &resnum)) {
++ if (!syncSearch(qd)) {
++ return;
++ }
++ Rcl::Doc doc;
++ if (resnum >= 0 && m_source && m_source->getDoc(resnum, doc)) {
++ showPreview(doc);
++ goto out;
++ }
++ } else if (ingest.isQuery(&qd)) {
++#if 0
++// Do we need this ?
++ if (host.isEmpty()) {
++ char cpage[20];sprintf(cpage, "%d", page);
++ QString nurl = QString::fromAscii("recoll://search/query?q=") +
++ query + "&qtp=" + opt + "&p=" + cpage;
++ redirection(KUrl(nurl));
++ goto out;
++ }
++#endif
++ // htmlDoSearch does the search syncing (needs to know about changes).
++ htmlDoSearch(qd);
++ goto out;
++ }
++
++ error(KIO::ERR_SLAVE_DEFINED, "Unrecognized URL or internal error");
++ out:
++ finished();
++}
++
++// Execute Recoll search, and set the docsource
++bool RecollProtocol::doSearch(const QueryDesc& qd)
++{
++ kDebug() << "query" << qd.query << "opt" << qd.opt;
++ m_query = qd;
++
++ char opt = qd.opt.isEmpty() ? 'l' : qd.opt.toUtf8().at(0);
++ string qs = (const char *)qd.query.toUtf8();
++ Rcl::SearchData *sd = 0;
++ if (opt != 'l') {
++ Rcl::SearchDataClause *clp = 0;
++ if (opt == 'f') {
++ clp = new Rcl::SearchDataClauseFilename(qs);
++ } else {
++ clp = new Rcl::SearchDataClauseSimple(opt == 'o' ? Rcl::SCLT_OR :
++ Rcl::SCLT_AND, qs);
++ }
++ sd = new Rcl::SearchData(Rcl::SCLT_OR, m_stemlang);
++ if (sd && clp)
++ sd->addClause(clp);
++ } else {
++ sd = wasaStringToRcl(o_rclconfig, m_stemlang, qs, m_reason);
++ }
++ if (!sd) {
++ m_reason = "Internal Error: cant build search";
++ error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
++ return false;
++ }
++
++ std::shared_ptr sdata(sd);
++ std::shared_ptrquery(new Rcl::Query(m_rcldb));
++ query->setCollapseDuplicates(prefs.collapseDuplicates);
++ if (!query->setQuery(sdata)) {
++ m_reason = "Query execute failed. Invalid query or syntax error?";
++ error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
++ return false;
++ }
++
++ DocSequenceDb *src =
++ new DocSequenceDb(std::shared_ptr(query), "Query results", sdata);
++ if (src == 0) {
++ error(KIO::ERR_SLAVE_DEFINED, "Can't build result sequence");
++ return false;
++ }
++ m_source = std::shared_ptr(src);
++ // Reset pager in all cases. Costs nothing, stays at page -1 initially
++ // htmldosearch will fetch the first page if needed.
++ m_pager.setDocSource(m_source);
++ return true;
++}
++
++// Note: KDE_EXPORT is actually needed on Unix when building with
++// cmake. Says something like __attribute__(visibility(defautl))
++// (cmake apparently sets all symbols to not exported)
++extern "C" {KDE_EXPORT int kdemain(int argc, char **argv);}
++
++int kdemain(int argc, char **argv)
++{
++#ifdef KDE_VERSION_3
++ KInstance instance("kio_recoll");
++#else
++ KComponentData instance("kio_recoll");
++#endif
++ kDebug() << "*** starting kio_recoll " << endl;
++
++ if (argc != 4) {
++ kDebug() << "Usage: kio_recoll proto dom-socket1 dom-socket2\n" << endl;
++ exit(-1);
++ }
++
++ RecollProtocol slave(argv[2], argv[3]);
++ slave.dispatchLoop();
++
++ kDebug() << "kio_recoll Done" << endl;
++ return 0;
++}
+diff --git a/kde/kioslave/kio_recoll-kde4/kio_recoll.h b/kde/kioslave/kio_recoll-kde4/kio_recoll.h
+new file mode 100644
+index 0000000..c2da557
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/kio_recoll.h
+@@ -0,0 +1,191 @@
++#ifndef _RECOLL_H
++#define _RECOLL_H
++/* Copyright (C) 2005 J.F.Dockes
++ * 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.
++ */
++
++#include
++using std::string;
++
++#include
++#include
++
++#include
++#include
++#include
++#include
++
++#include "rclconfig.h"
++#include "rcldb.h"
++#include "reslistpager.h"
++#include "docseq.h"
++#include
++
++class RecollProtocol;
++
++/** Specialize the recoll html pager for the kind of links we use etc. */
++class RecollKioPager : public ResListPager {
++public:
++ RecollKioPager() : m_parent(0) {}
++ void setParent(RecollProtocol *proto) {m_parent = proto;}
++
++ virtual bool append(const string& data);
++ virtual bool append(const string& data, int, const Rcl::Doc&)
++ {return append(data);}
++ virtual string detailsLink();
++ virtual const string &parFormat();
++ virtual string nextUrl();
++ virtual string prevUrl();
++ virtual string pageTop();
++
++private:
++ RecollProtocol *m_parent;
++};
++
++class QueryDesc {
++public:
++ QueryDesc() : opt("l"), page(0), isDetReq(false) {}
++ QString query;
++ QString opt;
++ int page;
++ bool isDetReq;
++ bool sameQuery(const QueryDesc& o) const {
++ return !opt.compare(o.opt) && !query.compare(o.query);
++ }
++};
++
++// Our virtual tree is a bit complicated. We need a class to analyse an URL
++// and tell what we should do with it
++class UrlIngester {
++public:
++ UrlIngester(RecollProtocol *p, const KUrl& url);
++ enum RootEntryType {UIRET_NONE, UIRET_ROOT, UIRET_HELP, UIRET_SEARCH};
++ bool isRootEntry(RootEntryType *tp) {
++ if (m_type != UIMT_ROOTENTRY) return false;
++ *tp = m_retType;
++ return true;
++ }
++ bool isQuery(QueryDesc *q) {
++ if (m_type != UIMT_QUERY) return false;
++ *q = m_query;
++ return true;
++ }
++ bool isResult(QueryDesc *q, int *num) {
++ if (m_type != UIMT_QUERYRESULT) return false;
++ *q = m_query;
++ *num = m_resnum;
++ return true;
++ }
++ bool isPreview(QueryDesc *q, int *num) {
++ if (m_type != UIMT_PREVIEW) return false;
++ *q = m_query;
++ *num = m_resnum;
++ return true;
++ }
++ bool endSlashQuery() {return m_slashend;}
++ bool alwaysDir() {return m_alwaysdir;}
++
++private:
++ RecollProtocol *m_parent;
++ QueryDesc m_query;
++ bool m_slashend;
++ bool m_alwaysdir;
++ RootEntryType m_retType;
++ int m_resnum;
++ enum MyType {UIMT_NONE, UIMT_ROOTENTRY, UIMT_QUERY, UIMT_QUERYRESULT,
++ UIMT_PREVIEW};
++ MyType m_type;
++};
++
++
++/**
++ * A KIO slave to execute and display Recoll searches.
++ *
++ * Things are made a little complicated because KIO slaves can't hope
++ * that their internal state will remain consistent with their user
++ * application state: slaves die, are restarted, reused, at random
++ * between requests.
++ * In our case, this means that any request has to be processed
++ * without reference to the last operation performed. Ie, if the
++ * search parameters are not those from the last request, the search
++ * must be restarted anew. This happens for example with different
++ * searches in 2 konqueror screens: typically only one kio_slave will
++ * be used.
++ * The fact that we check if the search is the same as the last one,
++ * to avoid restarting is an optimization, not the base mechanism
++ * (contrary to what was initially assumed, and may have left a few
++ * crumbs around).
++ *
++ * We have two modes of operation, one based on html forms and result
++ * pages, which can potentially be developped to the full Recoll
++ * functionality, and one based on a directory listing model, which
++ * will always be more limited, but may be useful in some cases to
++ * allow easy copying of files etc. Which one is in use is decided by
++ * the form of the URL.
++ */
++class RecollProtocol : public KIO::SlaveBase {
++ public:
++ RecollProtocol(const QByteArray &pool, const QByteArray &app );
++ virtual ~RecollProtocol();
++ virtual void mimetype(const KUrl& url);
++ virtual void get(const KUrl& url);
++ // The directory mode is not available with KDE 4.0, I could find
++ // no way to avoid crashing kdirmodel
++#if KDE_IS_VERSION(4,1,0)
++ virtual void stat(const KUrl & url);
++ virtual void listDir(const KUrl& url);
++#endif
++
++ static RclConfig *o_rclconfig;
++
++ friend class RecollKioPager;
++ friend class UrlIngester;
++
++ private:
++ bool maybeOpenDb(string& reason);
++ bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0);
++ bool doSearch(const QueryDesc& qd);
++
++ void searchPage();
++ void queryDetails();
++ string makeQueryUrl(int page, bool isdet = false);
++ bool syncSearch(const QueryDesc& qd);
++ void htmlDoSearch(const QueryDesc& qd);
++ void showPreview(const Rcl::Doc& doc);
++ bool isRecollResult(const KUrl &url, int *num, QString* q);
++
++ bool m_initok;
++ Rcl::Db *m_rcldb;
++ string m_reason;
++ bool m_alwaysdir;
++ string m_stemlang; // english by default else env[RECOLL_KIO_STEMLANG]
++
++ // Search state: because of how the KIO slaves are used / reused,
++ // we can't be sure that the next request will be for the same
++ // search, and we need to check and restart one if the data
++ // changes. This is very wasteful but hopefully won't happen too
++ // much in actual use. One possible workaround for some scenarios
++ // (one slave several konqueror windows) would be to have a small
++ // cache of recent searches kept open.
++ RecollKioPager m_pager;
++ std::shared_ptr m_source;
++ // Note: page here is not used, current page always comes from m_pager.
++ QueryDesc m_query;
++};
++
++extern "C" {int kdemain(int, char**);}
++
++#endif // _RECOLL_H
+diff --git a/kde/kioslave/kio_recoll-kde4/notes.txt b/kde/kioslave/kio_recoll-kde4/notes.txt
+new file mode 100644
+index 0000000..8b8127f
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/notes.txt
+@@ -0,0 +1,188 @@
++Recoll KIO Slave notes/todoes/etc.
++
++Goal: access Recoll search from other applications.
++
++We want to allow URLs like recoll:/?? to be used inside
++Konqueror/Dolphin and open dialogs, to start a search with results
++displayed/used inside the application.
++
++
++Todoes
++======
++
++
++Implementation notes:
++====================
++
++- There are two main ways to do this:
++ - a-la kio_beagle, using listDir() to list entries pointing to the
++ different operations or objects (help, status, search result
++ entries, bookmarks, whatever...). The nice thing is that the
++ results really look like file object in a directory (probably,
++ didn't try it actually), no need for look and feel, it's provided by
++ KDE
++
++ - Or a la strigi: all interactions are through html pages and get()
++ operations. Much simpler, but does not allow file management
++ operations (except by drag/drop from the result list), and can't
++ use it inside other application's Open dialogs.
++
++Recoll is currently doing both things on KDE4.1 (only html for KDE4.0).
++
++
++Virtual tree:
++=============
++
++recoll:
++recoll:/
++recoll:/help.html
++recoll:/search.html
++ Purely synthetic top level entries. Yes, given the following, this means
++ that you can't search for 'help.html' directly (but you can do it through
++ the html interface). These have to exist in the top level directory
++
++recoll:/some search string
++recoll:/some search string/
++ We have a 'mode' determined by the protocol name:
++ recoll -> mixed
++ recollf -> file manager
++ - html mode: these redirect to recoll://search/query?q="some search string"
++ - file manager mode: do the search and display results.
++ - mixed mode: what mode is entered depends on ending /
++
++recoll://search/query?q=...
++ html mode search
++
++recoll:/some search string/recollResultxyz
++xyz is the index in result list.
++
++When generating a directory, with use bogus names for the result
++entries (the displayed ones are from UDS_DISPLAY_NAME and are the real
++names). When doing drag/drop or "open with" Konqueror/Dolphin builds
++an url by concatenating the current directory name and the UDS_NAME,
++instead of using UDS_TARGET_URL as when the entry is clicked. This
++forces us to use identifying names including the result number, which
++has many ennoying side effects (such as the target app not knowing the
++real file path...
++
++
++KIO notes:
++=========
++
++- Slaves are reused seemingly at random. Even with connection-oriented
++ ones (ie ftp), you can have 2 konqueror windows on different hosts
++ with only one slave which will have to close/reopen the connection at
++ each switch.
++ For slaves with really expensive internal state, this is very wasteful.
++
++- Use cases for father_url+name or target_url are ill defined.
++- Need a way to block autocompletion queries !
++- No way to display the target URL in konqueror
++
++Todoes
++======
++- Improve the html interface to support more functions
++ - Category filtering
++ - Sorting
++
++- Find a way to use the html form to enter the query and get the
++ results as a directory ? - Would it be possible to use a redirect
++ to switch to the directory-oriented results for a query from the
++ html form ?
++ -> No, even a redirect to a form that would initially trigger a
++ listDir() triggers a get() when performed from a get()
++
++KDE misc notes
++==================
++Debug areas: /usr/share/kde4/config/kdebug.areas
++kdebugdialog [--fullmode] pour configurer
++./.kde/share/config/kdebugrc
++Output to ~/.xession-errors by default. How to change ?
++
++kio_recoll misc notes:
++===========================
++Probleme quand l'url se termine par un / et qu'on edite le mot,
++konqueror lance une recherche a chaque lettre.
++
++Apparemment c'est l'entree "listing" du .protocol qui decide si le plugin
++est traité plutot comme un dirlister ou comme un htmlgetter. Curieusement,
++le changement ne s'opere pas toujours immediatement quand on change le
++fichier .proto, y compris apres avoir tue tous les process kde (changement
++ŕ la deuxieme execution de konqueror sur kde4.0). Sur kde4.0 il faut que le
++.proto soit sans entree "listing"
++
++Problemes de gestion de l'etat
++===============================
++Les KIO slaves ne sont pas associes a une fenetre ! ils sont
++reutilises au hasard, et leur etat n'a aucune raison de correspondre a
++celui de l'affichage. On peut tres bien avoir 1 fenetre 2 kio ou 1 kio
++deux fenetres, et le next d'un search peut arriver au kio qui a
++l'autre search, donc n'importenaouak. Il faudrait que l'etat soit
++partage et accede par un identifiant uniquement determine par l'url de
++la fenetre.
++
++Meme pour une fenetre unique, au bout d'un moment le kio timeout et exite.
++
++En fait les slaves ne peuvent pas stocker d'etat du tout. Donc:
++ - soit un serveur central auquel ils parlent
++ - soit ils relancent dynamiquement les recherches si pas de match
++C'est vrai aussi bien pour les dirlists que pour la version html.
++
++J'ai essaye de mettre une boucle timeout callback callspecial() mais
++ca ne sert a rien, c'est gere dans le process kio_slave, ca ne
++maintient pas l'association avec un konqueror.
++
++KDE_FORK_SLAVES sort of solves the problem in a limited way:
++ - It applies to an application instance, not a KIO slave type, so it
++ affects other KIO usages.
++ - If the application has 2 sessions with the same KIO there are no
++ warranties that 1 kio per session will be used ?
++
++
++
++Old KDE3 notes,
++===============
++
++kio_recoll has not been checked or worked under KDE3 for eons, no
++reason to believe it works.
++
++- Not using libtool. Probably should. compilation flags in the Makefile
++ were copy-pasted from a kdebase compilation tree on FreeBSD (kio/man).
++- You MUST install a kio_recoll.la in lib/kde3 along with kio_recoll.so,
++ else kdeinit won't be able to load the lib (probably uses the libltdl
++ thingy?). The one in this directory was duplicated/adjusted from
++ kio_man.la. The contents don't seem too critical, just needs to exist.
++- If you want to try, compile, then install kio_recoll.la kio_recoll.so
++ wherever kde keeps its plugins (ie: lib/kde3), and recoll.protocol in the
++ services directory (share/services ? look for other .protocol file).
++- I saw after doing the build/config mockup that kdevelop can generate a
++ kio_slave project. This might be the next thing to do. otoh would need to
++ separate the kio from the main source to avoid having to distribute 2megs
++ of kde build config files.
++
++
++
++Connected mode
++==============
++Tried to add bogus connection status to see if this would prevent switching between apps/slaves, doesnt... checked that's the same for kio_ftp
++
++void RecollProtocol::openConnection()
++{
++ kDebug();
++ connected();
++}
++void RecollProtocol::closeConnection()
++{
++ kDebug();
++}
++void RecollProtocol::setHost(const QString& host, quint16,
++ const QString&, const QString&)
++{
++ kDebug() << host;
++}
++void RecollProtocol::slave_status()
++{
++ kDebug();
++ slaveStatus("search", true);
++}
+++ connected(); call in maybeopendb()
+diff --git a/kde/kioslave/kio_recoll-kde4/recoll.protocol b/kde/kioslave/kio_recoll-kde4/recoll.protocol
+new file mode 100644
+index 0000000..c69fc77
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/recoll.protocol
+@@ -0,0 +1,11 @@
++[Protocol]
++exec=kio_recoll
++protocol=recoll
++input=none
++output=filesystem
++listing=Name,Type, URL
++reading=true
++defaultMimeType=text/html
++Icon=recoll
++Class=:local
++URIMode=rawuri
+diff --git a/kde/kioslave/kio_recoll-kde4/recollf.protocol b/kde/kioslave/kio_recoll-kde4/recollf.protocol
+new file mode 100644
+index 0000000..fb150ec
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/recollf.protocol
+@@ -0,0 +1,11 @@
++[Protocol]
++exec=kio_recoll
++protocol=recollf
++input=none
++output=filesystem
++listing=Name,Type, URL
++reading=true
++defaultMimeType=text/html
++Icon=recoll
++Class=:local
++URIMode=rawuri
+diff --git a/kde/kioslave/kio_recoll-kde4/recollnolist.protocol b/kde/kioslave/kio_recoll-kde4/recollnolist.protocol
+new file mode 100644
+index 0000000..cb5d55e
+--- /dev/null
++++ b/kde/kioslave/kio_recoll-kde4/recollnolist.protocol
+@@ -0,0 +1,11 @@
++[Protocol]
++exec=kio_recoll
++protocol=recoll
++input=none
++output=filesystem
++# Version for kde4.0: no "listing" entry
++reading=true
++defaultMimeType=text/html
++Icon=recoll
++Class=:local
++URIMode=rawuri
diff --git a/kde/kioslave/kio_recoll/dirif.cpp b/kde/kioslave/kio_recoll/dirif.cpp
index 3a96891..9d0a5f8 100644
--- a/kde/kioslave/kio_recoll/dirif.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index b50345ea..f24534fe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -333,6 +333,19 @@ kde/kioslave/kio_recoll/recollf.protocol \
kde/kioslave/kio_recoll/recollnolist.protocol \
kde/kioslave/kio_recoll/recoll.protocol \
\
+kde/kioslave/kio_recoll-kde4/00README.txt \
+kde/kioslave/kio_recoll-kde4/CMakeLists.txt \
+kde/kioslave/kio_recoll-kde4/data/help.html \
+kde/kioslave/kio_recoll-kde4/data/searchable.html \
+kde/kioslave/kio_recoll-kde4/data/welcome.html \
+kde/kioslave/kio_recoll-kde4/dirif.cpp \
+kde/kioslave/kio_recoll-kde4/htmlif.cpp \
+kde/kioslave/kio_recoll-kde4/kio_recoll.cpp \
+kde/kioslave/kio_recoll-kde4/kio_recoll.h \
+kde/kioslave/kio_recoll-kde4/recollf.protocol \
+kde/kioslave/kio_recoll-kde4/recollnolist.protocol \
+kde/kioslave/kio_recoll-kde4/recoll.protocol \
+\
query/location.hh query/position.hh query/stack.hh \
\
qtgui/advsearch.ui \
diff --git a/src/VERSION b/src/VERSION
index a6c2798a..49e0a31d 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.23.0
+1.23.1
diff --git a/website/pages/recoll-windows.txt b/website/pages/recoll-windows.txt
index 079dc966..9c5c8518 100644
--- a/website/pages/recoll-windows.txt
+++ b/website/pages/recoll-windows.txt
@@ -17,7 +17,20 @@ distribute the program, you probably know the GPL, else you should read it.
NOTE: As much as I have fun writing software, producing the Windows version is
just tedious. If you use Recoll on Windows, please consider contributing to
-its availability: image:/donations/btn_donate_LG.gif[link="/donations/index.html"]
+its availability: image:/donations/btn_donate_LG.gif
+
+////
+
+[link="/donations/index.html"]
+
+////
+
+_Ok, so, in the last months, there have been hundreds of downloads of the
+recoll-for-windows installer, and nobody used the donate button. I
+certainly did not expect more than a small proportion of users to donate,
+but *none* is sort of disturbing. The download files are gone while I
+ponder if I'll just scrap the build or find a way to entice more
+donations._
== Note for updating