File indexing completed on 2024-05-19 05:54:13

0001 /*  This file was part of the KDE libraries
0002 
0003     SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "sshmanagerplugin.h"
0009 
0010 #include "sshmanagermodel.h"
0011 #include "sshmanagerpluginwidget.h"
0012 
0013 #include "ProcessInfo.h"
0014 #include "konsoledebug.h"
0015 #include "session/SessionController.h"
0016 
0017 #include <QDockWidget>
0018 #include <QListView>
0019 #include <QMainWindow>
0020 #include <QMenuBar>
0021 #include <QSortFilterProxyModel>
0022 #include <QStandardItemModel>
0023 #include <QTimer>
0024 
0025 #include <KActionCollection>
0026 #include <KCommandBar>
0027 #include <KCrash>
0028 #include <KLocalizedString>
0029 #include <KMessageBox>
0030 #include <QSettings>
0031 #include <kcommandbar.h>
0032 
0033 #include "MainWindow.h"
0034 #include "terminalDisplay/TerminalDisplay.h"
0035 
0036 K_PLUGIN_CLASS_WITH_JSON(SSHManagerPlugin, "konsole_sshmanager.json")
0037 
0038 struct SSHManagerPluginPrivate {
0039     SSHManagerModel model;
0040 
0041     QMap<Konsole::MainWindow *, SSHManagerTreeWidget *> widgetForWindow;
0042     QMap<Konsole::MainWindow *, QDockWidget *> dockForWindow;
0043     QAction *showQuickAccess = nullptr;
0044 };
0045 
0046 SSHManagerPlugin::SSHManagerPlugin(QObject *object, const QVariantList &args)
0047     : Konsole::IKonsolePlugin(object, args)
0048     , d(std::make_unique<SSHManagerPluginPrivate>())
0049 {
0050     d->showQuickAccess = new QAction();
0051 
0052     setName(QStringLiteral("SshManager"));
0053     KCrash::initialize();
0054 }
0055 
0056 SSHManagerPlugin::~SSHManagerPlugin()
0057 {
0058 }
0059 
0060 void SSHManagerPlugin::createWidgetsForMainWindow(Konsole::MainWindow *mainWindow)
0061 {
0062     auto *sshDockWidget = new QDockWidget(mainWindow);
0063     auto *managerWidget = new SSHManagerTreeWidget();
0064     managerWidget->setModel(&d->model);
0065     sshDockWidget->setWidget(managerWidget);
0066     sshDockWidget->setWindowTitle(i18n("SSH Manager"));
0067     sshDockWidget->setObjectName(QStringLiteral("SSHManagerDock"));
0068     sshDockWidget->setVisible(false);
0069     sshDockWidget->setAllowedAreas(Qt::DockWidgetArea::LeftDockWidgetArea | Qt::DockWidgetArea::RightDockWidgetArea);
0070 
0071     mainWindow->addDockWidget(Qt::LeftDockWidgetArea, sshDockWidget);
0072 
0073     d->widgetForWindow[mainWindow] = managerWidget;
0074     d->dockForWindow[mainWindow] = sshDockWidget;
0075 
0076     connect(managerWidget, &SSHManagerTreeWidget::requestNewTab, this, [mainWindow] {
0077         mainWindow->newTab();
0078     });
0079 
0080     connect(managerWidget, &SSHManagerTreeWidget::quickAccessShortcutChanged, this, [this, mainWindow](QKeySequence s) {
0081         mainWindow->actionCollection()->setDefaultShortcut(d->showQuickAccess, s);
0082 
0083         QString sequenceText = s.toString();
0084         QSettings settings;
0085         settings.beginGroup(QStringLiteral("plugins"));
0086         settings.beginGroup(QStringLiteral("sshplugin"));
0087         settings.setValue(QStringLiteral("ssh_shortcut"), sequenceText);
0088         settings.sync();
0089     });
0090 }
0091 
0092 QList<QAction *> SSHManagerPlugin::menuBarActions(Konsole::MainWindow *mainWindow) const
0093 {
0094     Q_UNUSED(mainWindow)
0095 
0096     QAction *toggleVisibilityAction = new QAction(i18n("Show SSH Manager"), mainWindow);
0097     toggleVisibilityAction->setCheckable(true);
0098     mainWindow->actionCollection()->setDefaultShortcut(toggleVisibilityAction, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_F2));
0099     connect(toggleVisibilityAction, &QAction::triggered, d->dockForWindow[mainWindow], &QDockWidget::setVisible);
0100     connect(d->dockForWindow[mainWindow], &QDockWidget::visibilityChanged, toggleVisibilityAction, &QAction::setChecked);
0101 
0102     return {toggleVisibilityAction};
0103 }
0104 
0105 #include <iostream>
0106 
0107 void SSHManagerPlugin::activeViewChanged(Konsole::SessionController *controller, Konsole::MainWindow *mainWindow)
0108 {
0109     Q_ASSERT(controller);
0110     Q_ASSERT(mainWindow);
0111 
0112     auto terminalDisplay = controller->view();
0113 
0114     d->showQuickAccess->deleteLater();
0115     d->showQuickAccess = new QAction(i18n("Show Quick Access for SSH Actions"));
0116 
0117     QSettings settings;
0118     settings.beginGroup(QStringLiteral("plugins"));
0119     settings.beginGroup(QStringLiteral("sshplugin"));
0120 
0121     const QKeySequence def(Qt::CTRL | Qt::ALT | Qt::Key_H);
0122     const QString defText = def.toString();
0123     const QString entry = settings.value(QStringLiteral("ssh_shortcut"), defText).toString();
0124     const QKeySequence shortcutEntry(entry);
0125 
0126     mainWindow->actionCollection()->setDefaultShortcut(d->showQuickAccess, shortcutEntry);
0127     terminalDisplay->addAction(d->showQuickAccess);
0128 
0129     connect(d->showQuickAccess, &QAction::triggered, this, [this, terminalDisplay, controller] {
0130         auto bar = new KCommandBar(terminalDisplay->topLevelWidget());
0131         QList<QAction *> actions;
0132         for (int i = 0; i < d->model.rowCount(); i++) {
0133             QModelIndex folder = d->model.index(i, 0);
0134             for (int e = 0; e < d->model.rowCount(folder); e++) {
0135                 QModelIndex idx = d->model.index(e, 0, folder);
0136                 QAction *act = new QAction(idx.data().toString());
0137                 connect(act, &QAction::triggered, this, [this, idx, controller] {
0138                     requestConnection(nullptr, &d->model, controller, idx);
0139                 });
0140                 actions.append(act);
0141             }
0142         }
0143 
0144         if (actions.isEmpty()) // no ssh config found, must give feedback to the user about that
0145         {
0146             const QString feedbackMessage = i18n("No saved SSH config found. You can add one on Plugins -> SSH Manager");
0147             const QString feedbackTitle = i18n("Plugins - SSH Manager");
0148             KMessageBox::error(terminalDisplay->topLevelWidget(), feedbackMessage, feedbackTitle);
0149             return;
0150         }
0151 
0152         QVector<KCommandBar::ActionGroup> groups;
0153         groups.push_back(KCommandBar::ActionGroup{i18n("SSH Entries"), actions});
0154         bar->setActions(groups);
0155         bar->show();
0156     });
0157 
0158     if (mainWindow) {
0159         d->widgetForWindow[mainWindow]->setCurrentController(controller);
0160     }
0161 }
0162 
0163 void SSHManagerPlugin::requestConnection(QSortFilterProxyModel *filterModel,
0164                                          QStandardItemModel *model,
0165                                          Konsole::SessionController *controller,
0166                                          const QModelIndex &idx)
0167 {
0168     if (!controller) {
0169         return;
0170     }
0171 
0172     auto sourceIdx = filterModel ? filterModel->mapToSource(idx) : idx;
0173     if (sourceIdx.parent() == model->invisibleRootItem()->index()) {
0174         return;
0175     }
0176 
0177 #ifndef Q_OS_WIN
0178     Konsole::ProcessInfo *info = controller->session()->getProcessInfo();
0179     bool ok = false;
0180     QString processName = info->name(&ok);
0181     if (!ok) {
0182         KMessageBox::error(nullptr, i18n("Could not get the process name, assume that we can't request a connection"), i18n("Error issuing SSH Command"));
0183         return;
0184     }
0185 
0186     if (!QVector<QString>({QStringLiteral("fish"),
0187                            QStringLiteral("bash"),
0188                            QStringLiteral("dash"),
0189                            QStringLiteral("sh"),
0190                            QStringLiteral("csh"),
0191                            QStringLiteral("ksh"),
0192                            QStringLiteral("zsh")})
0193              .contains(processName)) {
0194         KMessageBox::error(nullptr, i18n("Can't issue SSH command outside the shell application (eg, bash, zsh, sh)"), i18n("Error issuing SSH Command"));
0195         return;
0196     }
0197 #else
0198     // FIXME: Can we do this on windows?
0199 #endif
0200 
0201     auto item = model->itemFromIndex(sourceIdx);
0202     auto data = item->data(SSHManagerModel::SSHRole).value<SSHConfigurationData>();
0203 
0204     QString sshCommand = QStringLiteral("ssh ");
0205     if (!data.useSshConfig) {
0206         if (data.sshKey.length()) {
0207             sshCommand += QStringLiteral("-i %1 ").arg(data.sshKey);
0208         }
0209 
0210         if (data.port.length()) {
0211             sshCommand += QStringLiteral("-p %1 ").arg(data.port);
0212         }
0213 
0214         if (!data.username.isEmpty()) {
0215             sshCommand += data.username + QLatin1Char('@');
0216         }
0217     }
0218 
0219     if (!data.host.isEmpty()) {
0220         sshCommand += data.host;
0221     }
0222 
0223     controller->session()->sendTextToTerminal(sshCommand, QLatin1Char('\r'));
0224     if (controller->session()->views().count()) {
0225         controller->session()->views().at(0)->setFocus();
0226     }
0227 }
0228 
0229 #include "moc_sshmanagerplugin.cpp"
0230 #include "sshmanagerplugin.moc"