cleaned up virtual tree and url handling. Drag to desktop now works with appropriate name. recollf protocol
This commit is contained in:
parent
8b164381d2
commit
0b649ae8d6
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 *)
|
||||||
|
|||||||
@ -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";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
} else if (!path.compare("/help.html")) {
|
||||||
// Decode the forms' arguments
|
m_type = UIMT_ROOTENTRY;
|
||||||
q = url.queryItem("q");
|
m_retType = UIRET_HELP;
|
||||||
opt = url.queryItem("qtp");
|
return;
|
||||||
if (opt.isEmpty()) {
|
} else if (!path.compare("/search.html")) {
|
||||||
opt = "l";
|
m_type = UIMT_ROOTENTRY;
|
||||||
}
|
m_retType = UIRET_SEARCH;
|
||||||
if (page) {
|
return;
|
||||||
QString p = url.queryItem("p");
|
} else if (m_parent->isRecollResult(url, &m_resnum, &m_query.query)) {
|
||||||
if (p.isEmpty()) {
|
m_type = UIMT_QUERYRESULT;
|
||||||
*page = 0;
|
m_query.opt = "l";
|
||||||
} else {
|
m_query.page = 0;
|
||||||
sscanf(p.toAscii(), "%d", page);
|
} 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 {
|
||||||
|
if (url.host().compare("search")) {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
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;
|
goto out;
|
||||||
}
|
}
|
||||||
} else if (!host.compare("command")) {
|
#endif
|
||||||
if (path.indexOf("/QueryDetails") == 0) {
|
// htmlDoSearch does the search syncing (needs to know about changes).
|
||||||
queryDetails();
|
htmlDoSearch(qd);
|
||||||
goto out;
|
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);
|
||||||
|
|||||||
@ -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.
Loading…
x
Reference in New Issue
Block a user