cleaned up virtual tree and url handling. Drag to desktop now works with appropriate name. recollf protocol

This commit is contained in:
dockes 2008-12-03 17:04:20 +00:00
parent 8b164381d2
commit 0b649ae8d6
7 changed files with 320 additions and 187 deletions

View File

@ -95,7 +95,7 @@ target_link_libraries(kio_recoll xapian ${EXTRA_LIBS} ${KDE4_KIO_LIBS})
install(TARGETS kio_recoll DESTINATION ${PLUGIN_INSTALL_DIR}) install(TARGETS kio_recoll DESTINATION ${PLUGIN_INSTALL_DIR})
IF ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0) IF ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0)
install(FILES recoll.protocol DESTINATION ${SERVICES_INSTALL_DIR}) install(FILES recoll.protocol recollf.protocol DESTINATION ${SERVICES_INSTALL_DIR})
ELSE ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0) ELSE ("${KDE_VERSION_MAJOR}.${KDE_VERSION_MINOR}" GREATER 4.0)
install(FILES recollnolist.protocol DESTINATION ${SERVICES_INSTALL_DIR} install(FILES recollnolist.protocol DESTINATION ${SERVICES_INSTALL_DIR}
RENAME recoll.protocol) RENAME recoll.protocol)

View File

@ -4,7 +4,7 @@
<title>Recoll Kio Slave</title> <title>Recoll Kio Slave</title>
</head> </head>
<body> <body>
<a href="recoll:///welcome">Recoll search</a> <a href="recoll:///search.html">Recoll search</a>
<h3>Recoll kio slave</h3> <h3>Recoll kio slave</h3>
<p>Use this module to perform Recoll searches from any program with <p>Use this module to perform Recoll searches from any program with

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: dirif.cpp,v 1.8 2008-12-03 10:02:20 dockes Exp $ (C) 2008 J.F.Dockes"; static char rcsid[] = "@(#$Id: dirif.cpp,v 1.9 2008-12-03 17:04:20 dockes Exp $ (C) 2008 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -53,14 +53,14 @@ static const QString resultBaseName("recollResult");
// is the search string). If it is, extract return the result document // is the search string). If it is, extract return the result document
// number. Possibly restart the search if the search string does not // number. Possibly restart the search if the search string does not
// match the current one // match the current one
bool RecollProtocol::isRecollResult(const KUrl &url, int *num) bool RecollProtocol::isRecollResult(const KUrl &url, int *num, QString *q)
{ {
*num = -1; *num = -1;
kDebug() << "url" << url << "m_srchStr" << m_srchStr; kDebug() << "url" << url;
// Basic checks // Basic checks
if (!url.host().isEmpty() || url.path().isEmpty() || if (!url.host().isEmpty() || url.path().isEmpty() ||
url.protocol().compare("recoll")) (url.protocol().compare("recoll") && url.protocol().compare("recollf")))
return false; return false;
QString path = url.path(); QString path = url.path();
if (!path.startsWith("/")) if (!path.startsWith("/"))
@ -87,13 +87,7 @@ bool RecollProtocol::isRecollResult(const KUrl &url, int *num)
// We do have something that ressembles a recoll result locator. Check if // We do have something that ressembles a recoll result locator. Check if
// this matches the current search, else have to run the requested one // this matches the current search, else have to run the requested one
QString searchstring = path.mid(1, slashpos-2); *q = path.mid(1, slashpos-2);
kDebug() << "Comparing search strings" << m_srchStr << "and" << searchstring;
if (searchstring.compare(m_srchStr)) {
if (!doSearch(searchstring))
return false;
}
return true; return true;
} }
@ -106,7 +100,7 @@ static const UDSEntry resultToUDSEntry(const Rcl::Doc& doc, int num)
kDebug() << doc.url.c_str(); kDebug() << doc.url.c_str();
entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, url.fileName()); entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, url.fileName());
char cnum[30];sprintf(cnum, "%d", num); char cnum[30];sprintf(cnum, "%04d", num);
entry.insert(KIO::UDSEntry::UDS_NAME, resultBaseName + cnum); entry.insert(KIO::UDSEntry::UDS_NAME, resultBaseName + cnum);
if (!doc.mimetype.compare("application/x-fsdirectory")) { if (!doc.mimetype.compare("application/x-fsdirectory")) {
@ -150,7 +144,7 @@ static void createGoHomeEntry(KIO::UDSEntry& entry)
entry.insert(KIO::UDSEntry::UDS_NAME, "search"); entry.insert(KIO::UDSEntry::UDS_NAME, "search");
entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Recoll search (click me)"); entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, "Recoll search (click me)");
entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
entry.insert(KIO::UDSEntry::UDS_TARGET_URL, "recoll:///welcome"); entry.insert(KIO::UDSEntry::UDS_TARGET_URL, "recoll:///search.html");
entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500); entry.insert(KIO::UDSEntry::UDS_ACCESS, 0500);
entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "text/html"); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "text/html");
entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "recoll"); entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "recoll");
@ -175,28 +169,40 @@ static void createGoHelpEntry(KIO::UDSEntry& entry)
void RecollProtocol::stat(const KUrl & url) void RecollProtocol::stat(const KUrl & url)
{ {
kDebug() << url << endl ; kDebug() << url << endl ;
int num = -1;
QString path = url.path(); UrlIngester ingest(this, url);
QString host = url.host();
KIO::UDSEntry entry; KIO::UDSEntry entry;
if (!host.isEmpty()) { UrlIngester::RootEntryType rettp;
// Do nothing probably coming from the html form, if we return a QueryDesc qd;
// directory here, we crash konqueror int num;
kDebug() << "HOST NOT EMPTY:" << host; if (ingest.isRootEntry(&rettp)) {
} else if (!path.compare("/")) { switch(rettp) {
createRootEntry(entry); case UrlIngester::UIRET_ROOT:
} else if (!path.compare("/help")) { createRootEntry(entry);
createGoHelpEntry(entry); break;
} else if (!path.compare("/search")) { case UrlIngester::UIRET_HELP:
createGoHomeEntry(entry); createGoHelpEntry(entry);
// } else if (!path.compare("/welcome")) { break;
} else if (isRecollResult(url, &num)) { case UrlIngester::UIRET_SEARCH:
// Let's stat said result. createGoHomeEntry(entry);
Rcl::Doc doc; break;
if (num >= 0 && !m_source.isNull() && m_source->getDoc(num, doc)) { default:
entry = resultToUDSEntry(doc, num); error(ERR_DOES_NOT_EXIST, "");
break;
} }
} else { } else if (ingest.isResult(&qd, &num)) {
if (syncSearch(qd)) {
Rcl::Doc doc;
if (num >= 0 && !m_source.isNull() && m_source->getDoc(num, doc)) {
entry = resultToUDSEntry(doc, num);
} else {
error(ERR_DOES_NOT_EXIST, "");
}
} else {
// hopefully syncSearch() set the error?
}
} else if (ingest.isQuery(&qd)) {
// ie "recoll:/some string" or "recoll:/some string/" // ie "recoll:/some string" or "recoll:/some string/"
// //
// We have a problem here. We'd like to let the user enter // We have a problem here. We'd like to let the user enter
@ -207,13 +213,11 @@ void RecollProtocol::stat(const KUrl & url)
// //
// Another approach would be to use different protocol names // Another approach would be to use different protocol names
// to avoid any possibility of mixups // to avoid any possibility of mixups
if (path.endsWith("/")) { if (m_alwaysdir || ingest.alwaysDir() || ingest.endSlashQuery()) {
QString q, opt; entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
URLToQuery(url, q, opt); entry.insert(KIO::UDSEntry::UDS_ACCESS, 0700);
entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory");
entry.insert( KIO::UDSEntry::UDS_ACCESS, 0700); entry.insert(KIO::UDSEntry::UDS_NAME, qd.query);
entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, "inode/directory");
entry.insert(KIO::UDSEntry::UDS_NAME, q);
} }
} }
@ -226,50 +230,48 @@ void RecollProtocol::listDir(const KUrl& url)
{ {
kDebug() << url << endl; kDebug() << url << endl;
// It seems that when the request is from konqueror UrlIngester ingest(this, url);
// autocompletion it comes with a / at the end, which offers UrlIngester::RootEntryType rettp;
// an opportunity to not perform it. QueryDesc qd;
if (url.path() != "/" && url.path().endsWith("/")) {
kDebug() << "EndsWith /" << endl;
error(ERR_SLAVE_DEFINED, "Autocompletion search aborted");
return;
}
if (!m_initok || !maybeOpenDb(m_reason)) { if (ingest.isRootEntry(&rettp)) {
string reason = "RecollProtocol::listDir: Init error:" + m_reason; switch(rettp) {
error(KIO::ERR_SLAVE_DEFINED, reason.c_str()); case UrlIngester::UIRET_ROOT:
return; {
} kDebug() << "list /" << endl;
UDSEntryList entries;
if (url.path().isEmpty() || url.path() == "/") { KIO::UDSEntry entry;
kDebug() << "list /" << endl; createRootEntry(entry);
entries.append(entry);
UDSEntryList entries; createGoHomeEntry(entry);
KIO::UDSEntry entry; entries.append(entry);
createGoHelpEntry(entry);
// entry for '/' entries.append(entry);
createRootEntry(entry); listEntries(entries);
entries.append(entry); finished();
}
createGoHomeEntry(entry);
entries.append(entry);
createGoHelpEntry(entry);
entries.append(entry);
listEntries(entries);
finished();
return;
}
QString query, opt;
URLToQuery(url, query, opt);
kDebug() << "Query: " << query;
if (!query.isEmpty()) {
if (!doSearch(query, opt))
return; return;
default:
error(ERR_CANNOT_ENTER_DIRECTORY, "");
finished();
return;
}
} else if (ingest.isQuery(&qd)) {
// At this point, it seems that when the request is from
// konqueror autocompletion it comes with a / at the end,
// which offers an opportunity to not perform it.
if (ingest.endSlashQuery()) {
kDebug() << "Ends With /" << endl;
error(ERR_SLAVE_DEFINED, "Autocompletion search aborted");
return;
}
if (!syncSearch(qd)) {
return;
}
// Fallthrough to actually listing the directory
} else { } else {
finished(); kDebug() << "Cant grok input url";
error(ERR_CANNOT_ENTER_DIRECTORY, "");
return; return;
} }
@ -290,7 +292,9 @@ void RecollProtocol::listDir(const KUrl& url)
listEntries(entries); listEntries(entries);
finished(); finished();
} }
#else // <--- KDE 4.1+ #else // <--- KDE 4.1+
#include <kurl.h> #include <kurl.h>
#include "kio_recoll.h" #include "kio_recoll.h"
bool RecollProtocol::isRecollResult(const KUrl &, int *) bool RecollProtocol::isRecollResult(const KUrl &, int *)

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.5 2008-12-02 13:14:01 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: htmlif.cpp,v 1.6 2008-12-03 17:04:20 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -53,10 +53,24 @@ bool RecollKioPager::append(const string& data)
return true; return true;
} }
string RecollProtocol::makeQueryUrl(int page, bool isdet)
{
char buf[100];
sprintf(buf, "recoll://search/query?q=%s&qtp=%s&p=%d",
(const char*)m_query.query.toUtf8(),
(const char*)m_query.opt.toUtf8(),
page);
string ret(buf);
if (isdet)
ret += "&det=1";
return ret;
}
string RecollKioPager::detailsLink() string RecollKioPager::detailsLink()
{ {
string chunk = "<a href=\"recoll://command/QueryDetails\">"; string chunk = string("<a href=\"") +
chunk += tr("(show query)") + "</a>"; m_parent->makeQueryUrl(m_parent->m_pager.pageNumber(), true) + "\">"
+ "(show query)" + "</a>";
return chunk; return chunk;
} }
@ -73,16 +87,7 @@ const string& RecollKioPager::parFormat()
string RecollKioPager::pageTop() string RecollKioPager::pageTop()
{ {
return "<p align=\"center\"><a href=\"recoll:///welcome\">New Search</a></p>"; return "<p align=\"center\"><a href=\"recoll:///search.html\">New Search</a></p>";
}
string RecollProtocol::makeQueryUrl(int page)
{
char buf[100];
sprintf(buf, "recoll://search/query?q=%s&qtp=%s&p=%d",
(const char*)m_srchStr.toUtf8(), (const char*)m_opt.toUtf8(),
page);
return string(buf);
} }
string RecollKioPager::nextUrl() string RecollKioPager::nextUrl()
@ -107,7 +112,7 @@ string RecollKioPager::prevUrl()
static string welcomedata; static string welcomedata;
void RecollProtocol::welcomePage() void RecollProtocol::searchPage()
{ {
kDebug(); kDebug();
mimeType("text/html"); mimeType("text/html");
@ -171,32 +176,35 @@ void RecollProtocol::queryDetails()
data(array); data(array);
} }
void RecollProtocol::htmlDoSearch(const QString& q, const QString &opt, int page) void RecollProtocol::htmlDoSearch(const QueryDesc& qd)
{ {
kDebug() << "q" << q << "opt" << opt << "page" << page; kDebug() << "q" << qd.query << "opt" << qd.opt << "page" << qd.page <<
if (m_source.isNull()) "isdet" << qd.isDetReq;
kDebug() << "Null source";
// Check if same search or need to start new mimeType("text/html");
if (q.compare(m_srchStr) || opt.compare(m_opt)) {
if (!doSearch(q, opt)) bool samesearch;
return; if (!syncSearch(qd, &samesearch))
return;
if (!samesearch) {
m_pager.setDocSource(m_source); m_pager.setDocSource(m_source);
// goto page 0
m_pager.resultPageNext(); m_pager.resultPageNext();
} }
if (qd.isDetReq) {
queryDetails();
return;
}
// Check / adjust page number // Check / adjust page number
if (page > m_pager.pageNumber()) { if (qd.page > m_pager.pageNumber()) {
int npages = page - m_pager.pageNumber(); int npages = qd.page - m_pager.pageNumber();
for (int i = 0; i < npages; i++) for (int i = 0; i < npages; i++)
m_pager.resultPageNext(); m_pager.resultPageNext();
} else if (page < m_pager.pageNumber()) { } else if (qd.page < m_pager.pageNumber()) {
int npages = m_pager.pageNumber() - page; int npages = m_pager.pageNumber() - qd.page;
for (int i = 0; i < npages; i++) for (int i = 0; i < npages; i++)
m_pager.resultPageBack(); m_pager.resultPageBack();
} }
// Display // Display
mimeType("text/html");
m_pager.displayPage(); m_pager.displayPage();
kDebug() << "done";
} }

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.20 2008-12-01 18:42:52 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: kio_recoll.cpp,v 1.21 2008-12-03 17:04:20 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -58,7 +58,8 @@ RclConfig *RclConfig::getMainConfig()
} }
RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app) RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app)
: SlaveBase("recoll", pool, app), m_initok(false), m_rcldb(0), m_opt("l") : SlaveBase("recoll", pool, app), m_initok(false), m_rcldb(0),
m_alwaysdir(false)
{ {
kDebug() << endl; kDebug() << endl;
if (o_rclconfig == 0) { if (o_rclconfig == 0) {
@ -81,6 +82,17 @@ RecollProtocol::RecollProtocol(const QByteArray &pool, const QByteArray &app)
m_reason = "Could not build database object. (out of memory ?)"; m_reason = "Could not build database object. (out of memory ?)";
return; 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);
}
m_pager.setParent(this); m_pager.setParent(this);
m_initok = true; m_initok = true;
return; return;
@ -113,46 +125,99 @@ bool RecollProtocol::maybeOpenDb(string &reason)
void RecollProtocol::mimetype(const KUrl &url) void RecollProtocol::mimetype(const KUrl &url)
{ {
kDebug() << url << endl; kDebug() << url << endl;
///////////////////////////////REMOVEME REMOVEME REMOVEME when sure !/////
abort();
////////////////////////////////////////////////////////////////////////
mimeType("text/html"); mimeType("text/html");
finished(); finished();
} }
bool RecollProtocol::URLToQuery(const KUrl &url, QString& q, QString& opt, UrlIngester::UrlIngester(RecollProtocol *p, const KUrl& url)
int *page) : m_parent(p), m_slashend(false), m_alwaysdir(false),
m_retType(UIRET_NONE), m_resnum(0), m_type(UIMT_NONE)
{ {
// "recoll:/some query/" or "recoll:/some query" kDebug() << "Url" << url;
m_alwaysdir = !url.protocol().compare("recollf");
QString path = url.path();
if (url.host().isEmpty()) { if (url.host().isEmpty()) {
q = url.path(); if (path.isEmpty() || !path.compare("/")) {
opt = "l"; m_type = UIMT_ROOTENTRY;
if (page) m_retType = UIRET_ROOT;
*page = 0; 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;
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 { } else {
if (url.host().compare("search")) {
return;
}
m_type = UIMT_QUERY;
// Decode the forms' arguments // Decode the forms' arguments
q = url.queryItem("q"); m_query.query = url.queryItem("q");
opt = url.queryItem("qtp");
if (opt.isEmpty()) { m_query.opt = url.queryItem("qtp");
opt = "l"; if (m_query.opt.isEmpty()) {
m_query.opt = "l";
} }
if (page) { QString p = url.queryItem("p");
QString p = url.queryItem("p"); if (p.isEmpty()) {
if (p.isEmpty()) { m_query.page = 0;
*page = 0; } else {
} else { sscanf(p.toAscii(), "%d", &m_query.page);
sscanf(p.toAscii(), "%d", page);
}
} }
p = url.queryItem("det");
m_query.isDetReq = !p.isEmpty();
} }
if (q.startsWith("/")) if (m_query.query.startsWith("/"))
q.remove(0,1); m_query.query.remove(0,1);
if (q.endsWith("/")) if (m_query.query.endsWith("/")) {
q.chop(1); m_slashend = true;
return true; m_query.query.chop(1);
} else {
m_slashend = false;
}
return;
}
bool RecollProtocol::syncSearch(const QueryDesc &qd, bool *same)
{
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)) {
if (same)
*same = true;
return true;
}
if (same)
*same = false;
// doSearch() calls error() if appropriate.
return doSearch(qd);
} }
// This is used by the html interface, but also by the directory one // This is used by the html interface, but also by the directory one
// when doing file copies for exemple. This is the central dispatcher // when doing file copies for exemple. This is the central dispatcher
// for requests, it has to know a little about both models. // for requests, it has to know a little about both models.
void RecollProtocol::get(const KUrl & url) void RecollProtocol::get(const KUrl& url)
{ {
kDebug() << url << endl; kDebug() << url << endl;
@ -162,56 +227,65 @@ void RecollProtocol::get(const KUrl & url)
return; return;
} }
QString host = url.host(); UrlIngester ingest(this, url);
QString path = url.path(); UrlIngester::RootEntryType rettp;
QueryDesc qd;
int docnum = -1; int resnum;
if (host.isEmpty() && if (ingest.isRootEntry(&rettp)) {
(path.isEmpty() || !path.compare("/")||!path.compare("/welcome"))) { switch(rettp) {
// recoll:/ : print the html form page case UrlIngester::UIRET_HELP:
welcomePage(); {
goto out; QString location =
} else if (host.isEmpty() && isRecollResult(url, &docnum)) { KStandardDirs::locate("data", "kio_recoll/help.html");
redirection(location);
}
goto out;
default:
searchPage();
goto out;
}
} else if (ingest.isResult(&qd, &resnum)) {
// Matched an url generated by konqueror out of a directory listing: // Matched an url generated by konqueror out of a directory listing:
// ie: recoll:/some search string/recollResultxx // ie: recoll:/some search string/recollResultxx
// Redirect to the result document URL // Redirect to the result document URL
if (!syncSearch(qd)) {
return;
}
Rcl::Doc doc; Rcl::Doc doc;
if (docnum >= 0 && !m_source.isNull() && m_source->getDoc(docnum, doc)) { if (resnum >= 0 && !m_source.isNull() && m_source->getDoc(resnum, doc)) {
mimeType(doc.mimetype.c_str()); mimeType(doc.mimetype.c_str());
redirection(KUrl::fromLocalFile((const char *)(doc.url.c_str()+7))); redirection(KUrl::fromLocalFile((const char *)(doc.url.c_str()+7)));
goto out; goto out;
} }
} else if (host.isEmpty() || } else if (ingest.isQuery(&qd)) {
(!host.compare("search") && !path.compare("/query"))) { #if 0
// Either "recoll://search/query?query args" // Do we need this ?
// Or "recoll:[/]some search string" if (host.isEmpty()) {
// HTML style query, maybe initial or request for other page char cpage[20];sprintf(cpage, "%d", page);
QString query, opt; QString nurl = QString::fromAscii("recoll://search/query?q=") +
int page; query + "&qtp=" + opt + "&p=" + cpage;
URLToQuery(url, query, opt, &page); redirection(KUrl(nurl));
if (!query.isEmpty()) {
htmlDoSearch(query, opt, page);
goto out;
}
} else if (!host.compare("command")) {
if (path.indexOf("/QueryDetails") == 0) {
queryDetails();
goto out; goto out;
} }
#endif
// htmlDoSearch does the search syncing (needs to know about changes).
htmlDoSearch(qd);
goto out;
} }
error(KIO::ERR_SLAVE_DEFINED, "Unrecognized URL");
error(KIO::ERR_SLAVE_DEFINED, "Unrecognized URL or internal error");
out: out:
finished(); finished();
} }
// Execute Recoll search, and set the docsource etc. // Execute Recoll search, and set the docsource
bool RecollProtocol::doSearch(const QString& q, const QString &qopt) bool RecollProtocol::doSearch(const QueryDesc& qd)
{ {
kDebug() << "query" << q << "opt" << qopt; kDebug() << "query" << qd.query << "opt" << qd.opt;
m_srchStr = q; m_query = qd;
m_opt = qopt;
char opt = qopt.isEmpty() ? 'l' : qopt.toUtf8().at(0); char opt = qd.opt.isEmpty() ? 'l' : qd.opt.toUtf8().at(0);
string qs = (const char *)q.toUtf8(); string qs = (const char *)qd.query.toUtf8();
Rcl::SearchData *sd = 0; Rcl::SearchData *sd = 0;
if (opt != 'l') { if (opt != 'l') {
Rcl::SearchDataClause *clp = 0; Rcl::SearchDataClause *clp = 0;
@ -238,7 +312,6 @@ bool RecollProtocol::doSearch(const QString& q, const QString &qopt)
if (!sd) { if (!sd) {
m_reason = "Internal Error: cant build search"; m_reason = "Internal Error: cant build search";
error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
finished();
return false; return false;
} }
@ -248,7 +321,6 @@ bool RecollProtocol::doSearch(const QString& q, const QString &qopt)
if (!query->setQuery(sdata)) { if (!query->setQuery(sdata)) {
m_reason = "Query execute failed. Invalid query or syntax error?"; m_reason = "Query execute failed. Invalid query or syntax error?";
error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str()); error(KIO::ERR_SLAVE_DEFINED, m_reason.c_str());
finished();
return false; return false;
} }
@ -256,7 +328,6 @@ bool RecollProtocol::doSearch(const QString& q, const QString &qopt)
new DocSequenceDb(RefCntr<Rcl::Query>(query), "Query results", sdata); new DocSequenceDb(RefCntr<Rcl::Query>(query), "Query results", sdata);
if (src == 0) { if (src == 0) {
error(KIO::ERR_SLAVE_DEFINED, "Can't build result sequence"); error(KIO::ERR_SLAVE_DEFINED, "Can't build result sequence");
finished();
return false; return false;
} }
m_source = RefCntr<DocSequence>(src); m_source = RefCntr<DocSequence>(src);

View File

@ -1,5 +1,5 @@
#ifndef _RECOLL_H #ifndef _RECOLL_H
/* @(#$Id: kio_recoll.h,v 1.11 2008-12-01 18:42:52 dockes Exp $ (C) 2005 J.F.Dockes */ /* @(#$Id: kio_recoll.h,v 1.12 2008-12-03 17:04:20 dockes Exp $ (C) 2005 J.F.Dockes */
#define _RECOLL_H #define _RECOLL_H
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -54,6 +54,54 @@ private:
RecollProtocol *m_parent; 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 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};
MyType m_type;
};
/** /**
* A KIO slave to execute and display Recoll searches. * A KIO slave to execute and display Recoll searches.
* *
@ -95,23 +143,25 @@ class RecollProtocol : public KIO::SlaveBase {
static RclConfig *o_rclconfig; static RclConfig *o_rclconfig;
friend class RecollKioPager; friend class RecollKioPager;
friend class UrlIngester;
private: private:
bool maybeOpenDb(string& reason); bool maybeOpenDb(string& reason);
bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0); bool URLToQuery(const KUrl &url, QString& q, QString& opt, int *page=0);
bool doSearch(const QString& q, const QString& opt = "l"); bool doSearch(const QueryDesc& qd);
void welcomePage(); void searchPage();
void queryDetails(); void queryDetails();
string makeQueryUrl(int page); string makeQueryUrl(int page, bool isdet = false);
void htmlDoSearch(const QString& q, const QString& opt, int page); bool syncSearch(const QueryDesc& qd, bool *same = 0);
void htmlDoSearch(const QueryDesc& qd);
bool isRecollResult(const KUrl &url, int *num); bool isRecollResult(const KUrl &url, int *num, QString* q);
bool m_initok; bool m_initok;
Rcl::Db *m_rcldb; Rcl::Db *m_rcldb;
string m_reason; string m_reason;
bool m_alwaysdir;
// Search state: because of how the KIO slaves are used / reused, // 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 // 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 // search, and we need to check and restart one if the data
@ -121,8 +171,8 @@ class RecollProtocol : public KIO::SlaveBase {
// cache of recent searches kept open. // cache of recent searches kept open.
RecollKioPager m_pager; RecollKioPager m_pager;
RefCntr<DocSequence> m_source; RefCntr<DocSequence> m_source;
QString m_srchStr; // Note: page here is not used, current page always comes from m_pager.
QString m_opt; QueryDesc m_query;
}; };
extern "C" {int kdemain(int, char**);} extern "C" {int kdemain(int, char**);}

Binary file not shown.