From b47113e5df8c2263acea944776489b6579d9d615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrew=20Lee=20=28=E6=9D=8E=E5=81=A5=E7=A7=8B=29?= Date: Fri, 14 Aug 2015 01:18:48 +0800 Subject: [PATCH] Adding upstream version 0.9.0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrew Lee (李健秋) --- .gitignore | 1 + CMakeLists.txt | 84 +++++++++++++++ main.cpp | 193 +++++++++++++++++++++++++++++++++++ man/lxqt-sudo.1 | 17 +++ passworddialog.cpp | 62 +++++++++++ passworddialog.h | 59 +++++++++++ passworddialog.ui | 151 +++++++++++++++++++++++++++ translations/lxqt-sudo.ts | 69 +++++++++++++ translations/lxqt-sudo_sk.ts | 80 +++++++++++++++ 9 files changed, 716 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 main.cpp create mode 100644 man/lxqt-sudo.1 create mode 100644 passworddialog.cpp create mode 100644 passworddialog.h create mode 100644 passworddialog.ui create mode 100644 translations/lxqt-sudo.ts create mode 100644 translations/lxqt-sudo_sk.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..dd5b755 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 2.8.11) + +project(lxqt-sudo) + +option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) + +include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +if(COMPILER_SUPPORTS_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +elseif(COMPILER_SUPPORTS_CXX0X) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +else() + message(FATAL "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. C++11 support is required") +endif() + +find_package(Qt5Widgets REQUIRED QUIET) +find_package(lxqt REQUIRED QUIET) + +include(${LXQT_USE_FILE}) +include(LXQtTranslate) + +include_directories ( + ${CMAKE_CURRENT_BINARY_DIR} + ${LXQT_INCLUDE_DIRS} +) + +add_definitions("-DLXQTSUDO_INSTALL_DIR=\"${CMAKE_INSTALL_PREFIX}/bin\"" + "-DLXQTSUDO_SUDO=\"sudo\"" + "-DLXQTSUDO=\"lxqt-sudo\"" + "-DLXQT_VERSION=\"${LXQT_VERSION}\"" + ) + +set ( HDRS + passworddialog.h +) + +set ( SRCS + passworddialog.cpp + main.cpp +) + +set ( MOCS + passworddialog.h +) + +set( UIS + passworddialog.ui +) + +qt5_wrap_cpp(MOC_OBJECTS ${MOCS}) +qt5_wrap_ui(UI_HEADERS ${UIS}) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} + SOURCES + ${HDRS} + ${SRCS} + ${UIS} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(SRCS ${PROJECT_NAME}) +#************************************************ + +add_executable(lxqt-sudo + ${SRCS} + ${UI_HEADERS} + ${MOC_OBJECTS} + ${DESKTOP_FILES} + ${QM_FILES} +) + +target_link_libraries(lxqt-sudo + Qt5::Widgets + ${LXQT_LIBRARIES} +) + +install(TARGETS lxqt-sudo RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") +install(FILES man/lxqt-sudo.1 DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1") diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..4e19500 --- /dev/null +++ b/main.cpp @@ -0,0 +1,193 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2015 LXQt team + * Authors: + * Palo Kisa + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include "passworddialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const QString app_master{QStringLiteral(LXQTSUDO)}; +const QString app_version{QStringLiteral(LXQT_VERSION)}; +const QString install_dir{QStringLiteral(LXQTSUDO_INSTALL_DIR)}; +const QString sudo_prog{QStringLiteral(LXQTSUDO_SUDO)}; +const QString sudo_pwd_prompt{QStringLiteral("Password:\n")}; + +void termSignalHandler(int signal) +{ + if (QApplication::instance()) + QApplication::instance()->quit(); +} + +void usage(QString const & err = QString()) +{ + if (!err.isEmpty()) + QTextStream(stderr) << err << '\n'; + QTextStream(stdout) + << QObject::tr("Usage: %1 command [arguments...]\n\n" + "GUI frontend for %2\n\n" + "Arguments:\n" + " command Command to run.\n" + " arguments Optional arguments for command.\n\n").arg(app_master).arg(sudo_prog); + if (!err.isEmpty()) + QMessageBox(QMessageBox::Critical, app_master, err, QMessageBox::Ok).exec(); +} + +void version() +{ + QTextStream(stdout) + << QObject::tr("%1 version %2\n").arg(app_master).arg(app_version); +} + +int master(int argc, char **argv) +{ + //master + LxQt::Application app(argc, argv); + app.setQuitOnLastWindowClosed(false); + + if (1 >= argc) + { + usage(QObject::tr("%1: no command to run provided!").arg(app_master)); + return 1; + } else + { + //simple help check + std::string arg1(argv[1]); + if ("-h" == arg1 || "--help" == arg1) + { + usage(); + return 0; + } else if ("-v" == arg1 || "--version" == arg1) + { + version(); + return 0; + } + //any other arguments we simply forward to sudo + } + + QStringList args = app.arguments(); + //check for provided command is done before + args.removeAt(0); + PasswordDialog dlg(args); + dlg.setModal(true); + app.setActiveWindow(&dlg); + + QScopedPointer sudo{new QProcess}; + QObject::connect(&dlg, &QDialog::finished, [&sudo, &dlg] (int result) + { + if (QDialog::Accepted == result) + { + sudo->write(QByteArray{}.append(dlg.password().append('\n'))); + } else + { + sudo->terminate(); + if (!sudo->waitForFinished(1000)) + sudo->kill(); + } + }); + + //start background process -> sudo + sudo->setProcessChannelMode(QProcess::ForwardedOutputChannel); + sudo->setReadChannel(QProcess::StandardError); + + QString last_line; + int ret; + QObject::connect(sudo.data(), static_cast(&QProcess::finished) + , [&app, &ret, &last_line, &dlg] (int exitCode, QProcess::ExitStatus exitStatus) + { + ret = QProcess::NormalExit == exitStatus ? exitCode : 255; + if (0 != ret && last_line.startsWith(QStringLiteral("%1:").arg(sudo_prog))) + QMessageBox(QMessageBox::Critical, dlg.windowTitle() + , QObject::tr("Child '%1' process failed!\n%2").arg(sudo_prog).arg(last_line), QMessageBox::Ok).exec(); + app.quit(); + }); + + QObject::connect(sudo.data(), &QProcess::readyReadStandardError, [&sudo, &dlg, &last_line] + { + QByteArray err = sudo->readAllStandardError(); + if (sudo_pwd_prompt == err.constData()) + { + dlg.show(); + return; + } + + QTextStream{stderr, QIODevice::WriteOnly} << err; + int nl_pos = err.lastIndexOf('\n'); + if (-1 == nl_pos) + last_line += err; + else + { + if (err.endsWith('\n')) + err.remove(err.size() - 1, 1); + nl_pos = err.lastIndexOf('\n'); + if (-1 != nl_pos) + err.remove(0, nl_pos + 1); + last_line = err; + } + }); + + //forward all stdin to child + QTextStream std_in{stdin, QIODevice::ReadOnly}; + QSocketNotifier stdin_watcher{0/*stdin*/, QSocketNotifier::Read}; + QObject::connect(&stdin_watcher, &QSocketNotifier::activated, [&std_in, &sudo] + { + QString line{std_in.readLine()}; + if (!std_in.atEnd()) + line += QLatin1Char('\n'); + sudo->write(line.toStdString().c_str()); + if (std_in.atEnd()) + sudo->closeWriteChannel(); + }); + + sudo->start(sudo_prog, QStringList() << QStringLiteral("-S") + << QStringLiteral("-p") << sudo_pwd_prompt + << args); + app.exec(); + + sudo->waitForFinished(-1); + return ret; +} + +int main(int argc, char **argv) +{ + // Quit gracefully + ::signal(SIGALRM, termSignalHandler); + ::signal(SIGTERM, termSignalHandler); + ::signal(SIGINT, termSignalHandler); + ::signal(SIGQUIT, termSignalHandler); + ::signal(SIGHUP, termSignalHandler); + ::signal(SIGSTOP, termSignalHandler); + ::signal(SIGTSTP, termSignalHandler); + + return master(argc, argv); +} diff --git a/man/lxqt-sudo.1 b/man/lxqt-sudo.1 new file mode 100644 index 0000000..333ca12 --- /dev/null +++ b/man/lxqt-sudo.1 @@ -0,0 +1,17 @@ +.TH lxqt-sudo 1 "" "" "LXQt\ Module" +.SH NAME +\fBlxqt-sudo\fR \- execute a command as privileged user +.SH SYNOPSIS +\fBlxqt-sudo\fR \fIcommand\fR [\fIarguments\fR] +.SH DESCRIPTION +\fBlxqt-sudo\fR is a graphical QT frontend for plain \fBsudo(8)\fR (for requesting optional password in GUI fashion). +.br +When invoked it simply spawns child \fIsudo\fR process with requested \fIcommand\fR (and \fIarguments\fR). If \fIsudo\fR requests user's password, +the GUI password dialog is shown and (after submit) the password is provided to \fIsudo\fR. +.SH "REPORTING BUGS" +Report bugs to https://github.com/lxde/lxqt/issues +.SH "SEE ALSO" +\fBsudo(8)\fR +.SH AUTHOR +This manual page was created by \fBPalo Kisa\fR \fI\fR +for \fBLXQt\fR project. diff --git a/passworddialog.cpp b/passworddialog.cpp new file mode 100644 index 0000000..7b6de2a --- /dev/null +++ b/passworddialog.cpp @@ -0,0 +1,62 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2015 LXQt team + * Authors: + * Palo Kisa + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "passworddialog.h" +#include "ui_passworddialog.h" + +PasswordDialog::PasswordDialog(QStringList argv + , QWidget * parent/* = 0*/ + , Qt::WindowFlags f/* = 0*/) + : QDialog(parent, f) + , ui(new Ui::PasswordDialog) +{ + ui->setupUi(this); + + ui->commandL->setText(argv.join(QStringLiteral(" "))); + QString cmd; + if (0 < argv.size()) + cmd = argv[0]; + ui->descriptionL->setText(tr("%1 needs administrative privileges.\nPlease enter your password.").arg(cmd)); + ui->iconL->setPixmap(QIcon::fromTheme("dialog-password").pixmap(64, 64)); + setWindowIcon(QIcon::fromTheme("security-high")); +} + +PasswordDialog::~PasswordDialog() +{ +} + +void PasswordDialog::showEvent(QShowEvent * event) +{ + ui->errorL->setText(tr("Attempt #%1").arg(++mAttempt)); + return QDialog::showEvent(event); +} + +QString PasswordDialog::password() const +{ + return ui->passwordLE->text(); +} + diff --git a/passworddialog.h b/passworddialog.h new file mode 100644 index 0000000..e6064ce --- /dev/null +++ b/passworddialog.h @@ -0,0 +1,59 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2015 LXQt team + * Authors: + * Palo Kisa + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef PASSWORDDIALOG_H +#define PASSWORDDIALOG_H + +#include + +namespace Ui { + class PasswordDialog; +} + +class Communication; +class QProcess; + +class PasswordDialog : public QDialog +{ + Q_OBJECT + +public: + PasswordDialog(QStringList argv + , QWidget * parent = 0 + , Qt::WindowFlags f = 0); + ~PasswordDialog(); + + virtual void showEvent(QShowEvent * event) override; + QString password() const; + +private: + QScopedPointer ui; + int mAttempt = 0; +}; + +#endif // PASSWORDDIALOG_H + diff --git a/passworddialog.ui b/passworddialog.ui new file mode 100644 index 0000000..f033daa --- /dev/null +++ b/passworddialog.ui @@ -0,0 +1,151 @@ + + + PasswordDialog + + + + 0 + 0 + 400 + 200 + + + + + 0 + 0 + + + + LXQt sudo + + + + + + + + + + + + + + + + + + true + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Command: + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + PasswordDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PasswordDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/translations/lxqt-sudo.ts b/translations/lxqt-sudo.ts new file mode 100644 index 0000000..466ddce --- /dev/null +++ b/translations/lxqt-sudo.ts @@ -0,0 +1,69 @@ + + + + + PasswordDialog + + + + LXQt sudo + + + + + + Command: + + + + + + Password: + + + + + <b>%1</b> needs administrative privileges. +Please enter your password. + + + + + Attempt #%1 + + + + + QObject + + + Usage: %1 command [arguments...] + +GUI frontend for %2 + +Arguments: + command Command to run. + arguments Optional arguments for command. + + + + + + + %1 version %2 + + + + + + %1: no command to run provided! + + + + + Child '%1' process failed! +%2 + + + + diff --git a/translations/lxqt-sudo_sk.ts b/translations/lxqt-sudo_sk.ts new file mode 100644 index 0000000..b2103ab --- /dev/null +++ b/translations/lxqt-sudo_sk.ts @@ -0,0 +1,80 @@ + + + + + PasswordDialog + + + + LXQt sudo + LXQt sudo + + + + + Command: + Príkaz: + + + + + Password: + Heslo: + + + + <b>%1</b> needs administrative privileges. +Please enter your password. + <b>%1</b> vyžaduje práva administrátora. +Prosím, zadajte svoje heslo. + + + + Attempt #%1 + Pokus č. %1 + + + + QObject + + + Usage: %1 command [arguments...] + +GUI frontend for %2 + +Arguments: + command Command to run. + arguments Optional arguments for command. + + + Použitie: %1 command [arguments...] + +GUI frontend pre %2 + +Parametre: + command Príkaz na spustenie. + arguments Parametre príkazu. + + + + + + %1 version %2 + + %1 verzia %2 + + + + + %1: no command to run provided! + %1: žiaden príkaz na spustenie! + + + + Child '%1' process failed! +%2 + Dcérsky '%1' process zlyhal! +%2 + + +