You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kerry/kerry/src/beaglesearch.cpp

461 lines
19 KiB

/***************************************************************************
* Copyright (C) 2005 by Debajyoti Bera <dbera.web@gmail.com> *
* Copyright (C) 2005 Novell, Inc. *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
***************************************************************************/
#include "beaglesearch.h"
#include <tdemessagebox.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tqapplication.h>
#include <kurl.h>
struct PropertyInfo
{
int tilegroup;
const char* identifier;
const char* label;
};
static const PropertyInfo propertiesInfo[] =
{
/* { BeagleSearch::Application, "fixme:Name", I18N_NOOP("Name: %1")"<br>" },
{ BeagleSearch::Application, "fixme:Comment", I18N_NOOP("Comment: %1")"<br>" },
{ BeagleSearch::Application, "fixme:Categories", I18N_NOOP("Categories: %1")"<br>" },*/
{ BeagleSearch::Application, "fixme:Name", 0 },
{ BeagleSearch::Audio, "fixme:title", 0 },
{ BeagleSearch::Audio, "fixme:album", I18N_NOOP("Album: %1")"<br>" },
{ BeagleSearch::Audio, "fixme:ExactFilename", I18N_NOOP("Title: %1")"<br>" },
{ BeagleSearch::Audio, "fixme:artist", I18N_NOOP("Artist: %1")"<br>" },
{ BeagleSearch::Image, "fixme:width", I18N_NOOP("Width: %1")"&nbsp;&nbsp;&nbsp;" },
{ BeagleSearch::Image, "fixme:height", I18N_NOOP("Height: %1")"&nbsp;&nbsp;&nbsp;" },
{ BeagleSearch::Image, "fixme:colortype", I18N_NOOP("Color type: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:Name", 0 },
{ BeagleSearch::Contact, "fixme:Email1", 0 },
{ BeagleSearch::Contact, "vCard:FN", 0 },
{ BeagleSearch::Contact, "vCard:EMAIL", 0 },
{ BeagleSearch::Contact, "fixme:BusinessPhone", I18N_NOOP("Business phone: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:HomePhone", I18N_NOOP("Home phone: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:MobilePhone", I18N_NOOP("Mobile phone: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImAim", I18N_NOOP("AIM: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImYahoo", I18N_NOOP("Yahoo: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImMsn", I18N_NOOP("MSN: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImJabber", I18N_NOOP("Jabber: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImIcq", I18N_NOOP("ICQ: %1")"<br>" },
{ BeagleSearch::Contact, "fixme:ImGroupWise", I18N_NOOP("GroupWise: %1")"<br>" },
// { BeagleSearch::Conversations, "fixme:speakingto", I18N_NOOP("From: %1")"<br>" },
{ BeagleSearch::Conversations, "fixme:speakingto", 0 },
{ BeagleSearch::Conversations, "fixme:protocol", I18N_NOOP("Protocol: %1")"<br>" },
{ BeagleSearch::Conversations, "fixme:starttime", I18N_NOOP("Start time: %1")"<br>" },
{ BeagleSearch::Conversations, "fixme:endtime", I18N_NOOP("End time: %1")"<br>" },
{ BeagleSearch::Conversations, "dc:title", 0 },
{ BeagleSearch::Conversations, "fixme:from", 0 },
{ BeagleSearch::Conversations, "fixme:date", 0 },
{ BeagleSearch::Conversations, "fixme:folder", I18N_NOOP("Folder: %1")"&nbsp;" },
{ BeagleSearch::Conversations, "fixme:account", I18N_NOOP("(%1)")"<br>" },
/* { BeagleSearch::Conversations, "fixme:isAnswered", I18N_NOOP("Was answered.")"&nbsp;&nbsp;&nbsp;" },
{ BeagleSearch::Conversations, "fixme:isSeen", I18N_NOOP("Was seen.")"&nbsp;&nbsp;&nbsp;" },
{ BeagleSearch::Conversations, "fixme:hasAttachments", I18N_NOOP("Has Attachments.")"&nbsp;&nbsp;&nbsp;" },*/
// Presentation
{ BeagleSearch::Documents, "dc:title", I18N_NOOP("Title: %1")"<br>" },
{ BeagleSearch::Documents, "dc:author", I18N_NOOP("Author: %1")"<br>" },
{ BeagleSearch::Documents, "fixme:slide-count", I18N_NOOP("Slides: %1")"&nbsp;&nbsp;&nbsp;" },
// Text Document
{ BeagleSearch::Documents, "fixme:page-count", I18N_NOOP("Pages: %1")"&nbsp;&nbsp;&nbsp;" },
{ BeagleSearch::Documents, "fixme:word-count", I18N_NOOP("Words: %1") },
{ BeagleSearch::Feed, "dc:title", 0 },
{ BeagleSearch::Feed, "dc:identifier", 0 },
/* { BeagleSearch::Feed, "dc:date", I18N_NOOP("Date: %1")"<br>" },
{ BeagleSearch::Feed, "dc:source", I18N_NOOP("Source: %1")"<br>" },*/
{ BeagleSearch::Website, "dc:title", 0 },
{ BeagleSearch::Website, "Title", 0 },
{ BeagleSearch::Note, "dc:title", 0 },
// Packages (ebuild, RPM, etc.)
{ BeagleSearch::Packages, "dc:title", I18N_NOOP("Title: %1")"<br>" },
{ BeagleSearch::Packages, "dc:subject", 0 },
{ BeagleSearch::Packages, "fixme:category", I18N_NOOP("Category: %1")"<br>" },
{ BeagleSearch::Packages, "fixme:version", I18N_NOOP("Version: %1")"<br>" },
{ BeagleSearch::Packages, "dc:source", 0 },
{ BeagleSearch::Packages, "fixme:packager_name", I18N_NOOP("Packager name: %1")"<br>" },
{ BeagleSearch::Packages, "fixme:packager_email", I18N_NOOP("Packager email: %1")"<br>" },
{ BeagleSearch::Packages, "fixme:size", 0 },
{ BeagleSearch::Packages, "fixme:install_time", 0 },
{ BeagleSearch::Packages, "fixme:contents_byte_count", 0 },
{ BeagleSearch::Unknown, "dc:author", I18N_NOOP("Author: %1")"<br>" },
{ BeagleSearch::Unknown, "dc:title", I18N_NOOP("Title: %1")"<br>" },
// Calendar
{ BeagleSearch::Unknown, "fixme:summary", 0 },
{ BeagleSearch::Unknown, "fixme:starttime", 0 },
{ BeagleSearch::Unknown, "fixme:endtime", 0 },
{ BeagleSearch::Unknown, "fixme:location", I18N_NOOP("Location: %1")"<br>" },
{ BeagleSearch::Unknown, "fixme:page-count", I18N_NOOP("Pages: %1")"<br>" },
// { BeagleSearch::, "", I18N_NOOP(": %1")+"<br>" },
// { "", "", I18N_NOOP("") },
{ 0, 0, 0}
};
struct HitFlavorInfo
{
int tilegroup;
const char* uri;
const char* type;
const char* mimetype;
};
static const HitFlavorInfo hitflavorinfos[] =
{
{ BeagleSearch::Application, 0, 0, "application/x-desktop" },
{ BeagleSearch::Audio, 0, 0, "audio/" },
{ BeagleSearch::Audio, 0, 0, "application/ogg" },
{ BeagleSearch::Contact, 0, "Contact", 0 },
{ BeagleSearch::Conversations, 0, "IMLog", 0 },
{ BeagleSearch::Conversations, 0, "MailMessage", 0 },
{ BeagleSearch::Conversations,"email://", 0, 0 },
{ BeagleSearch::Feed, 0, "FeedItem", 0 },
{ BeagleSearch::Folder, 0, 0, "inode/directory" },
{ BeagleSearch::Folder, 0, 0, "x-directory/normal" },
{ BeagleSearch::Image, "file://", 0, "image/" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.impress.template" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.impress" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.ms-powerpoint" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.presentation" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.presentation" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.calc" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.calc.template" },
{ BeagleSearch::Documents, 0, 0, "application/excel" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.ms-excel" },
{ BeagleSearch::Documents, 0, 0, "application/x-excel" },
{ BeagleSearch::Documents, 0, 0, "application/x-msexcel" },
{ BeagleSearch::Documents, 0, 0, "application/x-gnumeric" },
{ BeagleSearch::Documents, 0, 0, "text/spreadsheet" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.spreadsheet" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.spreadsheet.template" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.writer" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.sun.xml.writer.template" },
{ BeagleSearch::Documents, 0, 0, "application/msword" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.ms-word" },
{ BeagleSearch::Documents, 0, 0, "application/x-msword" },
{ BeagleSearch::Documents, 0, 0, "application/pdf" },
{ BeagleSearch::Documents, 0, 0, "application/x-abiword" },
{ BeagleSearch::Documents, 0, 0, "application/rtf" },
{ BeagleSearch::Documents, 0, 0, "application/x-chm" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.text" },
{ BeagleSearch::Documents, 0, 0, "application/vnd.oasis.opendocument.text.template" },
{ BeagleSearch::Note, "note://", 0, 0 },
{ BeagleSearch::Note, "knotes://", 0, 0 },
{ BeagleSearch::Video, 0, 0, "video/" },
{ BeagleSearch::Website, 0, "Google", 0 },
{ BeagleSearch::Website, 0, "WebHistory", 0 },
{ BeagleSearch::Website, 0, 0, "beagle/x-konq-cache" },
{ BeagleSearch::Packages, "*.ebuild", 0, 0 },
{ BeagleSearch::Packages, "*.rpm", 0, "application/x-rpm" },
{ BeagleSearch::Packages, "*.deb", 0, "application/x-deb" },
{ BeagleSearch::Unknown, "file://", "File", 0 }, // mimetype wildcard must be last
{ 0, 0, 0, 0}
};
BeagleSearch::BeagleSearch(int id, TQObject *parent, TQString term)
: id (id), kill_me (false), parent (parent)
{
query = beagle_query_new ();
beagle_query_set_max_hits(query, 100);
beagle_query_add_text (query, term.ascii());
client = beagle_client_new (NULL);
client_mutex = new TQMutex ();
main_loop = g_main_loop_new (NULL, FALSE);
}
void BeagleSearch::run()
{
g_signal_connect (query, "hits-added",
G_CALLBACK (hits_added_cb),
this);
g_signal_connect (query, "hits-subtracted",
G_CALLBACK (hits_subtracted_cb),
this);
g_signal_connect (query, "finished",
G_CALLBACK (finished_cb),
this);
beagle_client_send_request_async (client,
BEAGLE_REQUEST (query),
NULL);
g_main_loop_run (main_loop);
kdDebug () << "Finished query ..." << endl;
bool run = true;
while (run) {
g_main_context_iteration(0, false);
sleep(1);
client_mutex->lock ();
run = !kill_me;
client_mutex->unlock ();
}
kdDebug() << "!!! run ending" << endl;
TQCustomEvent *ev;
ev = new TQCustomEvent (KILLME, this);
tqApp->postEvent(parent, ev);
}
void BeagleSearch::stopClient()
{
if (finished ())
return; // duh!
kdDebug () << "Query thread " << id << " not yet finished ..." << endl;
// get ready for suicide
client_mutex->lock ();
kill_me = true;
g_signal_handlers_disconnect_by_func (
query,
(void *)hits_added_cb,
this);
g_signal_handlers_disconnect_by_func (
query,
(void *)hits_subtracted_cb,
this);
g_signal_handlers_disconnect_by_func (
query,
(void *)finished_cb,
this);
g_main_loop_quit (main_loop);
client_mutex->unlock ();
}
BeagleSearch::~BeagleSearch()
{
if (! finished ()) {
kdDebug () << "Thread " << id << " still running. Waiting.........." << endl;
wait ();
}
g_object_unref (client);
g_main_loop_unref (main_loop);
g_object_unref (query);
kdDebug() << "Deleting client ..." << id << endl;
delete client_mutex;
}
TQString *BeagleSearch::get_uri_from_file_hit(BeagleHit *hit)
{
return new TQString (beagle_hit_get_uri (hit));
}
TQString *BeagleSearch::get_parent_uri_from_file_hit(BeagleHit *hit)
{
return new TQString (beagle_hit_get_parent_uri (hit));
}
TQString *BeagleSearch::get_source_from_file_hit(BeagleHit *hit)
{
return new TQString (beagle_hit_get_source (hit));
}
TQString *BeagleSearch::get_uri_from_feed_hit(BeagleHit *hit)
{
const char *result;
beagle_hit_get_one_property (hit, "fixme:itemuri", &result);
return new TQString (result);
}
void BeagleSearch::hits_added_cb (BeagleQuery *query, BeagleHitsAddedResponse *response, BeagleSearch *client)
{
GSList *hits, *l;
gint i;
gint nr_hits;
BeagleResultList* results;
results = new BeagleResultList;
// check if we are supposed to be killed
client->client_mutex->lock ();
if (client->kill_me) {
kdDebug () << "Suicide time before processing" << endl;
client->client_mutex->unlock ();
return;
}
client->client_mutex->unlock ();
// This is necessary only once, not for each item
BeagleSnippetRequest *snippetrequest = beagle_snippet_request_new();
beagle_snippet_request_set_query(snippetrequest, query);
hits = beagle_hits_added_response_get_hits (response);
nr_hits = g_slist_length (hits);
kdDebug() << "---------- hits added:" << nr_hits << endl;
for (l = hits, i = 1; l; l = l->next, ++i) {
//print_hit (BEAGLE_HIT (l->data));
beagle_result_struct *result = new beagle_result_struct;
BeagleHit *hit = BEAGLE_HIT (l->data);
result->hit_type = TQString(beagle_hit_get_type (BEAGLE_HIT (l->data)));
const char *_mime_type = beagle_hit_get_mime_type(BEAGLE_HIT (l->data));
const char *mime_type = (_mime_type == NULL ? "-" : _mime_type);
if (result->hit_type=="MailMessage" && TQString(mime_type)!="message/rfc822") {
delete result;
continue;
}
result->mime_type = new TQString(mime_type);
result->score = beagle_hit_get_score(BEAGLE_HIT (l->data));
result->uri = get_uri_from_file_hit (BEAGLE_HIT (l->data));
result->tilegroup = Unknown;
result->parent_uri = get_parent_uri_from_file_hit (BEAGLE_HIT (l->data));
result->source = get_source_from_file_hit (BEAGLE_HIT (l->data));
result->client_id = client->id;
#if 0
kdDebug() << "Properties of " << *(result->uri) << endl;
GSList *properties, *p;
gint i;
properties = beagle_hit_get_all_properties (hit);
for (p = properties, i = 1; p; p = p->next, ++i) {
BeagleProperty* property = (BeagleProperty*)p->data;
const char* key = beagle_property_get_key( property );
const char* value = beagle_property_get_value( property );
kdDebug() << " \"" << key << "\" = \"" << value << "\"" << endl;
}
kdDebug() << "parent_uri = " << *(result->parent_uri) << endl;
kdDebug() << "source = " << *(result->source) << endl;
kdDebug() << "tilegroup = " << result->tilegroup << endl;
#endif
for( uint i = 0; hitflavorinfos[i].tilegroup!=0; i++ ) {
if( (hitflavorinfos[i].uri == 0 || (*(result->uri)).startsWith(hitflavorinfos[i].uri) || (hitflavorinfos[i].uri[0]=='*' && (*(result->uri)).endsWith(hitflavorinfos[i].uri+1))) &&
(hitflavorinfos[i].type == 0 || hitflavorinfos[i].type==result->hit_type) &&
(hitflavorinfos[i].mimetype == 0 || (*(result->mime_type)).startsWith(hitflavorinfos[i].mimetype))) {
result->tilegroup = (TileGroup)hitflavorinfos[i].tilegroup;
break;
}
}
for( uint i = 0; propertiesInfo[i].identifier!=0; i++ ) {
if( propertiesInfo[i].tilegroup==0 || propertiesInfo[i].tilegroup==result->tilegroup ) {
GSList *properties = beagle_hit_get_properties( hit, propertiesInfo[i].identifier );
if (g_slist_length(properties)>0) {
const char *property = (char*)properties->data;
if (property) {
if (propertiesInfo[i].label) {
TQString propertystr = i18n(propertiesInfo[i].label).arg(property);
result->properties.append(propertystr);
}
else
result->properties.append(TQString(propertiesInfo[i].identifier)+'='+property);
}
}
}
}
beagle_snippet_request_set_hit(snippetrequest, hit);
GError *err = NULL;
BeagleResponse *response;
response = beagle_client_send_request (client->client, BEAGLE_REQUEST (snippetrequest), &err);
if (err) {
g_error_free (err);
result->snippet = 0;
}
else
result->snippet = new TQString( beagle_snippet_response_get_snippet( BEAGLE_SNIPPET_RESPONSE(response)) );
if (response)
g_object_unref(response);
BeagleTimestamp *timestamp = beagle_hit_get_timestamp (BEAGLE_HIT (l->data));
time_t index_time;
if (beagle_timestamp_to_unix_time (timestamp, &index_time))
result->last_index_time = index_time;
else
result->last_index_time = 0;
results->append (result);
}
g_object_unref(snippetrequest);
// check if we are supposed to be killed
client->client_mutex->lock ();
if (client->kill_me) {
kdDebug () << "Suicide time before sending ..." << endl;
client->client_mutex->unlock ();
delete results;
return;
}
client->client_mutex->unlock ();
TQCustomEvent *ev = new TQCustomEvent (RESULTFOUND, results);
tqApp->postEvent (client->parent, ev);
}
void BeagleSearch::hits_subtracted_cb (BeagleQuery */*query*/, BeagleHitsSubtractedResponse *response, BeagleSearch *client)
{
GSList *uris;
gint nr_hits;
BeagleVanishedURIList* vanished;
vanished = new BeagleVanishedURIList();
vanished->client_id = client->id;
// check if we are supposed to be killed
client->client_mutex->lock ();
if (client->kill_me) {
kdDebug () << "Suicide time before sending ..." << endl;
client->client_mutex->unlock ();
return;
}
client->client_mutex->unlock ();
uris = beagle_hits_subtracted_response_get_uris (response);
nr_hits = g_slist_length (uris);
kdDebug() << "---------- hits subtracted:" << nr_hits << endl;
while (uris != NULL) {
char *uri = (char*)uris->data;
g_print ("removed: %s\n", uri);
vanished->list.append(TQString(uri));
uris = uris->next;
}
TQCustomEvent *ev = new TQCustomEvent (RESULTGONE, vanished);
tqApp->postEvent (client->parent, ev);
}
void BeagleSearch::finished_cb (BeagleQuery */*query*/,
BeagleFinishedResponse */*response*/,
BeagleSearch *client)
{
kdDebug() << "---------- finished" << endl;
// check if we are supposed to be killed
client->client_mutex->lock ();
if (client->kill_me) {
kdDebug () << "Suicide time before sending ..." << endl;
client->client_mutex->unlock ();
return;
}
client->client_mutex->unlock ();
g_main_loop_quit (client->main_loop);
TQCustomEvent *ev = new TQCustomEvent (SEARCHOVER, client);
tqApp->postEvent (client->parent, ev);
}