You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1025 lines
30 KiB
1025 lines
30 KiB
/* This file is part of the KDE project
|
|
|
|
Autocompletion code:
|
|
Copyright (C) 2009 Timothy Pearson <kb9vqf@pearsoncomputing.net>
|
|
|
|
Copyright (C) 1999-2002,2003 Dawit Alemayehu <adawit@kde.org>
|
|
Copyright (C) 2000 Malte Starostik <starosti@zedat.fu-berlin.de>
|
|
Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
|
|
|
|
Kdesu integration:
|
|
Copyright (C) 2000 Geert Jansen <jansen@kde.org>
|
|
|
|
Original authors:
|
|
Copyright (C) 1997 Matthias Ettrich <ettrich@kde.org>
|
|
Copyright (C) 1997 Torben Weis [ Added command completion ]
|
|
Copyright (C) 1999 Preston Brown <pbrown@kde.org>
|
|
|
|
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 <pwd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <tqvbox.h>
|
|
#include <tqlabel.h>
|
|
#include <tqbitmap.h>
|
|
#include <tqfile.h>
|
|
#include <tqslider.h>
|
|
#include <tqlayout.h>
|
|
#include <tqgroupbox.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqregexp.h>
|
|
#include <tqwhatsthis.h>
|
|
#include <tqstylesheet.h>
|
|
|
|
#include <dcopclient.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kprocess.h>
|
|
#include <kcombobox.h>
|
|
#include <klineedit.h>
|
|
#include <kapplication.h>
|
|
#include <kdebug.h>
|
|
#include <kpassdlg.h>
|
|
#include <krun.h>
|
|
#include <kwin.h>
|
|
#include <kdesu/su.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kconfig.h>
|
|
#include <kiconloader.h>
|
|
#include <kpushbutton.h>
|
|
#include <kguiitem.h>
|
|
#include <kstdguiitem.h>
|
|
#include <kmimetype.h>
|
|
#include <kurifilter.h>
|
|
#include <kcompletionbox.h>
|
|
|
|
#include "minicli.moc"
|
|
#include "minicli_ui.h"
|
|
#include "kdesktopsettings.h"
|
|
|
|
#define KDESU_ERR strerror(errno)
|
|
|
|
Minicli::Minicli( TQWidget *parent, const char *name)
|
|
:KDialog( parent, name, false, (WFlags)WType_TopLevel ),
|
|
m_autoCheckedRunInTerm(false)
|
|
{
|
|
m_pURLCompletion = 0L;
|
|
|
|
setPlainCaption( i18n("Run Command") );
|
|
KWin::setIcons( winId(), DesktopIcon("run"), SmallIcon("run") );
|
|
|
|
TQVBoxLayout* mainLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
|
|
m_dlg = new MinicliDlgUI (this);
|
|
mainLayout->addWidget(m_dlg);
|
|
|
|
m_dlg->lbRunIcon->setPixmap(DesktopIcon("kmenu"));
|
|
m_dlg->lbComment->tqsetAlignment( TQt::WordBreak );
|
|
|
|
m_dlg->cbCommand->setDuplicatesEnabled( false );
|
|
m_dlg->cbCommand->setTrapReturnKey( true );
|
|
|
|
// Options button...
|
|
m_dlg->pbOptions->setGuiItem (KGuiItem( i18n("&Options >>"), "configure" ));
|
|
|
|
// Run button...
|
|
m_dlg->pbRun->setGuiItem (KGuiItem( i18n("&Run"), "run" ));
|
|
|
|
// Cancel button...
|
|
m_dlg->pbCancel->setGuiItem ( KStdGuiItem::cancel() );
|
|
|
|
if (!kapp->authorize("shell_access"))
|
|
m_dlg->pbOptions->hide();
|
|
|
|
m_dlg->pbRun->setEnabled(!m_dlg->cbCommand->currentText().isEmpty());
|
|
m_dlg->pbRun->setDefault( true );
|
|
|
|
// Do not show the advanced group box on startup...
|
|
m_dlg->gbAdvanced->hide();
|
|
|
|
// URI Filter meta object...
|
|
m_filterData = new KURIFilterData();
|
|
|
|
// Create a timer object...
|
|
m_parseTimer = new TQTimer(this);
|
|
|
|
m_FocusWidget = 0;
|
|
|
|
m_prevCached = false;
|
|
m_iPriority = 50;
|
|
m_iScheduler = StubProcess::SchedNormal;
|
|
|
|
m_dlg->leUsername->setText("root");
|
|
|
|
// Autocomplete system
|
|
m_filesystemAutocomplete = 0;
|
|
m_histfilesystemAutocomplete = 0;
|
|
m_pURLCompletion = new KURLCompletion();
|
|
//m_pURLCompletion->setCompletionMode( KGlobalSettings::completionMode() );
|
|
connect( m_pURLCompletion, TQT_SIGNAL( match(const TQString&) ), TQT_SLOT( slotMatch(const TQString&) ));
|
|
|
|
// Main widget buttons...
|
|
connect( m_dlg->pbRun, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept()) );
|
|
connect( m_dlg->pbCancel, TQT_SIGNAL(clicked()), this, TQT_SLOT(reject()) );
|
|
connect( m_dlg->pbOptions, TQT_SIGNAL(clicked()), TQT_SLOT(slotAdvanced()) );
|
|
connect( m_parseTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotParseTimer()) );
|
|
|
|
connect( m_dlg->cbCommand, TQT_SIGNAL( textChanged( const TQString& ) ),
|
|
TQT_SLOT( slotCmdChanged(const TQString&) ) );
|
|
|
|
connect( m_dlg->cbCommand, TQT_SIGNAL( returnPressed() ),
|
|
m_dlg->pbRun, TQT_SLOT( animateClick() ) );
|
|
|
|
m_dlg->cbCommand->setHistoryEditorEnabled( true );
|
|
connect( m_dlg->cbCommand, TQT_SIGNAL(removed( const TQString&) ), TQT_SLOT(saveConfig()) );
|
|
|
|
// Advanced group box...
|
|
connect(m_dlg->cbPriority, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotChangeScheduler(bool)));
|
|
connect(m_dlg->slPriority, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotPriority(int)));
|
|
connect(m_dlg->cbRealtime, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotRealtime(bool)));
|
|
connect(m_dlg->cbAutocomplete, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotAutocompleteToggled(bool)));
|
|
connect(m_dlg->cbAutohistory, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotAutohistoryToggled(bool)));
|
|
connect(m_dlg->cbRunAsOther, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotChangeUid(bool)));
|
|
connect(m_dlg->leUsername, TQT_SIGNAL(lostFocus()), TQT_SLOT(updateAuthLabel()));
|
|
connect(m_dlg->cbRunInTerminal, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotTerminal(bool)));
|
|
|
|
m_dlg->slPriority->setValue(50);
|
|
|
|
loadConfig();
|
|
}
|
|
|
|
Minicli::~Minicli()
|
|
{
|
|
delete m_filterData;
|
|
delete m_pURLCompletion;
|
|
}
|
|
|
|
void Minicli::setCommand(const TQString& command)
|
|
{
|
|
m_dlg->cbCommand->lineEdit()->setText(command);
|
|
m_dlg->cbCommand->lineEdit()->deselect();
|
|
int firstSpace = command.find(' ');
|
|
if (firstSpace > 0) {
|
|
m_dlg->cbCommand->lineEdit()->setSelection(firstSpace+1, command.length());
|
|
}
|
|
}
|
|
|
|
TQSize Minicli::tqsizeHint() const
|
|
{
|
|
int maxWidth = tqApp->desktop()->screenGeometry((TQWidget*)this).width();
|
|
if (maxWidth < 603)
|
|
{
|
|
// a sensible max for smaller screens
|
|
maxWidth = (maxWidth > 240) ? 240 : maxWidth;
|
|
}
|
|
else
|
|
{
|
|
maxWidth = maxWidth * 2 / 5;
|
|
}
|
|
|
|
return TQSize(maxWidth, -1);
|
|
}
|
|
|
|
void Minicli::show()
|
|
{
|
|
KWin::setState( winId(), NET::StaysOnTop );
|
|
KDialog::show();
|
|
}
|
|
|
|
void Minicli::loadConfig()
|
|
{
|
|
TQStringList histList = KDesktopSettings::history();
|
|
int maxHistory = KDesktopSettings::historyLength();
|
|
m_terminalAppList = KDesktopSettings::terminalApps();
|
|
|
|
if (m_terminalAppList.isEmpty())
|
|
m_terminalAppList << "ls"; // Default
|
|
|
|
bool block = m_dlg->cbCommand->signalsBlocked();
|
|
m_dlg->cbCommand->blockSignals( true );
|
|
m_dlg->cbCommand->setMaxCount( maxHistory );
|
|
m_dlg->cbCommand->setHistoryItems( histList );
|
|
m_dlg->cbCommand->blockSignals( block );
|
|
|
|
m_dlg->cbAutocomplete->setChecked( KDesktopSettings::miniCLIFilesystemAutoComplete() );
|
|
m_dlg->cbAutohistory->setChecked( KDesktopSettings::miniCLIHistoryAndFilesystemAutoComplete() );
|
|
|
|
m_filesystemAutocomplete = KDesktopSettings::miniCLIFilesystemAutoComplete();
|
|
m_histfilesystemAutocomplete = KDesktopSettings::miniCLIHistoryAndFilesystemAutoComplete();
|
|
|
|
if (m_histfilesystemAutocomplete == true) {
|
|
m_dlg->cbAutocomplete->setDisabled( true );
|
|
}
|
|
else {
|
|
m_dlg->cbAutocomplete->setDisabled( false );
|
|
}
|
|
|
|
TQStringList compList = KDesktopSettings::completionItems();
|
|
if( compList.isEmpty() )
|
|
m_dlg->cbCommand->completionObject()->setItems( histList );
|
|
else
|
|
m_dlg->cbCommand->completionObject()->setItems( compList );
|
|
|
|
int mode = KDesktopSettings::completionMode();
|
|
m_dlg->cbCommand->setCompletionMode( (KGlobalSettings::Completion) mode );
|
|
|
|
KCompletionBox* box = m_dlg->cbCommand->completionBox();
|
|
if (box)
|
|
box->setActivateOnSelect( false );
|
|
|
|
m_finalFilters = KURIFilter::self()->pluginNames();
|
|
m_finalFilters.remove("kuriikwsfilter");
|
|
|
|
m_middleFilters = m_finalFilters;
|
|
m_middleFilters.remove("localdomainurifilter");
|
|
|
|
// Provide username completions. Use saner and configurable maximum values.
|
|
int maxEntries = KDesktopSettings::maxUsernameCompletions();
|
|
TQStringList users;
|
|
|
|
struct passwd *pw;
|
|
setpwent();
|
|
for (int count=0; ((pw = getpwent()) != 0L) && (count < maxEntries); count++)
|
|
users << TQString::fromLocal8Bit(pw->pw_name);
|
|
endpwent();
|
|
|
|
KCompletion *completion = new KCompletion;
|
|
completion->setOrder(KCompletion::Sorted);
|
|
completion->insertItems (users);
|
|
|
|
m_dlg->leUsername->setCompletionObject(completion, true);
|
|
m_dlg->leUsername->setCompletionMode(KGlobalSettings::completionMode());
|
|
m_dlg->leUsername->setAutoDeleteCompletionObject( true );
|
|
|
|
}
|
|
|
|
void Minicli::saveConfig()
|
|
{
|
|
KDesktopSettings::setHistory( m_dlg->cbCommand->historyItems() );
|
|
KDesktopSettings::setTerminalApps( m_terminalAppList );
|
|
//KDesktopSettings::setCompletionItems( m_dlg->cbCommand->completionObject()->items() );
|
|
KDesktopSettings::setCompletionMode( m_dlg->cbCommand->completionMode() );
|
|
KDesktopSettings::setMiniCLIFilesystemAutoComplete( m_filesystemAutocomplete );
|
|
KDesktopSettings::setMiniCLIHistoryAndFilesystemAutoComplete( m_histfilesystemAutocomplete );
|
|
KDesktopSettings::writeConfig();
|
|
}
|
|
|
|
void Minicli::clearHistory()
|
|
{
|
|
m_dlg->cbCommand->clearHistory();
|
|
saveConfig();
|
|
}
|
|
|
|
void Minicli::accept()
|
|
{
|
|
TQString cmd = m_dlg->cbCommand->currentText().stripWhiteSpace();
|
|
if (!cmd.isEmpty() && (cmd[0].isNumber() || (cmd[0] == '(')) &&
|
|
(TQRegExp("[a-zA-Z\\]\\[]").search(cmd) == -1))
|
|
{
|
|
TQString result = calculate(cmd);
|
|
if (!result.isEmpty())
|
|
m_dlg->cbCommand->setCurrentText(result);
|
|
return;
|
|
}
|
|
|
|
bool logout = (cmd == "logout");
|
|
bool lock = (cmd == "lock");
|
|
|
|
if( !logout && !lock && runCommand() == 1 )
|
|
return;
|
|
|
|
m_dlg->cbCommand->addToHistory( m_dlg->cbCommand->currentText().stripWhiteSpace() );
|
|
reset();
|
|
saveConfig();
|
|
TQDialog::accept();
|
|
|
|
if ( logout )
|
|
{
|
|
kapp->propagateSessionManager();
|
|
kapp->requestShutDown();
|
|
}
|
|
if ( lock )
|
|
{
|
|
TQCString appname( "kdesktop" );
|
|
int kicker_screen_number = qt_xscreen();
|
|
if ( kicker_screen_number )
|
|
appname.sprintf("kdesktop-screen-%d", kicker_screen_number);
|
|
kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", TQString(""));
|
|
}
|
|
}
|
|
|
|
void Minicli::reject()
|
|
{
|
|
reset();
|
|
TQDialog::reject();
|
|
}
|
|
|
|
void Minicli::reset()
|
|
{
|
|
if( m_dlg->gbAdvanced->isShown() )
|
|
slotAdvanced();
|
|
|
|
bool block = m_dlg->cbCommand->signalsBlocked();
|
|
m_dlg->cbCommand->blockSignals( true );
|
|
m_dlg->cbCommand->clearEdit();
|
|
m_dlg->cbCommand->setFocus();
|
|
m_dlg->cbCommand->reset();
|
|
m_dlg->cbCommand->blockSignals( block );
|
|
m_dlg->pbRun->setEnabled( false );
|
|
|
|
m_iPriority = 50;
|
|
m_iScheduler = StubProcess::SchedNormal;
|
|
|
|
m_dlg->cbRunInTerminal->setChecked(false);
|
|
m_dlg->cbRunAsOther->setChecked(false);
|
|
|
|
m_dlg->leUsername->setText("root");
|
|
|
|
m_dlg->cbPriority->setChecked(false);
|
|
|
|
m_dlg->slPriority->setValue(m_iPriority);
|
|
|
|
m_dlg->cbRealtime->setChecked( m_iScheduler == StubProcess::SchedRealtime );
|
|
m_dlg->lePassword->erase();
|
|
|
|
m_FocusWidget = 0;
|
|
m_iconName = TQString::null;
|
|
m_prevIconName = TQString::null;
|
|
|
|
m_prevCached = false;
|
|
updateAuthLabel();
|
|
setIcon();
|
|
}
|
|
|
|
void Minicli::keyPressEvent( TQKeyEvent* e )
|
|
{
|
|
if ( e->key() == Qt::Key_Escape )
|
|
{
|
|
e->accept();
|
|
m_dlg->pbCancel->animateClick();
|
|
return;
|
|
}
|
|
|
|
TQDialog::keyPressEvent( e );
|
|
}
|
|
|
|
TQString Minicli::terminalCommand (const TQString& cmd, const TQString& args)
|
|
{
|
|
TQString terminal = KDesktopSettings::terminalApplication().stripWhiteSpace();
|
|
if (terminal.endsWith("konsole"))
|
|
terminal += " --noclose";
|
|
|
|
if( args.isEmpty() )
|
|
terminal += TQString(" -e /bin/sh -c \"%1\"").arg(cmd);
|
|
else
|
|
terminal += TQString(" -e /bin/sh -c \"%1 %2\"").arg(cmd).arg(args);
|
|
|
|
if (!m_terminalAppList.contains(cmd))
|
|
m_terminalAppList << cmd;
|
|
|
|
return terminal;
|
|
}
|
|
|
|
int Minicli::runCommand()
|
|
{
|
|
m_parseTimer->stop();
|
|
|
|
// Make sure we have an updated data
|
|
parseLine( true );
|
|
|
|
// Ignore empty commands...
|
|
if ( m_dlg->cbCommand->currentText().isEmpty() )
|
|
return 1;
|
|
|
|
TQString cmd;
|
|
KURL uri = m_filterData->uri();
|
|
if ( uri.isLocalFile() && !uri.hasRef() && uri.query().isEmpty() )
|
|
cmd = uri.path();
|
|
else
|
|
cmd = uri.url();
|
|
|
|
TQCString asn;
|
|
if( tqApp->desktop()->isVirtualDesktop())
|
|
{
|
|
asn = KStartupInfo::createNewStartupId();
|
|
KStartupInfoId id;
|
|
id.initId( asn );
|
|
KStartupInfoData data;
|
|
data.setXinerama( tqApp->desktop()->screenNumber( this ));
|
|
KStartupInfo::sendChange( id, data );
|
|
}
|
|
|
|
// Determine whether the application should be run through
|
|
// the command line (terminal) interface...
|
|
bool useTerminal = m_dlg->cbRunInTerminal->isChecked();
|
|
|
|
kdDebug (1207) << "Use terminal ? " << useTerminal << endl;
|
|
|
|
if (!kapp->authorize("shell_access"))
|
|
useTerminal = false;
|
|
|
|
if( needsKDEsu() )
|
|
{
|
|
TQCString user;
|
|
struct passwd *pw;
|
|
|
|
if (m_dlg->cbRunAsOther)
|
|
{
|
|
pw = getpwnam(m_dlg->leUsername->text().local8Bit());
|
|
if (pw == 0L)
|
|
{
|
|
KMessageBox::sorry( this, i18n("<qt>The user <b>%1</b> "
|
|
"does not exist on this system.</qt>").arg(m_dlg->leUsername->text()));
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pw = getpwuid(getuid());
|
|
if (pw == 0L)
|
|
{
|
|
KMessageBox::error( this, i18n("You do not exist.\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
user = pw->pw_name;
|
|
|
|
{
|
|
// Scoped. we want this object to go away before the fork
|
|
// (maybe not necessary, but can't hurt) according to the cvs log,
|
|
// creating the SuProcess object in the parent and using it in the
|
|
// child creates crashes, but we need to check password before the
|
|
// fork in order to not get in trouble with X for the messagebox
|
|
|
|
SuProcess proc_checkpwd;
|
|
proc_checkpwd.setUser( user );
|
|
|
|
if (m_dlg->cbPriority->isChecked())
|
|
{
|
|
proc_checkpwd.setPriority(m_iPriority);
|
|
proc_checkpwd.setScheduler(m_iScheduler);
|
|
}
|
|
|
|
if (proc_checkpwd.checkInstall(m_dlg->lePassword->password()) != 0)
|
|
{
|
|
KMessageBox::sorry(this, i18n("Incorrect password; please try again."));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
TQApplication::flushX();
|
|
|
|
int pid = fork();
|
|
|
|
if (pid < 0)
|
|
{
|
|
kdError(1207) << "fork(): " << KDESU_ERR << "\n";
|
|
return -1;
|
|
}
|
|
|
|
if (pid > 0)
|
|
return 0;
|
|
|
|
// From here on, this is child...
|
|
|
|
SuProcess proc;
|
|
proc.setUser(user);
|
|
|
|
if (m_dlg->cbPriority->isChecked())
|
|
{
|
|
proc.setPriority(m_iPriority);
|
|
proc.setScheduler(m_iScheduler);
|
|
}
|
|
|
|
TQCString command;
|
|
|
|
if (useTerminal)
|
|
command = terminalCommand( cmd, m_filterData->argsAndOptions() ).local8Bit();
|
|
else
|
|
{
|
|
command = cmd.local8Bit();
|
|
if( m_filterData->hasArgsAndOptions() )
|
|
command += m_filterData->argsAndOptions().local8Bit();
|
|
}
|
|
|
|
proc.setCommand(command);
|
|
|
|
// Block SIGCHLD because SuProcess::exec() uses waitpid()
|
|
sigset_t sset;
|
|
sigemptyset(&sset);
|
|
sigaddset(&sset, SIGCHLD);
|
|
sigprocmask(SIG_BLOCK, &sset, 0L);
|
|
proc.setTerminal(true);
|
|
proc.setErase(true);
|
|
_exit(proc.exec(m_dlg->lePassword->password()));
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
TQString exec;
|
|
|
|
// yes, this is a hack, but there is no way of doing it
|
|
// through SuProcess without providing the user password
|
|
if (m_iPriority < 50)
|
|
{
|
|
// from kdesu_stub.c
|
|
int val = 20 - (int) (((double) m_iPriority) * 40 / 100 + 0.5);
|
|
cmd = "nice -n " + TQString::number( val ) + " " + cmd;
|
|
}
|
|
|
|
if (useTerminal)
|
|
{
|
|
cmd = terminalCommand( cmd, m_filterData->argsAndOptions() );
|
|
kdDebug(1207) << "Terminal command: " << cmd << endl;
|
|
}
|
|
else
|
|
{
|
|
switch( m_filterData->uriType() )
|
|
{
|
|
case KURIFilterData::LOCAL_FILE:
|
|
case KURIFilterData::LOCAL_DIR:
|
|
case KURIFilterData::NET_PROTOCOL:
|
|
case KURIFilterData::HELP:
|
|
{
|
|
// No need for kfmclient, KRun does it all (David)
|
|
(void) new KRun( m_filterData->uri(), parentWidget(), asn );
|
|
return 0;
|
|
}
|
|
case KURIFilterData::EXECUTABLE:
|
|
{
|
|
if( !m_filterData->hasArgsAndOptions() )
|
|
{
|
|
// Look for desktop file
|
|
KService::Ptr service = KService::serviceByDesktopName(cmd);
|
|
if (service && service->isValid() && service->type() == "Application")
|
|
{
|
|
notifyServiceStarted(service);
|
|
KRun::run(*service, KURL::List(), parentWidget(), asn );
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
// fall-through to shell case
|
|
case KURIFilterData::SHELL:
|
|
{
|
|
if (kapp->authorize("shell_access"))
|
|
{
|
|
exec = cmd;
|
|
|
|
if( m_filterData->hasArgsAndOptions() )
|
|
cmd += m_filterData->argsAndOptions();
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
|
|
"You do not have permission to execute "
|
|
"this command.")
|
|
.arg( TQStyleSheet::convertFromPlainText(cmd) ));
|
|
return 1;
|
|
}
|
|
}
|
|
case KURIFilterData::UNKNOWN:
|
|
case KURIFilterData::ERROR:
|
|
default:
|
|
{
|
|
// Look for desktop file
|
|
KService::Ptr service = KService::serviceByDesktopName(cmd);
|
|
if (service && service->isValid() && service->type() == "Application")
|
|
{
|
|
notifyServiceStarted(service);
|
|
KRun::run(*service, KURL::List(), parentWidget(), asn );
|
|
return 0;
|
|
}
|
|
|
|
service = KService::serviceByName(cmd);
|
|
if (service && service->isValid() && service->type() == "Application")
|
|
{
|
|
notifyServiceStarted(service);
|
|
KRun::run(*service, KURL::List(), parentWidget(), asn );
|
|
return 0;
|
|
}
|
|
|
|
KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
|
|
"Could not run the specified command.")
|
|
.arg( TQStyleSheet::convertFromPlainText(cmd) ));
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( KRun::runCommand( cmd, exec, m_iconName, parentWidget(), asn ) )
|
|
return 0;
|
|
else
|
|
{
|
|
KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
|
|
"The specified command does not exist.").arg(cmd) );
|
|
return 1; // Let the user try again...
|
|
}
|
|
}
|
|
}
|
|
|
|
void Minicli::notifyServiceStarted(KService::Ptr service)
|
|
{
|
|
// Inform other applications (like the quickstarter applet)
|
|
// that an application was started
|
|
TQByteArray params;
|
|
TQDataStream stream(params, IO_WriteOnly);
|
|
stream << "minicli" << service->storageId();
|
|
kdDebug() << "minicli appLauncher dcop signal: " << service->storageId() << endl;
|
|
KApplication::kApplication()->dcopClient()->emitDCOPSignal("appLauncher",
|
|
"serviceStartedByStorageId(TQString,TQString)", params);
|
|
}
|
|
|
|
void Minicli::slotCmdChanged(const TQString& text)
|
|
{
|
|
bool isEmpty = text.isEmpty();
|
|
m_dlg->pbRun->setEnabled( !isEmpty );
|
|
|
|
if( isEmpty )
|
|
{
|
|
// Reset values to default
|
|
m_filterData->setData(KURL());
|
|
|
|
// Empty String is certainly no terminal application
|
|
slotTerminal(false);
|
|
|
|
// Reset the icon if needed...
|
|
const TQPixmap pixmap = DesktopIcon("kmenu");
|
|
|
|
if ( pixmap.serialNumber() != m_dlg->lbRunIcon->pixmap()->serialNumber())
|
|
m_dlg->lbRunIcon->setPixmap(pixmap);
|
|
|
|
return;
|
|
}
|
|
else if ((m_filesystemAutocomplete == true) && ( m_pURLCompletion )) {
|
|
// Attempt to autocomplete the entered URL if it starts with the / character, meaning I am looking for something on the filesystem
|
|
// Also use autocompletion if it appears that I am using some kind of ioslave, except the http:// ioslave
|
|
m_urlCompletionStarted = true; // flag for slotMatch()
|
|
|
|
if ((text.startsWith( "/" ) || text.startsWith( "~" ) || (text.contains("://", false) != 0)) && (text.contains("http://", false) == 0)) {
|
|
TQString completion = m_pURLCompletion->makeCompletion( text );
|
|
}
|
|
}
|
|
|
|
m_parseTimer->start(250, true);
|
|
}
|
|
|
|
// Handle match() from m_pURLCompletion
|
|
void Minicli::slotMatch( const TQString &match )
|
|
{
|
|
TQString current_text;
|
|
TQStringList histList = KDesktopSettings::history();
|
|
int maxHistory = KDesktopSettings::historyLength();
|
|
int maxAutocompletion = KDesktopSettings::miniCLIAutocompletionLength();
|
|
|
|
if ( match.isEmpty() ) // this case is handled directly
|
|
return;
|
|
|
|
// Check flag to avoid match() raised by rotation
|
|
if ( m_urlCompletionStarted ) {
|
|
m_urlCompletionStarted = false;
|
|
|
|
if (m_filesystemAutocomplete == true) {
|
|
bool block = m_dlg->cbCommand->signalsBlocked();
|
|
m_dlg->cbCommand->blockSignals( true );
|
|
TQStringList items = m_pURLCompletion->allMatches();
|
|
items.sort();
|
|
if (m_histfilesystemAutocomplete == true) {
|
|
// Add the history to the list
|
|
histList += items;
|
|
maxHistory += maxAutocompletion;
|
|
}
|
|
else {
|
|
histList = items;
|
|
maxHistory = maxAutocompletion;
|
|
}
|
|
current_text = m_dlg->cbCommand->currentText();
|
|
//histList.prepend ( current_text ); // Add the current text to the autocompletion list
|
|
m_dlg->cbCommand->setMaxCount( maxHistory );
|
|
m_dlg->cbCommand->completionObject()->setItems( histList );
|
|
m_dlg->cbCommand->setCurrentText( current_text );
|
|
m_dlg->cbCommand->blockSignals( block );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Minicli::slotAdvanced()
|
|
{
|
|
if (m_dlg->gbAdvanced->isHidden())
|
|
{
|
|
m_dlg->gbAdvanced->show();
|
|
m_dlg->pbOptions->setText(i18n("&Options <<"));
|
|
|
|
// Set the focus back to the widget that had it to begin with, i.e.
|
|
// do not put the focus on the "Options" button.
|
|
m_FocusWidget = tqfocusWidget();
|
|
|
|
if( m_FocusWidget )
|
|
m_FocusWidget->setFocus();
|
|
}
|
|
else
|
|
{
|
|
m_dlg->gbAdvanced->hide();
|
|
m_dlg->pbOptions->setText(i18n("&Options >>"));
|
|
|
|
if( m_FocusWidget && m_FocusWidget->parent() != m_dlg->gbAdvanced )
|
|
m_FocusWidget->setFocus();
|
|
}
|
|
adjustSize();
|
|
}
|
|
|
|
void Minicli::slotParseTimer()
|
|
{
|
|
//kdDebug (1207) << "Minicli::slotParseTimer: Timed out..." << endl;
|
|
parseLine( false );
|
|
}
|
|
|
|
void Minicli::parseLine( bool final )
|
|
{
|
|
TQString cmd = m_dlg->cbCommand->currentText().stripWhiteSpace();
|
|
m_filterData->setData( cmd );
|
|
|
|
if( final )
|
|
KURIFilter::self()->filterURI( *(m_filterData), m_finalFilters );
|
|
else
|
|
KURIFilter::self()->filterURI( *(m_filterData), m_middleFilters );
|
|
|
|
bool isTerminalApp = ((m_filterData->uriType() == KURIFilterData::EXECUTABLE) &&
|
|
m_terminalAppList.contains(m_filterData->uri().url()));
|
|
|
|
if( !isTerminalApp )
|
|
{
|
|
m_iconName = m_filterData->iconName();
|
|
setIcon();
|
|
}
|
|
|
|
if ( isTerminalApp && final && !m_dlg->cbRunInTerminal->isChecked() )
|
|
{
|
|
m_terminalAppList.remove( m_filterData->uri().url() );
|
|
isTerminalApp = false;
|
|
}
|
|
else
|
|
{
|
|
bool wasAutoChecked = m_autoCheckedRunInTerm;
|
|
bool willBeAutoChecked = isTerminalApp && !m_dlg->cbRunInTerminal->isChecked();
|
|
slotTerminal(isTerminalApp || (m_dlg->cbRunInTerminal->isChecked() && !m_autoCheckedRunInTerm));
|
|
if (!wasAutoChecked && willBeAutoChecked)
|
|
m_autoCheckedRunInTerm = true;
|
|
}
|
|
|
|
kdDebug (1207) << "Command: " << m_filterData->uri().url() << endl;
|
|
kdDebug (1207) << "Arguments: " << m_filterData->argsAndOptions() << endl;
|
|
}
|
|
|
|
void Minicli::setIcon ()
|
|
{
|
|
if( m_iconName.isEmpty() || m_iconName == "unknown" || m_iconName == "kde" )
|
|
m_iconName = TQString::tqfromLatin1("kmenu");
|
|
|
|
TQPixmap icon = DesktopIcon( m_iconName );
|
|
|
|
if ( m_iconName == "www" )
|
|
{
|
|
// Not using KIconEffect::overlay as that requires the same size
|
|
// for the icon and the overlay, also the overlay definately doesn't
|
|
// have a more that one-bit alpha channel here
|
|
TQPixmap overlay( locate ( "icon", KMimeType::favIconForURL( m_filterData->uri() ) + ".png" ) );
|
|
if ( !overlay.isNull() )
|
|
{
|
|
int x = icon.width() - overlay.width();
|
|
int y = icon.height() - overlay.height();
|
|
if ( icon.mask() )
|
|
{
|
|
TQBitmap mask = *icon.mask();
|
|
bitBlt( &mask, x, y,
|
|
overlay.mask() ? TQT_TQPIXMAP(const_cast<TQBitmap *>(overlay.mask())) : &overlay,
|
|
0, 0, overlay.width(), overlay.height(),
|
|
overlay.mask() ? OrROP : SetROP );
|
|
icon.setMask(mask);
|
|
}
|
|
bitBlt( &icon, x, y, &overlay );
|
|
}
|
|
}
|
|
|
|
m_dlg->lbRunIcon->setPixmap( icon );
|
|
}
|
|
|
|
void Minicli::updateAuthLabel()
|
|
{
|
|
if ((m_dlg->cbPriority->isChecked() && (m_iPriority > 50)) ||
|
|
(m_iScheduler != StubProcess::SchedNormal))
|
|
{
|
|
if (!m_prevCached && !m_dlg->leUsername->text().isEmpty())
|
|
{
|
|
//kdDebug(1207) << k_funcinfo << "Caching: user=" << m_dlg->leUsername->text() <<
|
|
// ", checked=" << m_dlg->cbRunAsOther->isChecked() << endl;
|
|
|
|
m_prevUser = m_dlg->leUsername->text();
|
|
m_prevPass = m_dlg->lePassword->text();
|
|
m_prevChecked = m_dlg->cbRunAsOther->isChecked();
|
|
m_prevCached = true;
|
|
}
|
|
if (m_dlg->leUsername->text() != TQString::tqfromLatin1("root"))
|
|
m_dlg->lePassword->setText(TQString::null);
|
|
m_dlg->leUsername->setText(TQString::tqfromLatin1("root"));
|
|
m_dlg->cbRunAsOther->setChecked(true);
|
|
m_dlg->cbRunAsOther->setEnabled(false);
|
|
m_dlg->leUsername->setEnabled(false);
|
|
m_dlg->lbUsername->setEnabled(true);
|
|
m_dlg->lePassword->setEnabled(true);
|
|
m_dlg->lbPassword->setEnabled(true);
|
|
}
|
|
else if (m_dlg->cbRunAsOther->isEnabled() &&
|
|
m_dlg->cbRunAsOther->isChecked() && !m_dlg->leUsername->text().isEmpty())
|
|
{
|
|
m_dlg->lePassword->setEnabled(true);
|
|
m_dlg->lbPassword->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
if (m_prevCached)
|
|
{
|
|
m_dlg->leUsername->setText(m_prevUser);
|
|
m_dlg->lePassword->setText(m_prevPass);
|
|
m_dlg->cbRunAsOther->setChecked(m_prevChecked);
|
|
m_dlg->leUsername->setEnabled(m_prevChecked);
|
|
m_dlg->lbUsername->setEnabled(m_prevChecked);
|
|
}
|
|
else
|
|
{
|
|
m_dlg->cbRunAsOther->setChecked(false);
|
|
m_dlg->leUsername->setEnabled(false);
|
|
m_dlg->lbUsername->setEnabled(false);
|
|
}
|
|
m_dlg->cbRunAsOther->setEnabled(true);
|
|
m_dlg->lePassword->setEnabled(false);
|
|
m_dlg->lbPassword->setEnabled(false);
|
|
m_prevCached = false;
|
|
}
|
|
}
|
|
|
|
void Minicli::slotTerminal(bool enable)
|
|
{
|
|
m_dlg->cbRunInTerminal->setChecked(enable);
|
|
m_autoCheckedRunInTerm = false;
|
|
|
|
if (enable)
|
|
{
|
|
m_prevIconName = m_iconName;
|
|
m_iconName = TQString::tqfromLatin1( "konsole" );
|
|
setIcon();
|
|
}
|
|
else if (!m_prevIconName.isEmpty())
|
|
{
|
|
m_iconName = m_prevIconName;
|
|
setIcon();
|
|
}
|
|
}
|
|
|
|
void Minicli::slotChangeUid(bool enable)
|
|
{
|
|
m_dlg->leUsername->setEnabled(enable);
|
|
m_dlg->lbUsername->setEnabled(enable);
|
|
|
|
if(enable)
|
|
{
|
|
m_dlg->leUsername->selectAll();
|
|
m_dlg->leUsername->setFocus();
|
|
}
|
|
|
|
updateAuthLabel();
|
|
}
|
|
|
|
void Minicli::slotChangeScheduler(bool enable)
|
|
{
|
|
m_dlg->slPriority->setEnabled(enable);
|
|
m_dlg->lbLowPriority->setEnabled(enable);
|
|
m_dlg->lbHighPriority->setEnabled(enable);
|
|
|
|
updateAuthLabel();
|
|
}
|
|
|
|
bool Minicli::needsKDEsu()
|
|
{
|
|
return ((m_dlg->cbPriority->isChecked() && ((m_iPriority > 50) ||
|
|
(m_iScheduler != StubProcess::SchedNormal))) ||
|
|
(m_dlg->cbRunAsOther->isChecked() && !m_dlg->leUsername->text().isEmpty()));
|
|
}
|
|
|
|
void Minicli::slotRealtime(bool enabled)
|
|
{
|
|
m_iScheduler = enabled ? StubProcess::SchedRealtime : StubProcess::SchedNormal;
|
|
|
|
if (enabled)
|
|
{
|
|
if (KMessageBox::warningContinueCancel(this,
|
|
i18n("Running a realtime application can be very dangerous. "
|
|
"If the application misbehaves, the system might hang "
|
|
"unrecoverably.\nAre you sure you want to continue?"),
|
|
i18n("Warning - Run Command"), KGuiItem(i18n("&Run Realtime")),TQString::null,KMessageBox::Notify|KMessageBox::PlainCaption)
|
|
!= KMessageBox::Continue )
|
|
{
|
|
m_iScheduler = StubProcess::SchedNormal;
|
|
m_dlg->cbRealtime->setChecked(false);
|
|
}
|
|
}
|
|
|
|
updateAuthLabel();
|
|
}
|
|
|
|
void Minicli::slotAutocompleteToggled(bool enabled)
|
|
{
|
|
if (enabled)
|
|
{
|
|
// Enable filesystem autocompletion
|
|
m_filesystemAutocomplete = true;
|
|
}
|
|
else {
|
|
// Enable history only autocompletion
|
|
m_filesystemAutocomplete = false;
|
|
}
|
|
|
|
TQString current_text = m_dlg->cbCommand->currentText();
|
|
m_dlg->cbCommand->setCurrentText( current_text ); // Force an update of the autocompletion list
|
|
}
|
|
|
|
void Minicli::slotAutohistoryToggled(bool enabled)
|
|
{
|
|
if (enabled)
|
|
{
|
|
// Enable history and filesystem autocompletion
|
|
m_histfilesystemAutocomplete = true;
|
|
m_filesystemAutocomplete = true;
|
|
m_dlg->cbAutocomplete->setChecked( true );
|
|
m_dlg->cbAutocomplete->setDisabled ( true );
|
|
}
|
|
else {
|
|
// Disable history and filesystem autocompletion
|
|
m_histfilesystemAutocomplete = false;
|
|
m_dlg->cbAutocomplete->setDisabled ( false );
|
|
}
|
|
|
|
TQString current_text = m_dlg->cbCommand->currentText();
|
|
m_dlg->cbCommand->setCurrentText( current_text ); // Force an update of the autocompletion list
|
|
}
|
|
|
|
void Minicli::slotPriority(int priority)
|
|
{
|
|
// Provide a way to easily return to the default priority
|
|
if ((priority > 40) && (priority < 60))
|
|
{
|
|
priority = 50;
|
|
m_dlg->slPriority->setValue(50);
|
|
}
|
|
|
|
m_iPriority = priority;
|
|
|
|
updateAuthLabel();
|
|
}
|
|
|
|
TQString Minicli::calculate(const TQString &exp)
|
|
{
|
|
TQString result, cmd;
|
|
const TQString bc = KStandardDirs::findExe("bc");
|
|
if ( !bc.isEmpty() )
|
|
cmd = TQString("echo %1 | %2").arg(KProcess::quote(TQString("scale=8; ")+exp), KProcess::quote(bc));
|
|
else
|
|
cmd = TQString("echo $((%1))").arg(exp);
|
|
FILE *fs = popen(TQFile::encodeName(cmd).data(), "r");
|
|
if (fs)
|
|
{
|
|
{ // scope for QTextStream
|
|
TQTextStream ts(fs, IO_ReadOnly);
|
|
result = ts.read().stripWhiteSpace();
|
|
}
|
|
pclose(fs);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void Minicli::fontChange( const TQFont & )
|
|
{
|
|
adjustSize();
|
|
}
|
|
|
|
// vim: set et ts=2 sts=2 sw=2:
|
|
|