summaryrefslogtreecommitdiffstats
path: root/kio/kio/kurlcompletion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kio/kio/kurlcompletion.cpp')
-rw-r--r--kio/kio/kurlcompletion.cpp1604
1 files changed, 0 insertions, 1604 deletions
diff --git a/kio/kio/kurlcompletion.cpp b/kio/kio/kurlcompletion.cpp
deleted file mode 100644
index 2dc4185cc..000000000
--- a/kio/kio/kurlcompletion.cpp
+++ /dev/null
@@ -1,1604 +0,0 @@
-/* -*- indent-tabs-mode: t; tab-width: 4; c-basic-offset:4 -*-
-
- This file is part of the KDE libraries
- Copyright (C) 2000 David Smith <dsmith@algonet.se>
- Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
-
- This class was inspired by a previous KURLCompletion by
- Henner Zeller <zeller@think.de>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include <config.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <limits.h>
-
-#include <tqstring.h>
-#include <tqstringlist.h>
-#include <tqvaluelist.h>
-#include <tqregexp.h>
-#include <tqtimer.h>
-#include <tqdir.h>
-#include <tqfile.h>
-#include <tqtextstream.h>
-#include <tqdeepcopy.h>
-#include <tqthread.h>
-
-#include <kapplication.h>
-#include <kdebug.h>
-#include <kcompletion.h>
-#include <kurl.h>
-#include <kio/jobclasses.h>
-#include <kio/job.h>
-#include <kprotocolinfo.h>
-#include <kconfig.h>
-#include <kglobal.h>
-#include <klocale.h>
-#include <kde_file.h>
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <pwd.h>
-#include <time.h>
-#include <sys/param.h>
-
-#include "kurlcompletion.h"
-
-static bool expandTilde(TQString &);
-static bool expandEnv(TQString &);
-
-static TQString unescape(const TQString &text);
-
-// Permission mask for files that are executable by
-// user, group or other
-#define MODE_EXE (S_IXUSR | S_IXGRP | S_IXOTH)
-
-// Constants for types of completion
-enum ComplType {CTNone=0, CTEnv, CTUser, CTMan, CTExe, CTFile, CTUrl, CTInfo};
-
-class CompletionThread;
-
-/**
- * A custom event type that is used to return a list of completion
- * matches from an asyncrynous lookup.
- */
-
-class CompletionMatchEvent : public TQCustomEvent
-{
-public:
- CompletionMatchEvent( CompletionThread *thread ) :
- TQCustomEvent( uniqueType() ),
- m_completionThread( thread )
- {}
-
- CompletionThread *completionThread() const { return m_completionThread; }
- static int uniqueType() { return User + 61080; }
-
-private:
- CompletionThread *m_completionThread;
-};
-
-class CompletionThread : public TQThread
-{
-protected:
- CompletionThread( KURLCompletion *receiver ) :
- TQThread(),
- m_receiver( receiver ),
- m_terminationRequested( false )
- {}
-
-public:
- void requestTermination() { m_terminationRequested = true; }
- TQDeepCopy<TQStringList> matches() const { return m_matches; }
-
-protected:
- void addMatch( const TQString &match ) { m_matches.append( match ); }
- bool terminationRequested() const { return m_terminationRequested; }
- void done()
- {
- if ( !m_terminationRequested )
- kapp->postEvent( m_receiver, new CompletionMatchEvent( this ) );
- else
- delete this;
- }
-
-private:
- KURLCompletion *m_receiver;
- TQStringList m_matches;
- bool m_terminationRequested;
-};
-
-/**
- * A simple thread that fetches a list of tilde-completions and returns this
- * to the caller via a CompletionMatchEvent.
- */
-
-class UserListThread : public CompletionThread
-{
-public:
- UserListThread( KURLCompletion *receiver ) :
- CompletionThread( receiver )
- {}
-
-protected:
- virtual void run()
- {
- static const TQChar tilde = '~';
-
- struct passwd *pw;
- while ( ( pw = ::getpwent() ) && !terminationRequested() )
- addMatch( tilde + TQString::fromLocal8Bit( pw->pw_name ) );
-
- ::endpwent();
-
- addMatch( tilde );
-
- done();
- }
-};
-
-class DirectoryListThread : public CompletionThread
-{
-public:
- DirectoryListThread( KURLCompletion *receiver,
- const TQStringList &dirList,
- const TQString &filter,
- bool onlyExe,
- bool onlyDir,
- bool noHidden,
- bool appendSlashToDir ) :
- CompletionThread( receiver ),
- m_dirList( TQDeepCopy<TQStringList>( dirList ) ),
- m_filter( TQDeepCopy<TQString>( filter ) ),
- m_onlyExe( onlyExe ),
- m_onlyDir( onlyDir ),
- m_noHidden( noHidden ),
- m_appendSlashToDir( appendSlashToDir )
- {}
-
- virtual void run();
-
-private:
- TQStringList m_dirList;
- TQString m_filter;
- bool m_onlyExe;
- bool m_onlyDir;
- bool m_noHidden;
- bool m_appendSlashToDir;
-};
-
-void DirectoryListThread::run()
-{
- // Thread safety notes:
- //
- // There very possibly may be thread safety issues here, but I've done a check
- // of all of the things that would seem to be problematic. Here are a few
- // things that I have checked to be safe here (some used indirectly):
- //
- // TQDir::currentDirPath(), TQDir::setCurrent(), TQFile::decodeName(), TQFile::encodeName()
- // TQString::fromLocal8Bit(), TQString::local8Bit(), TQTextCodec::codecForLocale()
- //
- // Also see (for POSIX functions):
- // http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html
-
- DIR *dir = 0;
-
- for ( TQStringList::ConstIterator it = m_dirList.begin();
- it != m_dirList.end() && !terminationRequested();
- ++it )
- {
- // Open the next directory
-
- if ( !dir ) {
- dir = ::opendir( TQFile::encodeName( *it ) );
- if ( ! dir ) {
- kdDebug() << "Failed to open dir: " << *it << endl;
- done();
- return;
- }
- }
-
- // A trick from KIO that helps performance by a little bit:
- // chdir to the directroy so we won't have to deal with full paths
- // with stat()
-
- TQString path = TQDir::currentDirPath();
- TQDir::setCurrent( *it );
-
- // Loop through all directory entries
- // Solaris and IRIX dirent structures do not allocate space for d_name. On
- // systems that do (HP-UX, Linux, Tru64 UNIX), we overallocate space but
- // that's ok.
-#ifndef HAVE_READDIR_R
- struct dirent *dirEntry = 0;
- while ( !terminationRequested() &&
- (dirEntry = ::readdir( dir)))
-#else
-#if !defined(MAXPATHLEN) && defined(__GNU__)
-#define MAXPATHLEN UCHAR_MAX
-#endif
- struct dirent *dirPosition = (struct dirent *) malloc( sizeof( struct dirent ) + MAXPATHLEN + 1 );
- struct dirent *dirEntry = 0;
- while ( !terminationRequested() &&
- ::readdir_r( dir, dirPosition, &dirEntry ) == 0 && dirEntry )
-#endif
-
- {
- // Skip hidden files if m_noHidden is true
-
- if ( dirEntry->d_name[0] == '.' && m_noHidden )
- continue;
-
- // Skip "."
-
- if ( dirEntry->d_name[0] == '.' && dirEntry->d_name[1] == '\0' )
- continue;
-
- // Skip ".."
-
- if ( dirEntry->d_name[0] == '.' && dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0' )
- continue;
-
- TQString file = TQFile::decodeName( dirEntry->d_name );
-
- if ( m_filter.isEmpty() || file.startsWith( m_filter ) ) {
-
- if ( m_onlyExe || m_onlyDir || m_appendSlashToDir ) {
- KDE_struct_stat sbuff;
-
- if ( KDE_stat( dirEntry->d_name, &sbuff ) == 0 ) {
-
- // Verify executable
-
- if ( m_onlyExe && ( sbuff.st_mode & MODE_EXE ) == 0 )
- continue;
-
- // Verify directory
-
- if ( m_onlyDir && !S_ISDIR( sbuff.st_mode ) )
- continue;
-
- // Add '/' to directories
-
- if ( m_appendSlashToDir && S_ISDIR( sbuff.st_mode ) )
- file.append( '/' );
-
- }
- else {
- kdDebug() << "Could not stat file " << file << endl;
- continue;
- }
- }
-
- addMatch( file );
- }
- }
-
- // chdir to the original directory
-
- TQDir::setCurrent( path );
-
- ::closedir( dir );
- dir = 0;
-#ifdef HAVE_READDIR_R
- free( dirPosition );
-#endif
- }
-
- done();
-}
-
-///////////////////////////////////////////////////////
-///////////////////////////////////////////////////////
-// MyURL - wrapper for KURL with some different functionality
-//
-
-class KURLCompletion::MyURL
-{
-public:
- MyURL(const TQString &url, const TQString &cwd);
- MyURL(const MyURL &url);
- ~MyURL();
-
- KURL *kurl() const { return m_kurl; }
-
- TQString protocol() const { return m_kurl->protocol(); }
- // The directory with a trailing '/'
- TQString dir() const { return m_kurl->directory(false, false); }
- TQString file() const { return m_kurl->fileName(false); }
-
- // The initial, unparsed, url, as a string.
- TQString url() const { return m_url; }
-
- // Is the initial string a URL, or just a path (whether absolute or relative)
- bool isURL() const { return m_isURL; }
-
- void filter( bool replace_user_dir, bool replace_env );
-
-private:
- void init(const TQString &url, const TQString &cwd);
-
- KURL *m_kurl;
- TQString m_url;
- bool m_isURL;
-};
-
-KURLCompletion::MyURL::MyURL(const TQString &url, const TQString &cwd)
-{
- init(url, cwd);
-}
-
-KURLCompletion::MyURL::MyURL(const MyURL &url)
-{
- m_kurl = new KURL( *(url.m_kurl) );
- m_url = url.m_url;
- m_isURL = url.m_isURL;
-}
-
-void KURLCompletion::MyURL::init(const TQString &url, const TQString &cwd)
-{
- // Save the original text
- m_url = url;
-
- // Non-const copy
- TQString url_copy = url;
-
- // Special shortcuts for "man:" and "info:"
- if ( url_copy[0] == '#' ) {
- if ( url_copy[1] == '#' )
- url_copy.replace( 0, 2, TQString("info:") );
- else
- url_copy.replace( 0, 1, TQString("man:") );
- }
-
- // Look for a protocol in 'url'
- TQRegExp protocol_regex = TQRegExp( "^[^/\\s\\\\]*:" );
-
- // Assume "file:" or whatever is given by 'cwd' if there is
- // no protocol. (KURL does this only for absoute paths)
- if ( protocol_regex.search( url_copy ) == 0 )
- {
- m_kurl = new KURL( url_copy );
- m_isURL = true;
- }
- else // relative path or ~ or $something
- {
- m_isURL = false;
- if ( cwd.isEmpty() )
- {
- m_kurl = new KURL();
- if ( !TQDir::isRelativePath(url_copy) || url_copy[0] == '$' || url_copy[0] == '~' )
- m_kurl->setPath( url_copy );
- else
- *m_kurl = url_copy;
- }
- else
- {
- KURL base = KURL::fromPathOrURL( cwd );
- base.adjustPath(+1);
-
- if ( !TQDir::isRelativePath(url_copy) || url_copy[0] == '~' || url_copy[0] == '$' )
- {
- m_kurl = new KURL();
- m_kurl->setPath( url_copy );
- }
- else // relative path
- {
- //m_kurl = new KURL( base, url_copy );
- m_kurl = new KURL( base );
- m_kurl->addPath( url_copy );
- }
- }
- }
-}
-
-KURLCompletion::MyURL::~MyURL()
-{
- delete m_kurl;
-}
-
-void KURLCompletion::MyURL::filter( bool replace_user_dir, bool replace_env )
-{
- TQString d = dir() + file();
- if ( replace_user_dir ) expandTilde( d );
- if ( replace_env ) expandEnv( d );
- m_kurl->setPath( d );
-}
-
-///////////////////////////////////////////////////////
-///////////////////////////////////////////////////////
-// KURLCompletionPrivate
-//
-class KURLCompletionPrivate
-{
-public:
- KURLCompletionPrivate() : url_auto_completion(true),
- userListThread(0),
- dirListThread(0) {}
- ~KURLCompletionPrivate();
-
- TQValueList<KURL*> list_urls;
-
- bool onlyLocalProto;
-
- // urlCompletion() in Auto/Popup mode?
- bool url_auto_completion;
-
- // Append '/' to directories in Popup mode?
- // Doing that stat's all files and is slower
- bool popup_append_slash;
-
- // Keep track of currently listed files to avoid reading them again
- TQString last_path_listed;
- TQString last_file_listed;
- TQString last_prepend;
- int last_compl_type;
- int last_no_hidden;
-
- TQString cwd; // "current directory" = base dir for completion
-
- KURLCompletion::Mode mode; // ExeCompletion, FileCompletion, DirCompletion
- bool replace_env;
- bool replace_home;
- bool complete_url; // if true completing a URL (i.e. 'prepend' is a URL), otherwise a path
-
- TDEIO::ListJob *list_job; // kio job to list directories
-
- TQString prepend; // text to prepend to listed items
- TQString compl_text; // text to pass on to KCompletion
-
- // Filters for files read with kio
- bool list_urls_only_exe; // true = only list executables
- bool list_urls_no_hidden;
- TQString list_urls_filter; // filter for listed files
-
- CompletionThread *userListThread;
- CompletionThread *dirListThread;
-};
-
-KURLCompletionPrivate::~KURLCompletionPrivate()
-{
- if ( userListThread )
- userListThread->requestTermination();
- if ( dirListThread )
- dirListThread->requestTermination();
-}
-
-///////////////////////////////////////////////////////
-///////////////////////////////////////////////////////
-// KURLCompletion
-//
-
-KURLCompletion::KURLCompletion() : KCompletion()
-{
- init();
-}
-
-
-KURLCompletion::KURLCompletion( Mode mode ) : KCompletion()
-{
- init();
- setMode ( mode );
-}
-
-KURLCompletion::~KURLCompletion()
-{
- stop();
- delete d;
-}
-
-
-void KURLCompletion::init()
-{
- d = new KURLCompletionPrivate;
-
- d->cwd = TQDir::homeDirPath();
-
- d->replace_home = true;
- d->replace_env = true;
- d->last_no_hidden = false;
- d->last_compl_type = 0;
- d->list_job = 0L;
- d->mode = KURLCompletion::FileCompletion;
-
- // Read settings
- TDEConfig *c = TDEGlobal::config();
- TDEConfigGroupSaver cgs( c, "URLCompletion" );
-
- d->url_auto_completion = c->readBoolEntry("alwaysAutoComplete", true);
- d->popup_append_slash = c->readBoolEntry("popupAppendSlash", true);
- d->onlyLocalProto = c->readBoolEntry("LocalProtocolsOnly", false);
-}
-
-void KURLCompletion::setDir(const TQString &dir)
-{
- d->cwd = dir;
-}
-
-TQString KURLCompletion::dir() const
-{
- return d->cwd;
-}
-
-KURLCompletion::Mode KURLCompletion::mode() const
-{
- return d->mode;
-}
-
-void KURLCompletion::setMode( Mode mode )
-{
- d->mode = mode;
-}
-
-bool KURLCompletion::replaceEnv() const
-{
- return d->replace_env;
-}
-
-void KURLCompletion::setReplaceEnv( bool replace )
-{
- d->replace_env = replace;
-}
-
-bool KURLCompletion::replaceHome() const
-{
- return d->replace_home;
-}
-
-void KURLCompletion::setReplaceHome( bool replace )
-{
- d->replace_home = replace;
-}
-
-/*
- * makeCompletion()
- *
- * Entry point for file name completion
- */
-TQString KURLCompletion::makeCompletion(const TQString &text)
-{
- //kdDebug() << "KURLCompletion::makeCompletion: " << text << " d->cwd=" << d->cwd << endl;
-
- MyURL url(text, d->cwd);
-
- d->compl_text = text;
-
- // Set d->prepend to the original URL, with the filename [and ref/query] stripped.
- // This is what gets prepended to the directory-listing matches.
- int toRemove = url.file().length() - url.kurl()->query().length();
- if ( url.kurl()->hasRef() )
- toRemove += url.kurl()->ref().length() + 1;
- d->prepend = text.left( text.length() - toRemove );
- d->complete_url = url.isURL();
-
- TQString match;
-
- // Environment variables
- //
- if ( d->replace_env && envCompletion( url, &match ) )
- return match;
-
- // User directories
- //
- if ( d->replace_home && userCompletion( url, &match ) )
- return match;
-
- // Replace user directories and variables
- url.filter( d->replace_home, d->replace_env );
-
- //kdDebug() << "Filtered: proto=" << url.protocol()
- // << ", dir=" << url.dir()
- // << ", file=" << url.file()
- // << ", kurl url=" << *url.kurl() << endl;
-
- if ( d->mode == ExeCompletion ) {
- // Executables
- //
- if ( exeCompletion( url, &match ) )
- return match;
-
- // KRun can run "man:" and "info:" etc. so why not treat them
- // as executables...
-
- if ( urlCompletion( url, &match ) )
- return match;
- }
- else if ( d->mode == SystemExeCompletion ) {
- // Executables
- //
- if ( systemexeCompletion( url, &match ) )
- return match;
-
- // KRun can run "man:" and "info:" etc. so why not treat them
- // as executables...
-
- if ( urlCompletion( url, &match ) )
- return match;
- }
- else {
- // Local files, directories
- //
- if ( fileCompletion( url, &match ) )
- return match;
-
- // All other...
- //
- if ( urlCompletion( url, &match ) )
- return match;
- }
-
- setListedURL( CTNone );
- stop();
-
- return TQString::null;
-}
-
-/*
- * finished
- *
- * Go on and call KCompletion.
- * Called when all matches have been added
- */
-TQString KURLCompletion::finished()
-{
- if ( d->last_compl_type == CTInfo )
- return KCompletion::makeCompletion( d->compl_text.lower() );
- else
- return KCompletion::makeCompletion( d->compl_text );
-}
-
-/*
- * isRunning
- *
- * Return true if either a KIO job or the DirLister
- * is running
- */
-bool KURLCompletion::isRunning() const
-{
- return d->list_job || (d->dirListThread && !d->dirListThread->finished());
-}
-
-/*
- * stop
- *
- * Stop and delete a running KIO job or the DirLister
- */
-void KURLCompletion::stop()
-{
- if ( d->list_job ) {
- d->list_job->kill();
- d->list_job = 0L;
- }
-
- if ( !d->list_urls.isEmpty() ) {
- TQValueList<KURL*>::Iterator it = d->list_urls.begin();
- for ( ; it != d->list_urls.end(); it++ )
- delete (*it);
- d->list_urls.clear();
- }
-
- if ( d->dirListThread ) {
- d->dirListThread->requestTermination();
- d->dirListThread = 0;
- }
-}
-
-/*
- * Keep track of the last listed directory
- */
-void KURLCompletion::setListedURL( int complType,
- const TQString& dir,
- const TQString& filter,
- bool no_hidden )
-{
- d->last_compl_type = complType;
- d->last_path_listed = dir;
- d->last_file_listed = filter;
- d->last_no_hidden = (int)no_hidden;
- d->last_prepend = d->prepend;
-}
-
-bool KURLCompletion::isListedURL( int complType,
- const TQString& dir,
- const TQString& filter,
- bool no_hidden )
-{
- return d->last_compl_type == complType
- && ( d->last_path_listed == dir
- || (dir.isEmpty() && d->last_path_listed.isEmpty()) )
- && ( filter.startsWith(d->last_file_listed)
- || (filter.isEmpty() && d->last_file_listed.isEmpty()) )
- && d->last_no_hidden == (int)no_hidden
- && d->last_prepend == d->prepend; // e.g. relative path vs absolute
-}
-
-/*
- * isAutoCompletion
- *
- * Returns true if completion mode is Auto or Popup
- */
-bool KURLCompletion::isAutoCompletion()
-{
- return completionMode() == TDEGlobalSettings::CompletionAuto
- || completionMode() == TDEGlobalSettings::CompletionPopup
- || completionMode() == TDEGlobalSettings::CompletionMan
- || completionMode() == TDEGlobalSettings::CompletionPopupAuto;
-}
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// User directories
-//
-
-bool KURLCompletion::userCompletion(const MyURL &url, TQString *match)
-{
- if ( url.protocol() != "file"
- || !url.dir().isEmpty()
- || url.file().at(0) != '~' )
- return false;
-
- if ( !isListedURL( CTUser ) ) {
- stop();
- clear();
-
- if ( !d->userListThread ) {
- d->userListThread = new UserListThread( this );
- d->userListThread->start();
-
- // If the thread finishes quickly make sure that the results
- // are added to the first matching case.
-
- d->userListThread->wait( 200 );
- TQStringList l = d->userListThread->matches();
- addMatches( l );
- }
- }
- *match = finished();
- return true;
-}
-
-/////////////////////////////////////////////////////
-/////////////////////////////////////////////////////
-// Environment variables
-//
-
-extern char **environ; // Array of environment variables
-
-bool KURLCompletion::envCompletion(const MyURL &url, TQString *match)
-{
- if ( url.file().at(0) != '$' )
- return false;
-
- if ( !isListedURL( CTEnv ) ) {
- stop();
- clear();
-
- char **env = environ;
-
- TQString dollar = TQString("$");
-
- TQStringList l;
-
- while ( *env ) {
- TQString s = TQString::fromLocal8Bit( *env );
-
- int pos = s.find('=');
-
- if ( pos == -1 )
- pos = s.length();
-
- if ( pos > 0 )
- l.append( dollar + s.left(pos) );
-
- env++;
- }
-
- addMatches( l );
- }
-
- setListedURL( CTEnv );
-
- *match = finished();
- return true;
-}
-
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// Executables
-//
-
-bool KURLCompletion::exeCompletion(const MyURL &url, TQString *match)
-{
- if ( url.protocol() != "file" )
- return false;
-
- TQString dir = url.dir();
-
- dir = unescape( dir ); // remove escapes
-
- // Find directories to search for completions, either
- //
- // 1. complete path given in url
- // 2. current directory (d->cwd)
- // 3. $PATH
- // 4. no directory at all
-
- TQStringList dirList;
-
- if ( !TQDir::isRelativePath(dir) ) {
- // complete path in url
- dirList.append( dir );
- }
- else if ( !dir.isEmpty() && !d->cwd.isEmpty() ) {
- // current directory
- dirList.append( d->cwd + '/' + dir );
- }
- else if ( !url.file().isEmpty() ) {
- // $PATH
- dirList = TQStringList::split(KPATH_SEPARATOR,
- TQString::fromLocal8Bit(::getenv("PATH")));
-
- TQStringList::Iterator it = dirList.begin();
-
- for ( ; it != dirList.end(); it++ )
- (*it).append('/');
- }
-
- // No hidden files unless the user types "."
- bool no_hidden_files = url.file().at(0) != '.';
-
- // List files if needed
- //
- if ( !isListedURL( CTExe, dir, url.file(), no_hidden_files ) )
- {
- stop();
- clear();
-
- setListedURL( CTExe, dir, url.file(), no_hidden_files );
-
- *match = listDirectories( dirList, url.file(), true, false, no_hidden_files );
- }
- else if ( !isRunning() ) {
- *match = finished();
- }
- else {
- if ( d->dirListThread )
- setListedURL( CTExe, dir, url.file(), no_hidden_files );
- *match = TQString::null;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// System Executables
-//
-
-bool KURLCompletion::systemexeCompletion(const MyURL &url, TQString *match)
-{
- if ( url.protocol() != "file" )
- return false;
-
- TQString dir = url.dir();
-
- dir = unescape( dir ); // remove escapes
-
- // Find directories to search for completions, either
- //
- // 1. complete path given in url
- // 2. current directory (d->cwd)
- // 3. $PATH
- // 4. no directory at all
-
- TQStringList dirList;
-
- if ( !url.file().isEmpty() ) {
- // $PATH
- dirList = TQStringList::split(KPATH_SEPARATOR,
- TQString::fromLocal8Bit(::getenv("PATH")));
-
- TQStringList::Iterator it = dirList.begin();
-
- for ( ; it != dirList.end(); it++ )
- (*it).append('/');
- }
-
- // No hidden files unless the user types "."
- bool no_hidden_files = url.file().at(0) != '.';
-
- // List files if needed
- //
- if ( !isListedURL( CTExe, dir, url.file(), no_hidden_files ) )
- {
- stop();
- clear();
-
- setListedURL( CTExe, dir, url.file(), no_hidden_files );
-
- *match = listDirectories( dirList, url.file(), true, false, no_hidden_files );
- }
- else if ( !isRunning() ) {
- *match = finished();
- }
- else {
- if ( d->dirListThread )
- setListedURL( CTExe, dir, url.file(), no_hidden_files );
- *match = TQString::null;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// Local files
-//
-
-bool KURLCompletion::fileCompletion(const MyURL &url, TQString *match)
-{
- if ( url.protocol() != "file" )
- return false;
-
- TQString dir = url.dir();
-
- if (url.url()[0] == '.')
- {
- if (url.url().length() == 1)
- {
- *match =
- ( completionMode() == TDEGlobalSettings::CompletionMan )? "." : "..";
- return true;
- }
- if (url.url().length() == 2 && url.url()[1]=='.')
- {
- *match="..";
- return true;
- }
- }
-
- //kdDebug() << "fileCompletion " << url.url() << " dir=" << dir << endl;
-
- dir = unescape( dir ); // remove escapes
-
- // Find directories to search for completions, either
- //
- // 1. complete path given in url
- // 2. current directory (d->cwd)
- // 3. no directory at all
-
- TQStringList dirList;
-
- if ( !TQDir::isRelativePath(dir) ) {
- // complete path in url
- dirList.append( dir );
- }
- else if ( !d->cwd.isEmpty() ) {
- // current directory
- dirList.append( d->cwd + '/' + dir );
- }
-
- // No hidden files unless the user types "."
- bool no_hidden_files = ( url.file().at(0) != '.' );
-
- // List files if needed
- //
- if ( !isListedURL( CTFile, dir, "", no_hidden_files ) )
- {
- stop();
- clear();
-
- setListedURL( CTFile, dir, "", no_hidden_files );
-
- // Append '/' to directories in Popup mode?
- bool append_slash = ( d->popup_append_slash
- && (completionMode() == TDEGlobalSettings::CompletionPopup ||
- completionMode() == TDEGlobalSettings::CompletionPopupAuto ) );
-
- bool only_dir = ( d->mode == DirCompletion );
-
- *match = listDirectories( dirList, "", false, only_dir, no_hidden_files,
- append_slash );
- }
- else if ( !isRunning() ) {
- *match = finished();
- }
- else {
- *match = TQString::null;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// URLs not handled elsewhere...
-//
-
-bool KURLCompletion::urlCompletion(const MyURL &url, TQString *match)
-{
- //kdDebug() << "urlCompletion: url = " << *url.kurl() << endl;
- if (d->onlyLocalProto && KProtocolInfo::protocolClass(url.protocol()) != ":local")
- return false;
-
- // Use d->cwd as base url in case url is not absolute
- KURL url_cwd = KURL::fromPathOrURL( d->cwd );
-
- // Create an URL with the directory to be listed
- KURL url_dir( url_cwd, url.kurl()->url() );
-
- // Don't try url completion if
- // 1. malformed url
- // 2. protocol that doesn't have listDir()
- // 3. there is no directory (e.g. "ftp://ftp.kd" shouldn't do anything)
- // 4. auto or popup completion mode depending on settings
-
- bool man_or_info = ( url_dir.protocol() == TQString("man")
- || url_dir.protocol() == TQString("info") );
-
- if ( !url_dir.isValid()
- || !KProtocolInfo::supportsListing( url_dir )
- || ( !man_or_info
- && ( url_dir.directory(false,false).isEmpty()
- || ( isAutoCompletion()
- && !d->url_auto_completion ) ) ) ) {
- return false;
- }
-
- url_dir.setFileName(""); // not really nesseccary, but clear the filename anyway...
-
- // Remove escapes
- TQString dir = url_dir.directory( false, false );
-
- dir = unescape( dir );
-
- url_dir.setPath( dir );
-
- // List files if needed
- //
- if ( !isListedURL( CTUrl, url_dir.prettyURL(), url.file() ) )
- {
- stop();
- clear();
-
- setListedURL( CTUrl, url_dir.prettyURL(), "" );
-
- TQValueList<KURL*> url_list;
- url_list.append( new KURL( url_dir ) );
-
- listURLs( url_list, "", false );
-
- *match = TQString::null;
- }
- else if ( !isRunning() ) {
- *match = finished();
- }
- else {
- *match = TQString::null;
- }
-
- return true;
-}
-
-//////////////////////////////////////////////////
-//////////////////////////////////////////////////
-// Directory and URL listing
-//
-
-/*
- * addMatches
- *
- * Called to add matches to KCompletion
- */
-void KURLCompletion::addMatches( const TQStringList &matches )
-{
- TQStringList::ConstIterator it = matches.begin();
- TQStringList::ConstIterator end = matches.end();
-
- if ( d->complete_url )
- for ( ; it != end; it++ )
- addItem( d->prepend + KURL::encode_string(*it));
- else
- for ( ; it != end; it++ )
- addItem( d->prepend + (*it));
-}
-
-/*
- * listDirectories
- *
- * List files starting with 'filter' in the given directories,
- * either using DirLister or listURLs()
- *
- * In either case, addMatches() is called with the listed
- * files, and eventually finished() when the listing is done
- *
- * Returns the match if available, or TQString::null if
- * DirLister timed out or using kio
- */
-TQString KURLCompletion::listDirectories(
- const TQStringList &dirList,
- const TQString &filter,
- bool only_exe,
- bool only_dir,
- bool no_hidden,
- bool append_slash_to_dir)
-{
- assert( !isRunning() );
-
- if ( !::getenv("KURLCOMPLETION_LOCAL_KIO") ) {
-
- //kdDebug() << "Listing (listDirectories): " << dirList << " filter=" << filter << " without KIO" << endl;
-
- // Don't use KIO
-
- if ( d->dirListThread )
- d->dirListThread->requestTermination();
-
- TQStringList dirs;
-
- for ( TQStringList::ConstIterator it = dirList.begin();
- it != dirList.end();
- ++it )
- {
- KURL url;
- url.setPath(*it);
- if ( kapp->authorizeURLAction( "list", KURL(), url ) )
- dirs.append( *it );
- }
-
- d->dirListThread = new DirectoryListThread( this, dirs, filter, only_exe, only_dir,
- no_hidden, append_slash_to_dir );
- d->dirListThread->start();
- d->dirListThread->wait( 200 );
- addMatches( d->dirListThread->matches() );
-
- return finished();
- }
- else {
-
- // Use KIO
- //kdDebug() << "Listing (listDirectories): " << dirList << " with KIO" << endl;
-
- TQValueList<KURL*> url_list;
-
- TQStringList::ConstIterator it = dirList.begin();
-
- for ( ; it != dirList.end(); it++ )
- url_list.append( new KURL(*it) );
-
- listURLs( url_list, filter, only_exe, no_hidden );
- // Will call addMatches() and finished()
-
- return TQString::null;
- }
-}
-
-/*
- * listURLs
- *
- * Use KIO to list the given urls
- *
- * addMatches() is called with the listed files
- * finished() is called when the listing is done
- */
-void KURLCompletion::listURLs(
- const TQValueList<KURL *> &urls,
- const TQString &filter,
- bool only_exe,
- bool no_hidden )
-{
- assert( d->list_urls.isEmpty() );
- assert( d->list_job == 0L );
-
- d->list_urls = urls;
- d->list_urls_filter = filter;
- d->list_urls_only_exe = only_exe;
- d->list_urls_no_hidden = no_hidden;
-
-// kdDebug() << "Listing URLs: " << urls[0]->prettyURL() << ",..." << endl;
-
- // Start it off by calling slotIOFinished
- //
- // This will start a new list job as long as there
- // are urls in d->list_urls
- //
- slotIOFinished(0L);
-}
-
-/*
- * slotEntries
- *
- * Receive files listed by KIO and call addMatches()
- */
-void KURLCompletion::slotEntries(TDEIO::Job*, const TDEIO::UDSEntryList& entries)
-{
- TQStringList matches;
-
- TDEIO::UDSEntryListConstIterator it = entries.begin();
- TDEIO::UDSEntryListConstIterator end = entries.end();
-
- TQString filter = d->list_urls_filter;
-
- int filter_len = filter.length();
-
- // Iterate over all files
- //
- for (; it != end; ++it) {
- TQString name;
- TQString url;
- bool is_exe = false;
- bool is_dir = false;
-
- TDEIO::UDSEntry e = *it;
- TDEIO::UDSEntry::ConstIterator it_2 = e.begin();
-
- for( ; it_2 != e.end(); it_2++ ) {
- switch ( (*it_2).m_uds ) {
- case TDEIO::UDS_NAME:
- name = (*it_2).m_str;
- break;
- case TDEIO::UDS_ACCESS:
- is_exe = ((*it_2).m_long & MODE_EXE) != 0;
- break;
- case TDEIO::UDS_FILE_TYPE:
- is_dir = ((*it_2).m_long & S_IFDIR) != 0;
- break;
- case TDEIO::UDS_URL:
- url = (*it_2).m_str;
- break;
- }
- }
-
- if (!url.isEmpty()) {
- // kdDebug() << "KURLCompletion::slotEntries url: " << url << endl;
- name = KURL(url).fileName();
- }
-
- // kdDebug() << "KURLCompletion::slotEntries name: " << name << endl;
-
- if ( name[0] == '.' &&
- ( d->list_urls_no_hidden ||
- name.length() == 1 ||
- ( name.length() == 2 && name[1] == '.' ) ) )
- continue;
-
- if ( d->mode == DirCompletion && !is_dir )
- continue;
-
- if ( filter_len == 0 || name.left(filter_len) == filter ) {
- if ( is_dir )
- name.append( '/' );
-
- if ( is_exe || !d->list_urls_only_exe )
- matches.append( name );
- }
- }
-
- addMatches( matches );
-}
-
-/*
- * slotIOFinished
- *
- * Called when a KIO job is finished.
- *
- * Start a new list job if there are still urls in
- * d->list_urls, otherwise call finished()
- */
-void KURLCompletion::slotIOFinished( TDEIO::Job * job )
-{
-// kdDebug() << "slotIOFinished() " << endl;
-
- assert( job == d->list_job );
-
- if ( d->list_urls.isEmpty() ) {
-
- d->list_job = 0L;
-
- finished(); // will call KCompletion::makeCompletion()
-
- }
- else {
-
- KURL *kurl = d->list_urls.first();
-
- d->list_urls.remove( kurl );
-
-// kdDebug() << "Start KIO: " << kurl->prettyURL() << endl;
-
- d->list_job = TDEIO::listDir( *kurl, false );
- d->list_job->addMetaData("no-auth-prompt", "true");
-
- assert( d->list_job );
-
- connect( d->list_job,
- TQT_SIGNAL(result(TDEIO::Job*)),
- TQT_SLOT(slotIOFinished(TDEIO::Job*)) );
-
- connect( d->list_job,
- TQT_SIGNAL( entries( TDEIO::Job*, const TDEIO::UDSEntryList&)),
- TQT_SLOT( slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList&)) );
-
- delete kurl;
- }
-}
-
-///////////////////////////////////////////////////
-///////////////////////////////////////////////////
-
-/*
- * postProcessMatch, postProcessMatches
- *
- * Called by KCompletion before emitting match() and matches()
- *
- * Append '/' to directories for file completion. This is
- * done here to avoid stat()'ing a lot of files
- */
-void KURLCompletion::postProcessMatch( TQString *match ) const
-{
-// kdDebug() << "KURLCompletion::postProcess: " << *match << endl;
-
- if ( !match->isEmpty() ) {
-
- // Add '/' to directories in file completion mode
- // unless it has already been done
- if ( d->last_compl_type == CTFile )
- adjustMatch( *match );
- }
-}
-
-void KURLCompletion::adjustMatch( TQString& match ) const
-{
- if ( match.at( match.length()-1 ) != '/' )
- {
- TQString copy;
-
- if ( match.startsWith( TQString("file:") ) )
- copy = KURL(match).path();
- else
- copy = match;
-
- expandTilde( copy );
- expandEnv( copy );
- if ( TQDir::isRelativePath(copy) )
- copy.prepend( d->cwd + '/' );
-
-// kdDebug() << "postProcess: stating " << copy << endl;
-
- KDE_struct_stat sbuff;
-
- TQCString file = TQFile::encodeName( copy );
-
- if ( KDE_stat( (const char*)file, &sbuff ) == 0 ) {
- if ( S_ISDIR ( sbuff.st_mode ) )
- match.append( '/' );
- }
- else {
- kdDebug() << "Could not stat file " << copy << endl;
- }
- }
-}
-
-void KURLCompletion::postProcessMatches( TQStringList * matches ) const
-{
- if ( !matches->isEmpty() && d->last_compl_type == CTFile ) {
- TQStringList::Iterator it = matches->begin();
- for (; it != matches->end(); ++it ) {
- adjustMatch( (*it) );
- }
- }
-}
-
-void KURLCompletion::postProcessMatches( KCompletionMatches * matches ) const
-{
- if ( !matches->isEmpty() && d->last_compl_type == CTFile ) {
- KCompletionMatches::Iterator it = matches->begin();
- for (; it != matches->end(); ++it ) {
- adjustMatch( (*it).value() );
- }
- }
-}
-
-void KURLCompletion::customEvent(TQCustomEvent *e)
-{
- if ( e->type() == CompletionMatchEvent::uniqueType() ) {
-
- CompletionMatchEvent *event = static_cast<CompletionMatchEvent *>( e );
-
- event->completionThread()->wait();
-
- if ( !isListedURL( CTUser ) ) {
- stop();
- clear();
- addMatches( event->completionThread()->matches() );
- }
-
- setListedURL( CTUser );
-
- if ( d->userListThread == event->completionThread() )
- d->userListThread = 0;
-
- if ( d->dirListThread == event->completionThread() )
- d->dirListThread = 0;
-
- delete event->completionThread();
- }
-}
-
-// static
-TQString KURLCompletion::replacedPath( const TQString& text, bool replaceHome, bool replaceEnv )
-{
- if ( text.isEmpty() )
- return text;
-
- MyURL url( text, TQString::null ); // no need to replace something of our current cwd
- if ( !url.kurl()->isLocalFile() )
- return text;
-
- url.filter( replaceHome, replaceEnv );
- return url.dir() + url.file();
-}
-
-
-TQString KURLCompletion::replacedPath( const TQString& text )
-{
- return replacedPath( text, d->replace_home, d->replace_env );
-}
-
-/////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////
-// Static functions
-
-/*
- * expandEnv
- *
- * Expand environment variables in text. Escaped '$' are ignored.
- * Return true if expansion was made.
- */
-static bool expandEnv( TQString &text )
-{
- // Find all environment variables beginning with '$'
- //
- int pos = 0;
-
- bool expanded = false;
-
- while ( (pos = text.find('$', pos)) != -1 ) {
-
- // Skip escaped '$'
- //
- if ( text[pos-1] == '\\' ) {
- pos++;
- }
- // Variable found => expand
- //
- else {
- // Find the end of the variable = next '/' or ' '
- //
- int pos2 = text.find( ' ', pos+1 );
- int pos_tmp = text.find( '/', pos+1 );
-
- if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
- pos2 = pos_tmp;
-
- if ( pos2 == -1 )
- pos2 = text.length();
-
- // Replace if the variable is terminated by '/' or ' '
- // and defined
- //
- if ( pos2 >= 0 ) {
- int len = pos2 - pos;
- TQString key = text.mid( pos+1, len-1);
- TQString value =
- TQString::fromLocal8Bit( ::getenv(key.local8Bit()) );
-
- if ( !value.isEmpty() ) {
- expanded = true;
- text.replace( pos, len, value );
- pos = pos + value.length();
- }
- else {
- pos = pos2;
- }
- }
- }
- }
-
- return expanded;
-}
-
-/*
- * expandTilde
- *
- * Replace "~user" with the users home directory
- * Return true if expansion was made.
- */
-static bool expandTilde(TQString &text)
-{
- if ( text[0] != '~' )
- return false;
-
- bool expanded = false;
-
- // Find the end of the user name = next '/' or ' '
- //
- int pos2 = text.find( ' ', 1 );
- int pos_tmp = text.find( '/', 1 );
-
- if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
- pos2 = pos_tmp;
-
- if ( pos2 == -1 )
- pos2 = text.length();
-
- // Replace ~user if the user name is terminated by '/' or ' '
- //
- if ( pos2 >= 0 ) {
-
- TQString user = text.mid( 1, pos2-1 );
- TQString dir;
-
- // A single ~ is replaced with $HOME
- //
- if ( user.isEmpty() ) {
- dir = TQDir::homeDirPath();
- }
- // ~user is replaced with the dir from passwd
- //
- else {
- struct passwd *pw = ::getpwnam( user.local8Bit() );
-
- if ( pw )
- dir = TQFile::decodeName( pw->pw_dir );
-
- ::endpwent();
- }
-
- if ( !dir.isEmpty() ) {
- expanded = true;
- text.replace(0, pos2, dir);
- }
- }
-
- return expanded;
-}
-
-/*
- * unescape
- *
- * Remove escapes and return the result in a new string
- *
- */
-static TQString unescape(const TQString &text)
-{
- TQString result;
-
- for (uint pos = 0; pos < text.length(); pos++)
- if ( text[pos] != '\\' )
- result.insert( result.length(), text[pos] );
-
- return result;
-}
-
-void KURLCompletion::virtual_hook( int id, void* data )
-{ KCompletion::virtual_hook( id, data ); }
-
-#include "kurlcompletion.moc"
-