From kmail-devel Sun Jul 31 18:28:31 2005 From: =?iso-8859-1?q?Lu=EDs_Pedro_Coelho?= Date: Sun, 31 Jul 2005 18:28:31 +0000 To: kmail-devel Subject: [PATCH] full text indexing for kmail Message-Id: <200507311128.31699.luis () luispedro ! org> X-MARC-Message: https://marc.info/?l=kmail-devel&m=112283454428085 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_PhR7CLNuOQAlFIK" --Boundary-00=_PhR7CLNuOQAlFIK Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi, this is a heads-up. Either tomorrow evening or tue morning, I'll commit this to kmail unless I get a "No" from the maintainers. This depends on indexlib which has been on kdesupport for some time, so please compile that: it's a very little library. (I wanted to do this two weeks ago, but kdepim has been completely FUBAR for me. I had to fix a couple of portability issues to get it to compile) bye, -- luispedro http://blog.luispedro.org/ http://luispedro.org/ --Boundary-00=_PhR7CLNuOQAlFIK Content-Type: text/x-diff; charset="us-ascii"; name="kmail-patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kmail-patch" Index: kmfoldersearch.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmfoldersearch.h (revision 440058) +++ kmfoldersearch.h (working copy) @@ -71,9 +71,11 @@ bool running() const { return mRunning; } void stop(); int foundCount() const { return mFoundCount; } =2D int searchedCount() const { return mSearchedCount; } QString currentFolder() const { return mLastFolder; } =20 +public slots: + void indexFinished(); + signals: void found(Q_UINT32 serNum); void finished(bool success); @@ -87,7 +89,6 @@ friend class ::KMIndexSearchTarget; void setRunning(bool b) { mRunning =3D b; } void setFoundCount(int f) { mFoundCount =3D f; } =2D void setSearchedCount(int f) { mSearchedCount =3D f; } void setCurrentFolder(const QString &f) { mLastFolder =3D f; } =20 private: @@ -99,7 +100,7 @@ QValueList > mIncompleteFolders; SerNumList mSerNums; QString mLastFolder; =2D int mSearchedCount, mFoundCount; + int mFoundCount; QTimer *mProcessNextBatchTimer; }; =20 Index: kmmessage.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmmessage.h (revision 440058) +++ kmmessage.h (working copy) @@ -818,7 +818,6 @@ */ QCString mboxMessageSeparator(); =20 =2Dprivate: /** Returns message body with quoting header and indented by the given indentation string. This is suitable for including the message in another message of for replies, forwards. The header string is @@ -843,6 +842,7 @@ /** Return the textual content of the message as plain text, converting HTML to plain text if necessary. */ QString asPlainText( bool stripSignature, bool allowDecryption ) const; +private: =20 /** Initialization shared by the ctors. */ void init(); Index: Makefile.am =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- Makefile.am (revision 440058) +++ Makefile.am (working copy) @@ -3,6 +3,8 @@ =20 SUBDIRS =3D interfaces . about pics profiles avscripts tests =20 +LIB_INDEX =3D -lindex + INCLUDES =3D -I$(top_srcdir)/libkmime \ -I$(top_srcdir)/libkpgp \ -I$(top_srcdir)/libkdenetwork \ @@ -18,7 +20,7 @@ =20 lib_LTLIBRARIES =3D libkmailprivate.la libkmailprivate_la_LDFLAGS =3D $(all_libraries) -avoid-version -no-undefin= ed =2Dlibkmailprivate_la_LIBADD =3D $(LIB_KHTML) $(LIB_KSPELL) $(LIB_KABC) \ +libkmailprivate_la_LIBADD =3D $(LIB_KHTML) $(LIB_KSPELL) $(LIB_KABC) $(LI= B_INDEX) \ ../libkmime/libkmime.la ../libkpgp/libkpgp.la ../libkdepim/libkdep= im.la \ ../libkpimidentities/libkpimidentities.la ../mimelib/libmimelib.la= \ ../libksieve/libksieve.la ../libemailfunctions/libemailfunctions.l= a \ @@ -45,6 +47,7 @@ =20 libkmailprivate_la_SOURCES =3D kmmessage.cpp kmmainwin.cpp configuredialog= =2Ecpp \ configuredialog_p.cpp \ + index.cpp klistviewindexedsearchline.cpp \ simplestringlisteditor.cpp kmmsgindex.cpp \ identitydrag.cpp identitylistview.cpp identitydialog.cpp \ kmfolderdia.cpp kmfoldertree.cpp kmtransport.cpp \ Index: headeritem.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- headeritem.cpp (revision 440058) +++ headeritem.cpp (working copy) @@ -98,6 +98,7 @@ } =20 KMMsgBase *mMsgBase =3D headers->folder()->getMsgBase( mMsgId ); + mSerNum =3D mMsgBase->getMsgSerNum(); if (mMsgBase->isNew() || mMsgBase->isUnread() || mMsgBase->isImportant() || mMsgBase->isTodo() || mMsgBase->isWatc= hed() ) { setOpen(true); @@ -114,6 +115,12 @@ return mMsgId; } =20 +// Return the serial number +Q_UINT32 HeaderItem::msgSerNum() const +{ + return mSerNum; +} + // Update this item to summarise a new folder and message =20 //Opens all children in the thread Index: kmsearchpattern.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmsearchpattern.cpp (revision 440058) +++ kmsearchpattern.cpp (working copy) @@ -10,6 +10,9 @@ #include "kmmsgindex.h" #include "kmmsgdict.h" #include "filterlog.h" +#include "kmkernel.h" +#include "kmmsgdict.h" +#include "kmfolder.h" using KMail::FilterLog; =20 #include Index: searchwindow.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- searchwindow.cpp (revision 440058) +++ searchwindow.cpp (working copy) @@ -334,7 +334,6 @@ QString folderName; if (search) { numMatches =3D search->foundCount(); =2D count =3D search->searchedCount(); folderName =3D search->currentFolder(); } =20 Index: kmkernel.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmkernel.cpp (revision 440058) +++ kmkernel.cpp (working copy) @@ -11,7 +11,7 @@ =20 #include "globalsettings.h" #include "kmstartup.h" =2D#include "kmmsgindex.h" +#include "index.h" #include "kmmainwin.h" #include "composer.h" #include "kmmsgpart.h" @@ -1385,13 +1385,7 @@ readConfig(); mICalIface->readConfig(); // filterMgr->dump(); =2D#if 0 //disabled for now.. =2D the_msgIndex =3D new KMMsgIndex(this, "the_index"); //create the index= er =2D the_msgIndex->init(); =2D the_msgIndex->remove(); =2D delete the_msgIndex; =2D the_msgIndex =3D 0; =2D#endif + the_msgIndex =3D new KMMsgIndex(this); //create the indexer =20 #if 0 the_weaver =3D new KPIM::ThreadWeaver::Weaver( this ); Index: kmail.kcfg =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmail.kcfg (revision 440058) +++ kmail.kcfg (working copy) @@ -433,4 +433,11 @@ =20 =20 + + + true + + + + Index: kmmsgindex.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmmsgindex.h (revision 440058) +++ kmmsgindex.h (working copy) @@ -1,3 +1,5 @@ +#include "index.h" +#if 0 /* Message indexing * * Author: Sam Magnuson @@ -167,4 +169,5 @@ =20 =20 =20 +#endif =20 Index: kmmainwidget.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmmainwidget.cpp (revision 440058) +++ kmmainwidget.cpp (working copy) @@ -88,6 +88,7 @@ #include "filterlogdlg.h" using KMail::FilterLogDialog; #include +#include "klistviewindexedsearchline.h" using KMail::HeaderListQuickSearch; #include "kmheaders.h" #include "mailinglistpropertiesdialog.h" @@ -519,7 +520,7 @@ =20 =20 mHeaders =3D new KMHeaders(this, mSearchAndHeaders, "headers"); =2D mQuickSearchLine =3D new HeaderListQuickSearch( mSearchToolBar, mHeade= rs, + mQuickSearchLine =3D new KListViewIndexedSearchLine( mSearchToolBar, mHe= aders, actionCollection(), "h= eaders quick search line" ); label->setBuddy( mQuickSearchLine ); mSearchToolBar->setStretchableWidget( mQuickSearchLine ); Index: headeritem.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- headeritem.h (revision 440058) +++ headeritem.h (working copy) @@ -179,6 +179,9 @@ /** Return the msgId of the message associated with this item. */ int msgId() const; =20 + // Return the serial number of the message associated with this item; + Q_UINT32 msgSerNum() const; + /** Expands all children of the list view item. */ void setOpenRecursive( bool open ); =20 @@ -226,6 +229,7 @@ =20 private: int mMsgId; + Q_UINT32 mSerNum; QString mKey; bool mAboutToBeDeleted; SortCacheItem *mSortCacheItem; Index: kmfoldersearch.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmfoldersearch.cpp (revision 440058) +++ kmfoldersearch.cpp (working copy) @@ -25,7 +25,7 @@ #include "kmfoldermgr.h" #include "kmsearchpattern.h" #include "kmmsgdict.h" =2D#include "kmmsgindex.h" +#include "index.h" #include "jobscheduler.h" =20 #include @@ -77,12 +77,10 @@ mRunByIndex =3D mRunning =3D false; mRoot =3D 0; mSearchPattern =3D 0; =2D mSearchedCount =3D 0; mFoundCount =3D 0; =20 mProcessNextBatchTimer =3D new QTimer(); =2D connect(mProcessNextBatchTimer, SIGNAL(timeout()), =2D this, SLOT(slotProcessNextBatch())); + connect(mProcessNextBatchTimer, SIGNAL(timeout()), this, SLOT(slotProc= essNextBatch())); } =20 KMSearch::~KMSearch() @@ -155,7 +153,6 @@ return; } =20 =2D mSearchedCount =3D 0; mFoundCount =3D 0; mRunning =3D true; mRunByIndex =3D false; @@ -231,6 +228,11 @@ emit finished(false); } =20 +void KMSearch::indexFinished() { + mRunning =3D false; + mRunByIndex =3D false; +} + void KMSearch::slotProcessNextBatch() { if ( !running() ) @@ -246,11 +248,9 @@ folder->open(); mOpenedFolders.append( folder ); connect( folder->storage(), =2D SIGNAL( searchResult( KMFolder*, QValueList, =2D const KMSearchPattern*, bool ) ), + SIGNAL( searchResult( KMFolder*, QValueList, con= st KMSearchPattern*, bool ) ), this, =2D SLOT( slotSearchFolderResult( KMFolder*, QValueList, =2D const KMSearchPattern*, bo= ol ) ) ); + SLOT( slotSearchFolderResult( KMFolder*, QValueList, const KMSearchPattern*, bool ) ) ); folder->storage()->search( mSearchPattern ); } else --mRemainingFolders; @@ -281,7 +281,6 @@ this, SLOT( slotSearchFolderResult( KMFolder*, QValueList, const KMSearchPattern*, bool ) ) ); =2D mSearchedCount +=3D folder->count(); --mRemainingFolders; folder->close(); mOpenedFolders.remove( folder ); Index: kmmsgindex.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- kmmsgindex.cpp (revision 440058) +++ kmmsgindex.cpp (working copy) @@ -1,6 +1,7 @@ // Author: Sam Magnuson // License GPL -- indexing logic for KMail =20 +#if 0 #ifdef HAVE_CONFIG_H #include #endif @@ -1242,7 +1243,6 @@ if (!folder || (idx =3D=3D -1)) continue; if(mSearch->inScope(folder)) { =2D mSearch->setSearchedCount(mSearch->searchedCount()+1); mSearch->setCurrentFolder(folder->label()); if(mVerifyResult) { //full phrase.. if(mOpenedFolders.findIndex(folder) =3D=3D -1) { @@ -1297,3 +1297,4 @@ return stopQuery(id); } #include "kmmsgindex.moc" +#endif=20 =2D-- /dev/null Sun Jul 31 11:23:40 2005 +++ klistviewindexedsearchline.cpp Fri Jul 29 11:31:03 2005 @@ -0,0 +1,75 @@ + +/* This file is part of KMail + * Copyright (C) 2005 Lu=EDs Pedro Coelho + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + *=20 + * KMail 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. + *=20 + * 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 U= SA + *=20 + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ + +#include "klistviewindexedsearchline.h" +#include +#include +#include +#include "headeritem.h" +#include "kmheaders.h" +#include "kmfolder.h" +#include "index.h" + +using KMail::HeaderListQuickSearch; + +KListViewIndexedSearchLine::KListViewIndexedSearchLine( QWidget* parent, K= ListView* listView, KActionCollection* actionCollection, const char* name ): + HeaderListQuickSearch( parent, listView, actionCollection, name ), + mFiltering( false ) +{ +} + +KListViewIndexedSearchLine::~KListViewIndexedSearchLine() { +} + + +//std::string dirbase =3D std::string( getenv( "HOME" ) ) + "/.indexes/" += folder->location().latin1(); + +void KListViewIndexedSearchLine::updateSearch( const QString& s ) { + kdDebug( 5006 ) << "updateSearch( -" << s << "- )" << endl; + mFiltering =3D false; + if ( !s.isNull() && !s.isEmpty() ) { + KMMsgIndex* index =3D kmkernel->msgIndex(); + mResults =3D index->simpleSearch( s ); + std::sort( mResults.begin(), mResults.end() ); + mFiltering =3D true; + } + KListViewSearchLine::updateSearch( s ); +} +#include +#define kdDebug( x ) std::cerr +#define endl std::endl + +bool KListViewIndexedSearchLine::itemMatches( const QListViewItem* item, c= onst QString& s ) const { + return !mFiltering || + std::binary_search( mResults.begin(), mResults.end(), static_cast( item )->msgSerNum() ) + || KListViewSearchLine::itemMatches( item, s ); +} + +#include "klistviewindexedsearchline.moc" + =2D-- /dev/null Sun Jul 31 11:23:40 2005 +++ klistviewindexedsearchline.h Fri Jul 29 11:31:03 2005 @@ -0,0 +1,73 @@ +#ifndef LPC_KLISTVIEWINDEXEDSEARCHLINE_H1107549660_INCLUDE_GUARD_ +#define LPC_KLISTVIEWINDEXEDSEARCHLINE_H1107549660_INCLUDE_GUARD_ + +/* This file is part of KMail + * Copyright (C) 2005 Lu=EDs Pedro Coelho + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + *=20 + * KMail 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. + *=20 + * 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 U= SA + *=20 + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ + + +#include +#include +#include "headerlistquicksearch.h" +#include + +#include + +class KListView; +class QListViewItem; +class QToolButton; +class KListViewSearchLine; +class indexer; + +class KDEUI_EXPORT KListViewIndexedSearchLine: public KMail::HeaderListQui= ckSearch +{ + Q_OBJECT + +public: + + explicit KListViewIndexedSearchLine(QWidget *parent, KListView *listVi= ew, KActionCollection* action, const char *name =3D 0); + ~KListViewIndexedSearchLine(); + +public slots: + /** + * Updates search to only make visible the items that match \a s. If + * \a s is null then the line edit's text will be used. + */ + virtual void updateSearch(const QString &s =3D QString::null); + +protected: + virtual bool itemMatches(const QListViewItem *item, const QString &s) = const; + +private: + std::vector mResults; + bool mFiltering; + +}; + + + +#endif /* LPC_KLISTVIEWINDEXEDSEARCHLINE_H1107549660_INCLUDE_GUARD_ */ =2D-- /dev/null Sun Jul 31 11:23:40 2005 +++ index.h Fri Jul 29 11:31:03 2005 @@ -0,0 +1,151 @@ +#ifndef LPC_INDEX_H1110724080_INCLUDE_GUARD_ +#define LPC_INDEX_H1110724080_INCLUDE_GUARD_ + +/* This file is part of KMail + * Copyright (C) 2005 Lu=EDs Pedro Coelho + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + *=20 + * KMail 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. + *=20 + * 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 U= SA + *=20 + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +class KMFolder; + +class KMSearch; +class KMSearchRule; +class KMSearchPattern; + +class KMMsgIndex : public QObject { + Q_OBJECT + public: + explicit KMMsgIndex( QObject* parent ); + ~KMMsgIndex(); + + public: + =09 + bool startQuery( KMSearch* ); + bool stopQuery( KMSearch* ); + + std::vector simpleSearch( QString ) const; + public slots: + void clear(); + void create(); + void cleanUp(); + + private slots: + void act(); + void removeSearch( QObject* ); + + //void syncIndex(); + //void startSync(); + void continueCreation(); + + void slotAddMessage( KMFolder*, Q_UINT32 message ); + void slotRemoveMessage( KMFolder*, Q_UINT32 message ); + private: + static QString defaultPath(); + + bool canHandleQuery( const KMSearchPattern* ) const; + bool isIndexed( const KMFolder* ) const; + int addMessage( Q_UINT32 ); + void removeMessage( Q_UINT32 ); + + void scheduleAction(); + bool creating() const; + + public: + /** + * @internal + * DO NOT USE THIS CLASS + * + * It is conceptually a private class. Just needs to be public because o= f moc limitations + */ + class Search; + private: + + std::vector mPendingMsgs; + std::vector mPendingFolders; + std::vector mAddedMsgs; + std::vector mRemovedMsgs; + std::vector mExisting; + + enum e_state { + s_idle, // doing nothing + s_willcreate, // just constructed, create() scheduled (mIndex =3D=3D 0) + s_creating, // creating the index from the messages + s_processing // has messages to process + } mState; + + unsigned mMaintenanceCount; + + /** + * The lock below should be moved down into libindex itself + * where things can be handled with a lot more granularity + */ + indexlib::detail::lockfile mLockFile; + //enum e_syncState { ss_none, ss_started, ss_synced } mSyncState; + //QTimer* mSyncTimer; + + std::set mOpenedFolders; + std::vector mSearches; + indexlib::index* mIndex; + QCString mIndexPath; + QTimer* mTimer; + bool mSlowDown; +}; + + +class KMMsgIndex::Search : public QObject { + Q_OBJECT + public: + explicit Search( KMSearch* s ); + ~Search(); + KMSearch* search() const { return mSearch; } + signals: + void found( Q_UINT32 ); + void finished( bool ); + private slots: + void act(); + private: + KMSearch* mSearch; + QTimer* mTimer; + /** + * mResidual is the part of the pattern which is not + * handled by the index + */ + KMSearchPattern* mResidual; + std::vector mValues; + enum { s_none =3D 0, s_starting, s_emitting, s_emitstopped, s_done } mSt= ate; +}; + +#endif /* LPC_INDEX_H1110724080_INCLUDE_GUARD_ */ =2D-- /dev/null Sun Jul 31 11:23:40 2005 +++ index.cpp Fri Jul 29 11:31:03 2005 @@ -0,0 +1,435 @@ +/* This file is part of KMail + * Copyright (C) 2005 Lu=EDs Pedro Coelho + * + * KMail is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + *=20 + * KMail 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. + *=20 + * 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 U= SA + *=20 + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ + +#include "index.h" + +#include "kmkernel.h" +#include "kmfoldermgr.h" +#include "kmmsgdict.h" +#include "kmfolder.h" +#include "kmsearchpattern.h" +#include "kmfoldersearch.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +const unsigned int MaintenanceLimit =3D 1000; + +static +QValueList vectorToQValueList( const std::vector& input ) { + QValueList res; + std::copy( input.begin(), input.end(), std::back_inserter( res ) ); + return res; +} + + +static +std::vector QValueListToVector( const QValueList& input ) { + std::vector res; + // res.assign( input.begin(), input.end() ) doesn't work for some reason + for ( QValueList::const_iterator first =3D input.begin(), past =3D i= nput.end(); first !=3D past; ++first ) { + res.push_back( *first ); + } + return res; +} + +KMMsgIndex::KMMsgIndex( QObject* parent ): + QObject( parent, "index" ), + mIndex( 0 ), + mState( s_idle ), + mIndexPath( QFile::encodeName( defaultPath() ) ), + mTimer( new QTimer( this ) ), + mLockFile( std::string( static_cast( QFile::encodeName( defa= ultPath() ) + "/lock" ) ) ), + //mSyncState( ss_none ), + //mSyncTimer( new QTimer( this ) ), + mSlowDown( false ) { + kdDebug( 5006 ) << "KMMsgIndex::KMMsgIndex()" << endl; +=09 + if ( !QFileInfo( mIndexPath ).exists() ) { + ::mkdir( mIndexPath, S_IRWXU ); + } +=09 + connect( kmkernel->folderMgr(), SIGNAL( msgRemoved( KMFolder*, Q_UINT32 )= ), SLOT( slotRemoveMessage( KMFolder*, Q_UINT32 ) ) ); + connect( kmkernel->folderMgr(), SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) )= , SLOT( slotAddMessage( KMFolder*, Q_UINT32 ) ) ); + connect( kmkernel->dimapFolderMgr(), SIGNAL( msgRemoved( KMFolder*, Q_UIN= T32 ) ), SLOT( slotRemoveMessage( KMFolder*, Q_UINT32 ) ) ); + connect( kmkernel->dimapFolderMgr(), SIGNAL( msgAdded( KMFolder*, Q_UINT3= 2 ) ), SLOT( slotAddMessage( KMFolder*, Q_UINT32 ) ) ); + + connect( mTimer, SIGNAL( timeout() ), SLOT( act() ) ); + //connect( mSyncTimer, SIGNAL( timeout() ), SLOT( syncIndex() ) ); + + if ( !mLockFile.trylock() ) { + indexlib::remove( mIndexPath ); + mLockFile.force_unlock(); + mLockFile.trylock(); + } else { + mIndex =3D indexlib::open( mIndexPath, indexlib::open_flags::fail_if_non= existant ).release(); + } + if ( !mIndex ) { + QTimer::singleShot( 8000, this, SLOT( create() ) ); + mState =3D s_willcreate; + } else { + KConfigGroup cfg( KMKernel::config(), "text-index" ); + if ( cfg.readBoolEntry( "creating" ) ) { + QTimer::singleShot( 8000, this, SLOT( continueCreation() ) ); + mState =3D s_creating; + } else { + mPendingMsgs =3D QValueListToVector( cfg.readIntListEntry( "pending" ) = ); + mRemovedMsgs =3D QValueListToVector( cfg.readIntListEntry( "removed" ) = ); + } + } + //if ( mState =3D=3D s_idle ) mSyncState =3D ss_synced; +} + + +KMMsgIndex::~KMMsgIndex() { + kdDebug( 5006 ) << "KMMsgIndex::~KMMsgIndex()" << endl; + KConfigGroup cfg( KMKernel::config(), "text-index" ); + cfg.writeEntry( "creating", mState =3D=3D s_creating ); + QValueList pendingMsg; + if ( mState =3D=3D s_processing ) { + Q_ASSERT( mAddedMsgs.empty() ); + pendingMsg =3D vectorToQValueList( mPendingMsgs ); + } + cfg.writeEntry( "pending", pendingMsg ); + cfg.writeEntry( "removed", vectorToQValueList( mRemovedMsgs ) ); + delete mIndex; +} + +void KMMsgIndex::clear() { + delete mIndex; + mLockFile.force_unlock(); + mIndex =3D 0; + indexlib::remove( mIndexPath ); +} + +void KMMsgIndex::cleanUp() { + if ( mState !=3D s_idle || kapp->hasPendingEvents() ) { + QTimer::singleShot( 8000, this, SLOT( cleanUp() ) ); + return; + } + mIndex->maintenance(); +} + +int KMMsgIndex::addMessage( Q_UINT32 serNum ) { + kdDebug( 5006 ) << "KMMsgIndex::addMessage( " << serNum << " )" << endl; + assert( mIndex ); + if ( !mExisting.empty() && std::binary_search( mExisting.begin(), mExisti= ng.end(), serNum ) ) return 0; + + int idx =3D -1; + KMFolder* folder =3D 0; + KMMsgDict::instance()->getLocation( serNum, &folder, &idx ); + if ( !folder || idx =3D=3D -1 ) return -1; + if ( !mOpenedFolders.count( folder ) ) { + mOpenedFolders.insert( folder ); + folder->open(); + } + KMMessage* msg =3D folder->getMsg( idx ); + /* I still don't know whether we should allow decryption or not. + * Setting to false which makes more sense. + * We keep signature to get the person's name + */ + QString body =3D msg->asPlainText( false, false ); + if ( !body.isEmpty() && static_cast( body.latin1() ) ) { + mIndex->add( body.latin1(), QString::number( serNum ).latin1() ); + } else { + kdDebug( 5006 ) << "Funny, no body" << endl; + } + folder->unGetMsg( idx ); + return 0; +} + +void KMMsgIndex::act() { + kdDebug( 5006 ) << "KMMsgIndex::act()" << endl; + if ( kapp->hasPendingEvents() ) { + //nah, some other time.. + mTimer->start( 500 ); + mSlowDown =3D true; + return; + } + if ( mSlowDown ) { + mSlowDown =3D false; + mTimer->start( 0 ); + } + if ( !mPendingMsgs.empty() ) { + addMessage( mPendingMsgs.back() ); + mPendingMsgs.pop_back(); + return; + } + if ( !mPendingFolders.empty() ) { + KMFolder *f =3D mPendingFolders.back(); + mPendingFolders.pop_back(); + if ( !mOpenedFolders.count( f ) ) { + mOpenedFolders.insert( f ); + f->open(); + } + KMMsgDict* dict =3D KMMsgDict::instance(); + for ( int i =3D 0; i < f->count(); ++i) { + mPendingMsgs.push_back( dict->getMsgSerNum( f, i ) ); + } + return; + } + if ( !mAddedMsgs.empty() ) { + std::swap( mAddedMsgs, mPendingMsgs ); + mState =3D s_processing; + return; + } + for ( std::set::const_iterator first =3D mOpenedFolders.begin(= ), past =3D mOpenedFolders.end(); + first !=3D past; + ++first ) { + ( *first )->close(); + } + mOpenedFolders.clear(); + mState =3D s_idle; + mTimer->stop(); +} + +void KMMsgIndex::continueCreation() { + kdDebug( 5006 ) << "KMMsgIndex::continueCreation()" << endl; + create(); + unsigned count =3D mIndex->ndocs(); + mExisting.clear(); + mExisting.reserve( count ); + for ( unsigned i =3D 0; i !=3D count; ++i ) { + mExisting.push_back( std::atoi( mIndex->lookup_docname( i ).c_str() ) ); + } + std::sort( mExisting.begin(), mExisting.end() ); +} + +void KMMsgIndex::create() { + kdDebug( 5006 ) << "KMMsgIndex::create()" << endl; + mState =3D s_creating; + if ( !mIndex ) mIndex =3D indexlib::create( mIndexPath ).release(); + Q_ASSERT( mIndex ); + QValueStack folders; + folders.push(&(kmkernel->folderMgr()->dir())); + folders.push(&(kmkernel->dimapFolderMgr()->dir())); + while ( !folders.empty() ) { + KMFolderDir *dir =3D folders.pop(); + for(KMFolderNode *child =3D dir->first(); child; child =3D dir->next()) { + if ( child->isDir() ) + folders.push((KMFolderDir*)child); + else + mPendingFolders.push_back( (KMFolder*)child ); + } + } + mTimer->start( 4000 ); // wait a couple of seconds before starting up... + mSlowDown =3D true; +} + +bool KMMsgIndex::startQuery( KMSearch* s ) { + kdDebug( 5006 ) << "KMMsgIndex::startQuery( . )" << endl; + if ( mState =3D=3D s_creating ) return false; + if ( !isIndexed( s->root() ) || !canHandleQuery( s->searchPattern() ) ) r= eturn false; + + kdDebug( 5006 ) << "KMMsgIndex::startQuery( . ) starting query" << endl; + Search* search =3D new Search( s ); + connect( search, SIGNAL( finished( bool ) ), s, SIGNAL( finished( bool ) = ) ); + connect( search, SIGNAL( finished( bool ) ), s, SLOT( indexFinished() ) ); + connect( search, SIGNAL( destroyed( QObject* ) ), SLOT( removeSearch( QOb= ject* ) ) ); + connect( search, SIGNAL( found( Q_UINT32 ) ), s, SIGNAL( found( Q_UINT32 = ) ) ); + mSearches.push_back( search ); + return true; +} + + +//void KMMsgIndex::startSync() { +// switch ( mSyncState ) { +// case ss_none: +// mIndex->start_sync(); +// mSyncState =3D ss_started; +// mSyncTimer.start( 4000, true ); +// break; +// case ss_started: +// mIndex->sync_now(); +// mSyncState =3D ss_synced; +// mLockFile.unlock(); +// break; +// } +//} +// +//void KMMsgIndex::finishSync() { +//=09 +//} + +void KMMsgIndex::removeSearch( QObject* destroyed ) { + mSearches.erase( std::find( mSearches.begin(), mSearches.end(), destroyed= ) ); +} + +bool KMMsgIndex::isIndexed( const KMFolder* folder ) const { + if ( mState =3D=3D s_creating || mState =3D=3D s_willcreate ) return fals= e; + const KMFolderMgr* manager =3D folder->parent()->manager(); + return manager =3D=3D kmkernel->folderMgr() || manager =3D=3D kmkernel->d= imapFolderMgr(); +} + +bool KMMsgIndex::stopQuery( KMSearch* s ) { + kdDebug( 5006 ) << "KMMsgIndex::stopQuery( . )" << endl; + for ( std::vector::iterator iter =3D mSearches.begin(), past =3D= mSearches.end(); iter !=3D past; ++iter ) { + if ( ( *iter )->search() =3D=3D s ) { + delete *iter; + mSearches.erase( iter ); + return true; + } + } + return false; +} + +std::vector KMMsgIndex::simpleSearch( QString s ) const { + kdDebug( 5006 ) << "KMMsgIndex::simpleSearch( -" << s.latin1() << "- )" <= < endl; + std::vector res; + assert( mIndex ); + std::vector residx =3D mIndex->search( s.latin1() )->list(); + res.reserve( residx.size() ); + for ( std::vector::const_iterator first =3D residx.begin(), pas= t =3D residx.end();first !=3D past; ++first ) { + res.push_back( std::atoi( mIndex->lookup_docname( *first ).c_str() ) ); + } + return res; +} + +bool KMMsgIndex::canHandleQuery( const KMSearchPattern* pat ) const { + kdDebug( 5006 ) << "KMMsgIndex::canHandleQuery( . )" << endl; + for ( KMSearchRule* rule =3D pat->first(); rule; rule =3D pat->next() ) { + if ( !rule->field().isEmpty() && !rule->contents().isEmpty() && + rule->function() =3D=3D KMSearchRule::FuncContains && + rule->field() =3D=3D "" ) return true; + } + return false; +} + +void KMMsgIndex::slotAddMessage( KMFolder* folder, Q_UINT32 serNum ) { + kdDebug( 5006 ) << "KMMsgIndex::slotAddMessage( . , " << serNum << " )" <= < endl; +=09 + if ( mState =3D=3D s_creating ) mAddedMsgs.push_back( serNum ); + else mPendingMsgs.push_back( serNum ); + + if ( mState =3D=3D s_idle ) mState =3D s_processing; + scheduleAction(); +} + +void KMMsgIndex::slotRemoveMessage( KMFolder* folder, Q_UINT32 serNum ) { + kdDebug( 5006 ) << "KMMsgIndex::slotRemoveMessage( . , " << serNum << " )= " << endl; + if ( mState =3D=3D s_idle ) mState =3D s_processing; + mRemovedMsgs.push_back( serNum ); + scheduleAction(); +} + +void KMMsgIndex::scheduleAction() { + if ( mState =3D=3D s_willcreate || !mIndex ) return; + if ( !mSlowDown ) mTimer->start( 0 ); +} + +void KMMsgIndex::removeMessage( Q_UINT32 serNum ) { + mIndex->remove_doc( QString::number( serNum ).latin1() ); + ++mMaintenanceCount; + if ( mMaintenanceCount > MaintenanceLimit && mRemovedMsgs.empty() ) { + QTimer::singleShot( 100, this, SLOT( cleanUp() ) ); + } +} + +QString KMMsgIndex::defaultPath() { + return KMKernel::localDataPath() + "text-index"; +} + +bool KMMsgIndex::creating() const { + return !mPendingMsgs.empty() || !mPendingFolders.empty(); +} + +KMMsgIndex::Search::Search( KMSearch* s ): + mSearch( s ), + mTimer( new QTimer( this ) ), + mState( s_starting ), + mResidual( new KMSearchPattern ) { + connect( mTimer, SIGNAL( timeout() ), SLOT( act() ) ); + mTimer->start( 0 ); +} + +KMMsgIndex::Search::~Search() { + delete mTimer; +} + +void KMMsgIndex::Search::act() { + switch ( mState ) { + case s_starting: { + KMSearchPattern* pat =3D mSearch->searchPattern(); + QString terms; + for ( KMSearchRule* rule =3D pat->first(); rule; rule =3D pat->next() )= { + Q_ASSERT( rule->function() =3D=3D KMSearchRule::FuncContains ); + terms +=3D QString::fromLatin1( " %1 " ).arg( rule->contents() ); + } + + mValues =3D kmkernel->msgIndex()->simpleSearch( terms ); + mState =3D s_emitting; + break; + } + case s_emitstopped: + mTimer->start( 0 ); + mState =3D s_emitting; + // fall throu + case s_emitting: + if ( kapp->hasPendingEvents() ) { + //nah, some other time.. + mTimer->start( 250 ); + mState =3D s_emitstopped; + return; + } + for ( int i =3D 0; i !=3D 16 && !mValues.empty(); ++i ) { + KMFolder* folder; + int index; + KMMsgDict::instance()->getLocation( mValues.back(), &folder, &index ); + if ( folder && + mSearch->inScope( folder ) && + ( !mResidual || mResidual->matches( mValues.back() ) ) ) { + + emit found( mValues.back() ); + } + mValues.pop_back(); + } + if ( mValues.empty() ) { + emit finished( true ); + mState =3D s_done; + mTimer->stop(); + delete this; + } + break; + default: + Q_ASSERT( 0 ); + } +} +#include "index.moc" + --Boundary-00=_PhR7CLNuOQAlFIK Content-Type: text/plain; charset="iso-8859-1" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline _______________________________________________ KMail developers mailing list KMail-devel@kde.org https://mail.kde.org/mailman/listinfo/kmail-devel --Boundary-00=_PhR7CLNuOQAlFIK--