/***************************************************************************
* kio - locate : KDE I / O Slave for the locate command *
* *
* Copyright ( C ) 2005 by Tobi Vollebregt *
* tobivollebregt @ gmail . com *
* *
* Thanks to Google ' s Summer Of Code Program ! *
* *
* Copyright ( C ) 2004 by Armin Straub *
* linux @ arminstraub . de *
* *
* This program was initially written by Michael Schuerig . *
* Although I have completely rewritten it , most ideas are adopted *
* from his original work . *
* *
* Copyright ( C ) 2002 by Michael Schuerig *
* michael @ schuerig . de *
* *
* *
* 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 . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <algorithm>
# include <stdlib.h>
# include <sys/stat.h>
# include <pwd.h>
# include <grp.h>
# include <tdeapplication.h>
# include <tdeconfigdialog.h>
# include <kdebug.h>
# include <kde_file.h>
# include <kiconloader.h>
# include <tdelocale.h>
# include <kurl.h>
# include <kuser.h>
# include <tqfile.h>
# include "tdeio_locate.h"
# include "klocateconfig.h"
# include "klocateconfigwidget.h"
# include "klocateconfigfilterwidget.h"
# include "klocateconfiglocatewidget.h"
using namespace TDEIO ;
static const TQString queryQuery = " q " ;
static const TQString queryDirectory = " directory " ;
static const TQString queryCase = " case " ;
static const TQString queryRegExp = " regexp " ;
static const TQString iconToStringTable [ ] = {
" folder " , " folder_green " , " folder_grey " , " folder_orange " ,
" folder_red " , " folder_violet " , " folder_yellow "
} ;
/////////////////////////////////////////////////////////////////////
// HELPERS
/**
* Determines if a string contains unescaped wildcard characters .
* Currently , wildcard characters are : * + ? [ ]
* For older versions of Konqueror : + behaves identical to *
* @ param s the string to inspect
*/
static bool hasWildcards ( const TQString & s )
{
for ( unsigned int i = 0 ; i < s . length ( ) ; + + i ) {
if ( ( s [ i ] = = ' * ' | | s [ i ] = = ' + ' | | s [ i ] = = ' ? ' | | s [ i ] = = ' [ ' | | s [ i ] = = ' ] ' ) & & ( i < 1 | | s [ i - 1 ] ! = ' \\ ' ) )
return true ;
}
return false ;
}
/**
* Converts a string containing shell wildcard characters ( globbing characters )
* to a regular expression . This function takes care of escaped wildcards and
* any regexp special characters which happen to be in the string .
* @ param s the string to convert
* @ return the converted string
*/
static TQString convertWildcardsToRegExp ( TQString s )
{
bool in_set = false ;
// No support for regexp searches.
// (Konqueror makes passing chars like "/" almost impossible anyway.)
// Note that this converts actual wildcards to escaped wildcards (\wildcard),
// and escaped wildcards to 'triple'-escaped wildcards (\\\wildcard).
s = TQRegExp : : escape ( s ) ;
// Walk through the string, converting \wildcard to regexp and
// \\\wildcard back to \wildcard.
for ( unsigned i = 1 ; i < s . length ( ) ; + + i ) {
//DEBUGSTR << s.left(i+1) << endl;
if ( i < 3 | | s [ i - 3 ] ! = ' \\ ' | | s [ i - 2 ] ! = ' \\ ' ) {
// If it was an unescaped character (now possibly escaped once)
if ( s [ i - 1 ] = = ' \\ ' ) {
// If it actually was escaped once
if ( ! in_set ) {
// If it's NOT inside a character set, we need to convert *?[
if ( s [ i ] = = ' * ' | | s [ i ] = = ' + ' ) {
s = s . left ( i - 1 ) + " [^/]* " + s . mid ( i + 1 ) ;
i + = 3 ; // 3 == strlen("[^/]*")-strlen("\\*")
} else if ( s [ i ] = = ' ? ' ) {
s = s . left ( i - 1 ) + " [^/] " + s . mid ( i + 1 ) ;
i + = 2 ; // 2 == strlen("[^/]")-strlen("\\*")
} else if ( s [ i ] = = ' [ ' ) {
s = s . left ( i - 1 ) + s . mid ( i ) ;
- - i ;
in_set = true ;
}
} else {
// If it's inside a character set, we need to convert ]^
// and to unescape everything else.
if ( s [ i ] = = ' ] ' ) {
s = s . left ( i - 1 ) + s . mid ( i ) ;
- - i ;
in_set = false ;
} else if ( s [ i ] = = ' ^ ' & & i > = 2 & & s [ i - 2 ] = = ' [ ' ) {
s = s . left ( i - 1 ) + s . mid ( i ) ;
- - i ;
} else {
s = s . left ( i - 1 ) + s . mid ( i ) ;
}
}
}
} else {
// If it's an escaped character, remove the extra escape characters.
s = s . left ( i - 3 ) + s . mid ( i - 1 ) ;
i - = 2 ; // 2 == strlen("\\\\")-strlen("")
}
}
return s ;
}
/**
* Determines if path includes a trailing slash .
* @ param path the path to inspect
*/
static bool hasTrailingSlash ( const TQString & path )
{
int n = path . length ( ) ;
return ( ( n > 0 ) & & ( path [ n - 1 ] = = ' / ' ) ) ;
}
/**
* Strips a trailing slash / from a path .
* @ param path the path to strip the slash off
*/
static TQString stripTrailingSlash ( const TQString & path )
{
int n = path . length ( ) ;
if ( ( n > 0 ) & & ( path [ n - 1 ] = = ' / ' ) ) {
return path . left ( n - 1 ) ;
}
return path ;
}
/**
* Add a trailing slash / to a path if there is none yet .
* @ param path the path to append the slash to
*/
static TQString addTrailingSlash ( const TQString & path )
{
int n = path . length ( ) ;
if ( ( n > 0 ) & & ( path [ n - 1 ] = = ' / ' ) ) {
return path ;
}
return path + ' / ' ;
}
static void addAtom ( UDSEntry & entry , unsigned int uds , const TQString & s )
{
UDSAtom a ;
a . m_uds = uds ;
a . m_str = s ;
entry . append ( a ) ;
}
static void addAtom ( UDSEntry & entry , unsigned int uds , long long l )
{
UDSAtom a ;
a . m_uds = uds ;
a . m_long = l ;
entry . append ( a ) ;
}
static const UDSEntry pathToUDSEntry ( const TQString & path , const TQString & display ,
const TQString & url = TQString ( ) , const TQString & icon = TQString ( ) )
{
UDSEntry entry ;
addAtom ( entry , TDEIO : : UDS_NAME , display ) ;
if ( ! path . isEmpty ( ) ) {
KDE_struct_stat info ;
KDE_lstat ( path . local8Bit ( ) , & info ) ;
addAtom ( entry , TDEIO : : UDS_SIZE , info . st_size ) ;
addAtom ( entry , TDEIO : : UDS_ACCESS , info . st_mode ) ;
addAtom ( entry , TDEIO : : UDS_MODIFICATION_TIME , info . st_mtime ) ;
addAtom ( entry , TDEIO : : UDS_ACCESS_TIME , info . st_atime ) ;
addAtom ( entry , TDEIO : : UDS_CREATION_TIME , info . st_ctime ) ;
struct passwd * user = getpwuid ( info . st_uid ) ;
struct group * group = getgrgid ( info . st_gid ) ;
addAtom ( entry , TDEIO : : UDS_USER , ( ( user ! = NULL ) ? user - > pw_name : " ??? " ) ) ;
addAtom ( entry , TDEIO : : UDS_GROUP , ( ( group ! = NULL ) ? group - > gr_name : " ??? " ) ) ;
if ( url . isEmpty ( ) ) {
// List an existing file.
addAtom ( entry , TDEIO : : UDS_URL , " file: " + path ) ;
mode_t type = info . st_mode ;
if ( S_ISLNK ( type ) ) {
TQString slink = TQString ( ) ;
char buff [ 1000 ] ;
int n = readlink ( path . ascii ( ) , buff , 1000 ) ;
if ( n ! = - 1 ) {
buff [ n ] = 0 ;
slink = buff ;
}
addAtom ( entry , TDEIO : : UDS_LINK_DEST , slink ) ;
} else {
type & = S_IFMT ;
}
addAtom ( entry , TDEIO : : UDS_FILE_TYPE , type ) ;
# ifdef HAVE_UDS_HIDDEN
if ( path . contains ( " /. " ) ) {
addAtom ( entry , TDEIO : : UDS_HIDDEN , 1 ) ;
}
# endif
} else {
// List a locate link.
addAtom ( entry , TDEIO : : UDS_URL , url ) ;
addAtom ( entry , TDEIO : : UDS_FILE_TYPE , S_IFDIR ) ;
}
} else {
addAtom ( entry , TDEIO : : UDS_URL , url ) ;
}
if ( ! icon . isEmpty ( ) ) {
addAtom ( entry , TDEIO : : UDS_ICON_NAME , icon ) ;
}
return entry ;
}
/////////////////////////////////////////////////////////////////////
// INITIALIZATION
LocateProtocol : : LocateProtocol ( const TQCString & pool_socket , const TQCString & app_socket )
: SlaveBase ( " tdeio_locate " , pool_socket , app_socket )
{
DEBUGSTR < < " LocateProtocol::LocateProtocol() " < < endl ;
connect ( & m_locater , TQT_SIGNAL ( found ( const TQStringList & ) ) ,
this , TQT_SLOT ( processLocateOutput ( const TQStringList & ) ) ) ;
connect ( & m_locater , TQT_SIGNAL ( finished ( ) ) ,
this , TQT_SLOT ( locateFinished ( ) ) ) ;
m_baseDir = NULL ;
m_curDir = NULL ;
}
LocateProtocol : : ~ LocateProtocol ( )
{
DEBUGSTR < < " LocateProtocol::~LocateProtocol() " < < endl ;
delete m_baseDir ;
}
const LocateRegExp & LocateProtocol : : getRegExp ( ) const
{
return m_locateRegExp ;
}
int LocateProtocol : : getCollapseDirectoryThreshold ( ) const
{
return m_config . m_collapseDirectoryThreshold ;
}
/////////////////////////////////////////////////////////////////////
// KIO STUFF
void LocateProtocol : : setUrl ( const KURL & url )
{
if ( url . protocol ( ) ! = " locater " ) {
TQString pattern = KURL : : decode_string ( url . url ( ) ) ;
pattern = pattern . mid ( url . protocol ( ) . length ( ) + 1 ) ;
KURL newUrl ;
newUrl . setProtocol ( " locater " ) ;
if ( pattern . isEmpty ( ) | | pattern = = " / " ) {
// Give help.
newUrl . setPath ( " help " ) ;
} else if ( hasTrailingSlash ( pattern ) ) {
// Detect auto-completion from within konqueror and "stop"
// this search.
newUrl . setPath ( " autosearch " ) ;
newUrl . addQueryItem ( queryQuery , pattern ) ;
} else if ( url . protocol ( ) = = " rlocate " ) {
// Standard regexp search.
newUrl . setPath ( " search " ) ;
newUrl . addQueryItem ( queryQuery , pattern ) ;
newUrl . addQueryItem ( queryRegExp , " 1 " ) ;
} else {
// Standard wildcard search.
newUrl . setPath ( " search " ) ;
newUrl . addQueryItem ( queryQuery , pattern ) ;
}
m_url = newUrl ;
DEBUGSTR < < " Redirect: " < < m_url < < endl ;
} else {
m_url = url ;
}
// Perhaps this will be unneccessary most times, but who knows...
updateConfig ( ) ;
}
void LocateProtocol : : get ( const KURL & url )
{
DEBUGSTR < < " LocateProtocol::get( " < < url < < " ) " < < endl ;
setUrl ( url ) ;
if ( isSearchRequest ( ) ) {
if ( m_locater . binaryExists ( ) ) {
error ( TDEIO : : ERR_IS_DIRECTORY , TQString ( ) ) ;
} else {
TQString html = i18n ( " <h1> \" %1 \" could not be started.</h1><p>Please note that kio-locate can't be used on its own. You need an additional program for doing searches. Typically this is the command line tool <i>locate</i> that can be found in many distributions by default. You can check if the correct tool is used by looking at the <a href= \" locater:config \" >setting</a> \" Locate Binary \" .<p>Besides the mentioned tool <i>locate</i>, kio-locate can use any tool that uses the same syntax. In particular, it was reported to work with <i>slocate</i> and <i>rlocate</i>. " ) . arg ( m_locater . binary ( ) ) ;
outputHtml ( html ) ;
}
} else if ( isConfigRequest ( ) ) {
configRequest ( ) ;
} else if ( isHelpRequest ( ) ) {
helpRequest ( ) ;
} else {
// What's this?
error ( TDEIO : : ERR_DOES_NOT_EXIST , TQString ( ) ) ;
}
}
void LocateProtocol : : stat ( const KURL & url )
{
DEBUGSTR < < " LocateProtocol::stat( " < < url < < " ) " < < endl ;
setUrl ( url ) ;
if ( isSearchRequest ( ) | | isConfigRequest ( ) | | isHelpRequest ( ) ) {
bool isDir = isSearchRequest ( ) & & m_locater . binaryExists ( ) ;
/// \todo Is UDS_NAME used for anything in stat? If so we should
/// at least strip of the protocol part.
UDSEntry entry ;
addAtom ( entry , TDEIO : : UDS_NAME , url . decode_string ( url . url ( ) ) ) ;
addAtom ( entry , TDEIO : : UDS_FILE_TYPE , isDir ? S_IFDIR : S_IFREG ) ;
statEntry ( entry ) ;
finished ( ) ;
/// \todo Somehow locate: and locate:/ is thought to be a directory
/// by konqueror anyway. How to change this?
} else {
// What's this?
error ( TDEIO : : ERR_DOES_NOT_EXIST , TQString ( ) ) ;
}
}
void LocateProtocol : : listDir ( const KURL & url )
{
DEBUGSTR < < " LocateProtocol::listDir( " < < url < < " ) " < < endl ;
setUrl ( url ) ;
if ( isSearchRequest ( ) ) {
searchRequest ( ) ;
} else if ( isConfigRequest ( ) | | isHelpRequest ( ) ) {
error ( TDEIO : : ERR_IS_FILE , TQString ( ) ) ;
} else {
// What's this?
error ( TDEIO : : ERR_DOES_NOT_EXIST , TQString ( ) ) ;
}
}
void LocateProtocol : : mimetype ( const KURL & url )
{
DEBUGSTR < < " LocateProtocol::mimetype( " < < url < < " ) " < < endl ;
setUrl ( url ) ;
if ( isSearchRequest ( ) ) {
if ( m_locater . binaryExists ( ) ) {
mimeType ( " inode/directory " ) ;
} else {
mimeType ( " text/html " ) ;
}
} else if ( isConfigRequest ( ) | | isHelpRequest ( ) ) {
mimeType ( " text/html " ) ;
}
finished ( ) ;
}
void LocateProtocol : : outputHtml ( const TQString & body )
{
mimeType ( " text/html " ) ;
TQString theData = " <html><body> " + body + " </body></html> " ;
data ( theData . local8Bit ( ) ) ;
finished ( ) ;
}
/////////////////////////////////////////////////////////////////////
// SEARCHING
bool LocateProtocol : : isSearchRequest ( )
{
return m_url . path ( ) = = " search " ;
}
void LocateProtocol : : searchRequest ( )
{
// Reset old values.
m_caseSensitivity = caseAuto ;
m_useRegExp = false ;
m_locatePattern = TQString ( ) ;
m_locateDirectory = TQString ( ) ;
m_regExps . clear ( ) ;
m_pendingPath = TQString ( ) ;
delete m_baseDir ;
m_baseDir = NULL ;
m_curDir = NULL ;
updateConfig ( ) ;
TQString query = m_url . queryItem ( queryQuery ) ;
m_locateDirectory = addTrailingSlash ( m_url . queryItem ( queryDirectory ) ) ;
TQString caseSensitivity = m_url . queryItem ( queryCase ) ;
if ( caseSensitivity = = " sensitive " ) {
m_caseSensitivity = caseSensitive ;
} else if ( caseSensitivity = = " insensitive " ) {
m_caseSensitivity = caseInsensitive ;
}
TQString useRegExp = m_url . queryItem ( queryRegExp ) ;
if ( ! useRegExp . isEmpty ( ) & & useRegExp ! = " 0 " ) {
m_useRegExp = true ;
}
// Split query into components. The first component is the query
// for locate. The others are filtering regular expressions. They are
// delimited by (not escaped) whitespace.
// If the last component starts with two backslahes \\, then the search
// is only to be done within the directory following them.
query = query . simplifyWhiteSpace ( ) ;
int s = 0 ;
int n = query . length ( ) ;
bool regexp ;
TQString display ;
for ( int i = 0 ; i < = n ; i + + ) {
if ( ( i = = n ) | | ( ( query [ i ] = = ' ' ) & & ( i > 0 )
& & ( query [ i - 1 ] ! = ' \\ ' ) & & ( i - s > 0 ) ) ) {
TQString temp = query . mid ( s , i - s ) ;
TQString part = partToPattern ( temp , s = = 0 ) ;
if ( s = = 0 ) {
// We don't want to show the escaped regexpified string to
// the user, so we store the string we get in for later display.
display = temp ;
// This is the same check as in partToPattern.
// ie. regexp is used if locate pattern contains wildcards,
// or regexp searching was enabled.
regexp = hasWildcards ( temp ) ;
m_locatePattern = part ;
} else {
// For each regular expression determine if it should be
// case sensitive.
m_regExps + = LocateRegExp ( part , ! isCaseSensitive ( part ) ) ;
}
s = i + 1 ;
}
}
DEBUGSTR < < " Pattern: " < < m_locatePattern < < endl ;
DEBUGSTR < < " Directory: " < < m_locateDirectory < < endl ;
// We set up the regexp used to see whether the match was in the
// directory part or the filename part of a path.
m_locateRegExp = LocateRegExp ( convertWildcardsToRegExp ( m_locatePattern ) , ! isCaseSensitive ( m_locatePattern ) ) ;
// Now perform the search...
infoMessage ( i18n ( " Locating %1 ... " ) . arg ( display ) ) ;
bool started = m_locater . locate ( m_locatePattern , ! isCaseSensitive ( m_locatePattern ) , regexp ) ;
if ( ! started ) {
DEBUGSTR < < " Locate could not be found. " < < endl ;
finished ( ) ;
}
}
bool LocateProtocol : : isCaseSensitive ( const TQString & text )
{
if ( m_caseSensitivity = = caseSensitive ) {
return true ;
} else if ( m_caseSensitivity = = caseInsensitive ) {
return false ;
} else if ( m_config . m_caseSensitivity = = caseSensitive ) {
return true ;
} else if ( m_config . m_caseSensitivity = = caseInsensitive ) {
return false ;
} else {
return text ! = text . lower ( ) ;
}
}
void LocateProtocol : : addHit ( const TQString & path , int subItems )
{
// DEBUGSTR << "LocateProtocol::addHit( " << path << ", " << subItems << " )" << endl;
if ( TQFile : : exists ( path ) ) {
if ( subItems > 0 ) {
m_entries + = pathToUDSEntry ( path , pathToDisplay ( path , subItems ) , makeLocaterUrl ( path ) , iconToStringTable [ m_config . m_collapsedIcon ] ) ;
} else {
m_entries + = pathToUDSEntry ( path , pathToDisplay ( path ) ) ;
}
}
}
void LocateProtocol : : addPreviousLocateOutput ( )
{
if ( m_baseDir = = NULL ) {
return ;
}
// m_baseDir->debugTrace();
if ( m_locateDirectory = = " / " ) {
// Allow toplevel directories to collapse (e.g. when locating "/usr/").
m_baseDir - > prepareListing ( this , 0 ) ;
} else {
m_baseDir - > prepareListing ( this , m_locateDirectory . length ( ) ) ;
}
m_baseDir - > listItems ( this ) ;
delete m_baseDir ;
m_baseDir = NULL ;
m_curDir = NULL ;
listEntries ( m_entries ) ;
m_entries . clear ( ) ;
}
void LocateProtocol : : processPath ( const TQString & path , const TQString & nextPath )
{
if ( ! nextPath ) {
// We need to know the next path, so we remember this path for later processing.
m_pendingPath = path ;
} else if ( ! nextPath . startsWith ( path + ' / ' ) ) {
if ( isMatching ( path ) ) {
if ( ( m_baseDir ! = NULL ) & & ! path . startsWith ( m_baseDir - > m_path ) ) {
addPreviousLocateOutput ( ) ;
}
// Add path to current directory.
if ( m_baseDir = = NULL ) {
int p = path . find ( ' / ' , 1 ) ;
TQString base = path ;
if ( p > = 0 ) {
base = path . left ( p + 1 ) ;
}
m_baseDir = new LocateDirectory ( NULL , base ) ;
m_curDir = m_baseDir ;
}
m_curDir = m_curDir - > addPath ( path ) ;
}
}
}
void LocateProtocol : : processLocateOutput ( const TQStringList & items )
{
// I don't know if this really necessary, but if we were signaled, we'll
// better stop.
if ( wasKilled ( ) ) {
m_locater . stop ( ) ;
return ;
}
// Go through what we have found.
TQStringList : : ConstIterator it = items . begin ( ) ;
if ( ! m_pendingPath . isNull ( ) ) {
processPath ( m_pendingPath , * it ) ;
m_pendingPath = TQString ( ) ;
}
for ( ; it ! = items . end ( ) ; ) {
TQString path = * it ;
+ + it ;
processPath ( path , it ! = items . end ( ) ? * it : TQString ( ) ) ;
}
}
void LocateProtocol : : locateFinished ( )
{
// Add any pending items.
if ( ! m_pendingPath . isNull ( ) ) {
processPath ( m_pendingPath , " " ) ;
m_pendingPath = TQString ( ) ;
}
addPreviousLocateOutput ( ) ;
DEBUGSTR < < " LocateProtocol::locateFinished " < < endl ;
infoMessage ( i18n ( " Finished. " ) ) ;
finished ( ) ;
}
TQString LocateProtocol : : partToPattern ( const TQString & part , bool forLocate )
{
DEBUGSTR < < " BEG part: " < < part < < endl ;
TQString pattern = part ;
// Unescape whitespace.
pattern . replace ( " \\ " , " " ) ;
// Unquote quoted pattern.
int n = pattern . length ( ) , index ;
if ( ( n > 1 ) & & ( pattern [ 0 ] = = ' " ' ) & & ( pattern [ n - 1 ] = = ' " ' ) ) {
pattern = pattern . mid ( 1 , n - 2 ) ;
}
// We can't do regular expression matching on the locate pattern,
// the regular expression format used by locate is incompatible
// with the format used by TQRegExp.
if ( ! m_useRegExp | | forLocate ) {
// Escape regexp characters for filtering pattern, and for locate,
// but the latter only if it is actually necessary to pass a regexp to locate.
// (ie. the pattern contains wildcards.)
if ( ! forLocate | | hasWildcards ( pattern ) ) {
pattern = convertWildcardsToRegExp ( pattern ) ;
} else {
// Special case for locate pattern without wildcards:
// Unescape all escaped wildcards.
pattern . replace ( " \\ * " , " * " ) ;
pattern . replace ( " \\ + " , " + " ) ;
pattern . replace ( " \\ ? " , " ? " ) ;
pattern . replace ( " \\ [ " , " [ " ) ;
pattern . replace ( " \\ ] " , " ] " ) ;
}
}
// Special treatment for the pattern used for locate:
if ( forLocate ) {
// Replace ~/ and ~user/ at the beginning (as the shell does)
if ( ( pattern . length ( ) > 0 ) & & ( pattern [ 0 ] = = ' ~ ' ) ) {
index = pattern . find ( ' / ' ) ;
if ( index > = 0 ) {
TQString name = pattern . mid ( 1 , index - 1 ) ;
TQString homeDir ;
if ( name . isEmpty ( ) ) {
homeDir = KUser ( KUser : : UseRealUserID ) . homeDir ( ) ;
} else {
homeDir = KUser ( name ) . homeDir ( ) ;
}
if ( ! homeDir . isEmpty ( ) ) {
pattern . replace ( 0 , index , homeDir ) ;
}
}
}
pattern . replace ( " \\ ~ " , " ~ " ) ;
}
DEBUGSTR < < " END part: " < < pattern < < endl ;
return pattern ;
}
bool LocateProtocol : : isMatching ( const TQString & path )
{
// The file has to belong to our directory.
if ( ! path . startsWith ( m_locateDirectory ) ) {
return false ;
}
// And it has to match at least one regular expression in the whitelist.
if ( ! m_config . m_whiteList . isMatchingOne ( path ) ) {
return false ;
}
// And it may not match any regular expression in the blacklist.
if ( m_config . m_blackList . isMatchingOne ( path ) ) {
return false ;
}
// And it has to match against all regular expressions specified in the URL.
if ( ! m_regExps . isMatchingAll ( path ) ) {
return false ;
}
// And it must not solely match m_locateDirectory.
return m_locateRegExp . isMatching ( path . mid ( m_locateDirectory . length ( ) ) ) ;
}
TQString LocateProtocol : : pathToDisplay ( const TQString & path , int subItems )
{
// Split off the directory part. If it is not just the minimal '/'.
TQString display = path ;
if ( ( m_locateDirectory ! = " / " ) & & display . startsWith ( m_locateDirectory ) ) {
display = display . mid ( m_locateDirectory . length ( ) ) ;
}
if ( subItems > 0 ) {
// Can't use m_collapsedDisplay.arg(subItems).arg(display); here
// because user might forget to type %1 or %2, or type it twice.
// In both cases the result of arg() is undefined.
TQString output = m_config . m_collapsedDisplay , temp ;
temp . setNum ( subItems ) ;
output . replace ( " %1 " , temp ) ;
output . replace ( " %2 " , display ) ;
display = output ;
}
return display ;
}
TQString LocateProtocol : : makeLocaterUrl ( const TQString & directory )
{
KURL url ( m_url ) ;
url . removeQueryItem ( queryDirectory ) ;
url . addQueryItem ( queryDirectory , directory ) ;
return url . url ( ) ;
}
/////////////////////////////////////////////////////////////////////
// CONFIG
bool LocateProtocol : : isConfigRequest ( )
{
return m_url . path ( ) = = " config " ;
}
void LocateProtocol : : configRequest ( )
{
// This flag is used to show either a "succesful" or an "unchanged" message
// in configFinished().
m_configUpdated = false ;
// Don't show it twice. During my tests I never got there however.
if ( TDEConfigDialog : : showDialog ( " settings " ) )
return ;
TDEConfigDialog * dialog = new TDEConfigDialog ( 0 , " settings " , KLocateConfig : : self ( ) ,
KDialogBase : : IconList ,
KDialogBase : : Default | KDialogBase : : Ok | KDialogBase : : Cancel | KDialogBase : : Help ,
KDialogBase : : Ok , true ) ;
dialog - > setCaption ( i18n ( " Configure - kio-locate " ) ) ;
dialog - > setIcon ( SmallIcon ( " find " ) ) ;
dialog - > addPage ( new KLocateConfigWidget ( ) , i18n ( " General " ) , " package_settings " ) ;
dialog - > addPage ( new KLocateConfigFilterWidget ( ) , i18n ( " Filters " ) , " filter " ) ;
dialog - > addPage ( new KLocateConfigLocateWidget ( ) , i18n ( " Locate " ) , " find " ) ;
// React on user's actions.
connect ( dialog , TQT_SIGNAL ( settingsChanged ( ) ) , this , TQT_SLOT ( updateConfig ( ) ) ) ;
connect ( dialog , TQT_SIGNAL ( finished ( ) ) , this , TQT_SLOT ( configFinished ( ) ) ) ;
dialog - > show ( ) ;
tqApp - > enter_loop ( ) ;
delete dialog ;
}
void LocateProtocol : : configFinished ( )
{
DEBUGSTR < < " LocateProtocol::configFinished " < < endl ;
tqApp - > exit_loop ( ) ;
TQString html ;
if ( m_configUpdated ) {
html = i18n ( " Configuration succesfully updated. " ) ;
} else {
html = i18n ( " Configuration unchanged. " ) ;
}
outputHtml ( " <h1> " + html + " </h1> " ) ;
}
void LocateProtocol : : updateConfig ( )
{
// It's not needed to update the config if it's still up to date.
DEBUGSTR < < " LocateProtocol::updateConfig " < < endl ;
KLocateConfig : : self ( ) - > readConfig ( ) ;
m_config . m_caseSensitivity = ( LocateCaseSensitivity ) KLocateConfig : : caseSensitivity ( ) ;
m_config . m_collapseDirectoryThreshold = KLocateConfig : : collapseDirectoryThreshold ( ) ;
m_config . m_collapsedDisplay = KLocateConfig : : collapsedDisplay ( ) ;
m_config . m_collapsedIcon = ( LocateCollapsedIcon ) KLocateConfig : : collapsedIcon ( ) ;
m_config . m_whiteList = KLocateConfig : : whiteList ( ) ;
m_config . m_blackList = KLocateConfig : : blackList ( ) ;
m_locater . setupLocate ( KLocateConfig : : locateBinary ( ) ,
KLocateConfig : : locateAdditionalArguments ( ) ) ;
m_configUpdated = true ;
}
/////////////////////////////////////////////////////////////////////
// HELP
bool LocateProtocol : : isHelpRequest ( )
{
return m_url . path ( ) = = " help " ;
}
void LocateProtocol : : helpRequest ( )
{
// Redirect the user to our help documents.
redirection ( " help:/tdeio-locate/ " ) ;
finished ( ) ;
}
/////////////////////////////////////////////////////////////////////
// SEARCH STRUCTURES
LocateDirectory : : LocateDirectory ( LocateDirectory * parent , const TQString & path )
{
m_parent = parent ;
m_path = path ;
m_childs . setAutoDelete ( true ) ;
m_itemsCount = 0 ;
}
LocateDirectory * LocateDirectory : : addPath ( const TQString & path )
{
if ( path . startsWith ( m_path ) ) {
TQString relPath = path . mid ( m_path . length ( ) ) ;
int p = relPath . findRev ( ' / ' ) ;
if ( p > = 0 ) {
LocateDirectory * child = getSubDirectory ( relPath . left ( p ) ) ;
child - > addItem ( relPath . mid ( p + 1 ) ) ;
return child ;
}
addItem ( relPath ) ;
return this ;
}
if ( m_parent ! = NULL ) {
return m_parent - > addPath ( path ) ;
}
// This should not happen
return this ;
}
LocateDirectory * LocateDirectory : : getSubDirectory ( const TQString & relPath )
{
TQString base = relPath ;
int p = relPath . find ( ' / ' ) ;
if ( p > = 0 ) {
base = relPath . left ( p ) ;
}
LocateDirectory * child = m_childs . find ( base ) ;
if ( child = = NULL ) {
child = new LocateDirectory ( this , addTrailingSlash ( m_path + base ) ) ;
m_childs . insert ( base , child ) ;
}
if ( p > = 0 ) {
return child - > getSubDirectory ( relPath . mid ( p + 1 ) ) ;
}
return child ;
}
void LocateDirectory : : addItem ( const TQString & path )
{
m_items + = LocateItem ( m_path + path , 0 ) ;
m_itemsCount + + ;
}
int LocateDirectory : : countMatchingItems ( const LocateProtocol * protocol , int skip )
{
int count = 0 ;
LocateItems : : ConstIterator item = m_items . begin ( ) ;
for ( ; item ! = m_items . end ( ) ; + + item ) {
if ( ( * item ) . m_subItems ) {
count + = ( * item ) . m_subItems ;
} else if ( protocol - > getRegExp ( ) . isMatching ( ( * item ) . m_path . mid ( skip ) ) ) {
+ + count ;
}
}
return count ;
}
void LocateDirectory : : prepareListing ( const LocateProtocol * protocol , int skip )
{
int n = m_path . length ( ) , newSkip = n ;
if ( skip > newSkip ) newSkip = skip ;
// Recursively walk through all childs.
LocateDirectoriesIterator child ( m_childs ) ;
for ( ; child . current ( ) ; + + child ) {
child . current ( ) - > prepareListing ( protocol , newSkip ) ;
}
// Set m_fullCount to the total number of childs matching the pattern.
m_fullCount = countMatchingItems ( protocol , newSkip ) ;
// Collapse if directory part matches.
LocateDirectory * parent = m_parent ;
if ( parent = = NULL ) {
parent = this ;
}
if ( n > skip & & protocol - > getRegExp ( ) . isMatching ( m_path . mid ( skip ) ) ) {
// Directory part matches.
m_childs . clear ( ) ;
m_items . clear ( ) ;
m_itemsCount = 0 ;
parent - > m_items + = LocateItem ( m_path , m_fullCount ) ;
+ + parent - > m_itemsCount ;
if ( m_fullCount ! = 0 ) {
parent - > m_items + = LocateItem ( m_path , 0 ) ;
+ + parent - > m_itemsCount ;
}
}
// Collapse if we got too many hits.
int maxHits = protocol - > getCollapseDirectoryThreshold ( ) ;
if ( n > skip & & maxHits ! = 0 & & m_itemsCount > maxHits ) {
if ( m_parent ! = NULL ) {
m_parent - > m_items + = LocateItem ( m_path , m_fullCount ) ;
+ + m_parent - > m_itemsCount ;
} else {
m_items . clear ( ) ;
m_items + = LocateItem ( m_path , m_fullCount ) ;
+ + m_itemsCount ;
}
} else {
// Propagate items to parent.
// (only root LocateDirectory runs listItems)
if ( m_parent ! = NULL ) {
m_parent - > m_items + = m_items ;
m_parent - > m_itemsCount + = m_itemsCount ;
}
}
}
void LocateDirectory : : listItems ( LocateProtocol * protocol )
{
LocateItems : : ConstIterator item = m_items . begin ( ) ;
for ( ; item ! = m_items . end ( ) ; + + item ) {
protocol - > addHit ( stripTrailingSlash ( ( * item ) . m_path ) , ( * item ) . m_subItems ) ;
}
}
void LocateDirectory : : debugTrace ( int level )
{
TQString ws ;
ws . fill ( ' ' , level ) ;
DEBUGSTR < < ws < < m_path < < endl ;
LocateItems : : ConstIterator item = m_items . begin ( ) ;
for ( ; item ! = m_items . end ( ) ; + + item ) {
DEBUGSTR < < ws < < " + " < < ( * item ) . m_path < < endl ;
}
LocateDirectoriesIterator child ( m_childs ) ;
for ( ; child . current ( ) ; + + child ) {
child . current ( ) - > debugTrace ( level + 2 ) ;
}
}
LocateItem : : LocateItem ( )
{
}
LocateItem : : LocateItem ( const TQString & path , int subItems )
{
m_path = path ;
m_subItems = subItems ;
}
/////////////////////////////////////////////////////////////////////
// INVOKATION
extern " C " { KDE_EXPORT int kdemain ( int argc , char * * argv ) ; }
extern " C "
{
int kdemain ( int argc , char * * argv )
{
// We use TDEApplication instead of TDEInstance here, because we use a
// config dialog and such gui stuff.
TDEApplication app ( argc , argv , " tdeio_locate " , false , true ) ;
DEBUGSTR < < " *** Starting tdeio_locate " < < endl ;
if ( argc ! = 4 ) {
DEBUGSTR < < " Usage: tdeio_locate protocol domain-socket1 domain-socket2 " < < endl ;
exit ( - 1 ) ;
}
LocateProtocol slave ( argv [ 2 ] , argv [ 3 ] ) ;
slave . dispatchLoop ( ) ;
DEBUGSTR < < " *** tdeio_locate Done " < < endl ;
return 0 ;
}
}
# include "tdeio_locate.moc"