Compare commits
5 Commits
v0.5
...
Difrex/mas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99374da328 | ||
| 37b6f6d5e0 | |||
| 4fb25041f9 | |||
| 4ec5c96775 | |||
| 980f3ac9be |
30
LICENSE
Normal file
30
LICENSE
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
sshch
|
||||||
|
|
||||||
|
sshch is released under the DWTW license
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the terms of the Do What Thou Wilt License.
|
||||||
|
|
||||||
|
DO WHAT THAU WILT
|
||||||
|
TO PUBLIC LICENSE
|
||||||
|
|
||||||
|
Version 2.5
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. Do what thou wilt shall be the whole of the Law.
|
||||||
|
|
||||||
|
Anyone is allowed to copy and distribute the copies of this license agreement in whole or in part, as well as modify it without any other limitations.
|
||||||
|
|
||||||
|
DWTW – a license with a single requirement: DO WHAT THOU WILT
|
||||||
|
|
||||||
|
The license provides more freedom than any other one (such as GPL or BSD) and does not require saving the license text on copying.
|
||||||
|
|
||||||
|
DWTW – an accomplished and eligible license for free text (including the software, documentation and artwork).
|
||||||
|
|
||||||
|
The license does not contain "no warranty" clause. DWTW can be used in countries that do not legally acknowledge the transition to public domain.
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
|
||||||
|
An author-creator gives his or her source code to the world for free, without becoming distracted by worldly thinking regarding how and why the others will use it.
|
||||||
28
README.md
28
README.md
@@ -1,3 +1,25 @@
|
|||||||
Simpe python script for fast access to ssh hosts.
|
SSH connection manager with curses interface
|
||||||
|
======
|
||||||
under DWTWL 2.5 license: https://soundragon.su/license/license.html
|
sshch is released under DWTWL 2.5 license
|
||||||
|
### Screenshot
|
||||||
|

|
||||||
|
### Installing
|
||||||
|
To install for all users:
|
||||||
|
```
|
||||||
|
sudo python setup.py install
|
||||||
|
```
|
||||||
|
To install just for current user:
|
||||||
|
```
|
||||||
|
mkdir ~/.local/bin
|
||||||
|
cp sshch/sshch ~/.local/bin/
|
||||||
|
```
|
||||||
|
### Using
|
||||||
|
To run curses interface:
|
||||||
|
```
|
||||||
|
sshch
|
||||||
|
```
|
||||||
|
To run command line help:
|
||||||
|
```
|
||||||
|
sshch -h
|
||||||
|
```
|
||||||
|
**If you want to use unsafe 'password' feature you must install 'sshpass' first.**
|
||||||
35
setup.py
Normal file
35
setup.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""Setup script for sshch"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
setup(name='sshch',
|
||||||
|
author='zlaxy',
|
||||||
|
url='https://github.com/zlaxy/sshch/',
|
||||||
|
description='Ssh connection manager',
|
||||||
|
license='DWTWL 2.5',
|
||||||
|
version='0.55',
|
||||||
|
py_modules=['sshch'],
|
||||||
|
scripts=['sshch/sshch'],
|
||||||
|
|
||||||
|
# http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 4 - Beta',
|
||||||
|
'Environment :: Console :: Curses',
|
||||||
|
'Intended Audience :: System Administrators',
|
||||||
|
'License :: Freeware',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: POSIX',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Topic :: Internet',
|
||||||
|
'Topic :: System :: Networking',
|
||||||
|
'Topic :: System :: Systems Administration',
|
||||||
|
'Topic :: Utilities'])
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.exit(main())
|
||||||
215
sshch.py → sshch/sshch
Normal file → Executable file
215
sshch.py → sshch/sshch
Normal file → Executable file
@@ -4,20 +4,21 @@
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
from os import path
|
from os import path
|
||||||
from sys import argv
|
from sys import argv
|
||||||
from math import *
|
from math import ceil
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from curses import textpad, panel
|
from curses import textpad
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
import subprocess
|
import subprocess
|
||||||
import base64
|
import base64
|
||||||
import curses
|
import curses
|
||||||
|
|
||||||
# https://github.com/zlaxy/sshch
|
# https://github.com/zlaxy/sshch
|
||||||
version="0.5"
|
version = "0.55"
|
||||||
# path to conf file, default: ~/.config/sshch.conf
|
# path to conf file, default: ~/.config/sshch.conf
|
||||||
conf_file = path.expanduser("~") + '/.config/sshch.conf'
|
conf_file = path.expanduser("~") + '/.config/sshch.conf'
|
||||||
|
|
||||||
|
|
||||||
def AddNewAlias(alias):
|
def AddNewAlias(alias):
|
||||||
if not conf.has_section(alias):
|
if not conf.has_section(alias):
|
||||||
conf.add_section(alias)
|
conf.add_section(alias)
|
||||||
@@ -26,21 +27,25 @@ def AddNewAlias(alias):
|
|||||||
else:
|
else:
|
||||||
return "error: '" + alias + "' already exists"
|
return "error: '" + alias + "' already exists"
|
||||||
|
|
||||||
|
|
||||||
def SetAliasString(alias, string):
|
def SetAliasString(alias, string):
|
||||||
conf.set(alias, "exec_string", string)
|
conf.set(alias, "exec_string", string)
|
||||||
conf.write(open(conf_file, "w"))
|
conf.write(open(conf_file, "w"))
|
||||||
|
|
||||||
|
|
||||||
def SetPassword(alias, string):
|
def SetPassword(alias, string):
|
||||||
string = base64.b64encode(base64.b16encode(
|
string = base64.b64encode(base64.b16encode(
|
||||||
base64.b32encode(string)))
|
base64.b32encode(string)))
|
||||||
conf.set(alias, "password", string)
|
conf.set(alias, "password", string)
|
||||||
conf.write(open(conf_file, "w"))
|
conf.write(open(conf_file, "w"))
|
||||||
|
|
||||||
|
|
||||||
def RemoveAliases(aliases):
|
def RemoveAliases(aliases):
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
conf.remove_section(alias)
|
conf.remove_section(alias)
|
||||||
conf.write(open(conf_file, "w"))
|
conf.write(open(conf_file, "w"))
|
||||||
|
|
||||||
|
|
||||||
def ConnectAlias(alias, command=False):
|
def ConnectAlias(alias, command=False):
|
||||||
print "Connecting to " + alias + "..."
|
print "Connecting to " + alias + "..."
|
||||||
exec_string = ""
|
exec_string = ""
|
||||||
@@ -51,15 +56,17 @@ def ConnectAlias(alias, command=False):
|
|||||||
exec_string = exec_string + conf.get(alias, "exec_string")
|
exec_string = exec_string + conf.get(alias, "exec_string")
|
||||||
if command:
|
if command:
|
||||||
exec_string = exec_string + " " + command
|
exec_string = exec_string + " " + command
|
||||||
p = subprocess.Popen(exec_string, shell=True)
|
# Variables bellow is newer used
|
||||||
streamdata = p.communicate()[0]
|
subprocess.Popen(exec_string, shell=True)
|
||||||
|
# p.communicate()[0]
|
||||||
print "... " + alias + " session finished."
|
print "... " + alias + " session finished."
|
||||||
|
|
||||||
|
|
||||||
def CMDAdd(alias):
|
def CMDAdd(alias):
|
||||||
result = AddNewAlias(alias)
|
result = AddNewAlias(alias)
|
||||||
if result == True:
|
if result:
|
||||||
prompt_add = ("Enter connection string for new alias " +
|
prompt_add = ("".join(["Enter connection string for new alias ",
|
||||||
"(example: ssh user@somehost.com):\n")
|
"(example: ssh user@somehost.com):\n"]))
|
||||||
string = ""
|
string = ""
|
||||||
while string == "":
|
while string == "":
|
||||||
string = raw_input(prompt_add)
|
string = raw_input(prompt_add)
|
||||||
@@ -67,10 +74,11 @@ def CMDAdd(alias):
|
|||||||
else:
|
else:
|
||||||
print result
|
print result
|
||||||
|
|
||||||
|
|
||||||
def CMDEdit(alias):
|
def CMDEdit(alias):
|
||||||
if conf.has_section(alias):
|
if conf.has_section(alias):
|
||||||
prompt_edit = ("Enter connection string for existing alias " +
|
prompt_edit = ("".join(["Enter connection string for existing alias ",
|
||||||
"(example: ssh user@somehost.com):\n")
|
"(example: ssh user@somehost.com):\n"]))
|
||||||
string = ""
|
string = ""
|
||||||
while string == "":
|
while string == "":
|
||||||
string = raw_input(prompt_edit)
|
string = raw_input(prompt_edit)
|
||||||
@@ -78,19 +86,21 @@ def CMDEdit(alias):
|
|||||||
else:
|
else:
|
||||||
print "error: '" + alias + "' alias is not exists"
|
print "error: '" + alias + "' alias is not exists"
|
||||||
|
|
||||||
|
|
||||||
def CMDPassword(alias):
|
def CMDPassword(alias):
|
||||||
if conf.has_section(alias):
|
if conf.has_section(alias):
|
||||||
prompt_pass = ("[UNSAFE] Enter password for sshpass: ")
|
prompt_pass = ("[UNSAFE] Enter password for sshpass: ")
|
||||||
string = ""
|
string = ""
|
||||||
string = getpass(prompt_pass)
|
string = getpass(prompt_pass)
|
||||||
if not string == "": SetPassword(alias, string)
|
if not string == "":
|
||||||
|
SetPassword(alias, string)
|
||||||
else:
|
else:
|
||||||
print "error: '" + alias + "' alias is not exists"
|
print "error: '" + alias + "' alias is not exists"
|
||||||
|
|
||||||
|
|
||||||
def CMDRemove(alias):
|
def CMDRemove(alias):
|
||||||
if conf.has_section(alias):
|
if conf.has_section(alias):
|
||||||
prompt_remove = ("Type 'yes' if you sure to remove '" +
|
prompt_remove = ("Type 'yes' if you sure to remove '" + alias + "' alias: ")
|
||||||
alias + "' alias: ")
|
|
||||||
string = raw_input(prompt_remove)
|
string = raw_input(prompt_remove)
|
||||||
if string == "yes":
|
if string == "yes":
|
||||||
RemoveAliases([alias])
|
RemoveAliases([alias])
|
||||||
@@ -99,6 +109,7 @@ def CMDRemove(alias):
|
|||||||
else:
|
else:
|
||||||
print "error: '" + alias + "' alias is not exists."
|
print "error: '" + alias + "' alias is not exists."
|
||||||
|
|
||||||
|
|
||||||
def CMDConnect(aliases, command=False):
|
def CMDConnect(aliases, command=False):
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
if conf.has_section(alias):
|
if conf.has_section(alias):
|
||||||
@@ -106,13 +117,17 @@ def CMDConnect(aliases, command=False):
|
|||||||
else:
|
else:
|
||||||
print "error: '" + alias + "' alias is not exists"
|
print "error: '" + alias + "' alias is not exists"
|
||||||
|
|
||||||
|
|
||||||
def CMDList(option, opt, value, parser):
|
def CMDList(option, opt, value, parser):
|
||||||
print ', '.join(str(p) for p in conf.sections())
|
print ', '.join(str(p) for p in conf.sections())
|
||||||
|
|
||||||
|
|
||||||
def CMDFullList(option, opt, value, parser):
|
def CMDFullList(option, opt, value, parser):
|
||||||
print '\n'.join((str(p) + " - " + conf.get(p, "exec_string") +
|
for p in conf.sections():
|
||||||
(" [password]" if conf.has_option(p, "password") else ""))
|
to_print = "".join([str(p), " - ", conf.get(p, "exec_string"),
|
||||||
for p in conf.sections())
|
(" [password]" if conf.has_option(p, "password") else ""), "\n"])
|
||||||
|
print(to_print)
|
||||||
|
|
||||||
|
|
||||||
def CursesConnect(screen, aliases, command=False):
|
def CursesConnect(screen, aliases, command=False):
|
||||||
curses.endwin()
|
curses.endwin()
|
||||||
@@ -121,16 +136,20 @@ def CursesConnect(screen, aliases, command=False):
|
|||||||
print "Press 'enter' to continue."
|
print "Press 'enter' to continue."
|
||||||
screen.getch()
|
screen.getch()
|
||||||
|
|
||||||
|
|
||||||
def CursesExit(error=False):
|
def CursesExit(error=False):
|
||||||
curses.endwin()
|
curses.endwin()
|
||||||
if error: print error
|
if error:
|
||||||
|
print error
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
def CursesTextpadConfirm(value):
|
def CursesTextpadConfirm(value):
|
||||||
if value == 10:
|
if value == 10:
|
||||||
value = 7
|
value = 7
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def CursesTextpad(screen, h, w, y, x, title="", value="",
|
def CursesTextpad(screen, h, w, y, x, title="", value="",
|
||||||
text_colorpair=0, deco_colorpair=0):
|
text_colorpair=0, deco_colorpair=0):
|
||||||
new_window = curses.newwin(h + 3, w + 2, y - 1, x - 1)
|
new_window = curses.newwin(h + 3, w + 2, y - 1, x - 1)
|
||||||
@@ -147,6 +166,7 @@ def CursesTextpad(screen, h, w, y, x, title="", value="",
|
|||||||
sub_window.attron(text_colorpair)
|
sub_window.attron(text_colorpair)
|
||||||
return textbox_field
|
return textbox_field
|
||||||
|
|
||||||
|
|
||||||
def CursesPanel(screen, h, w, y, x, text,
|
def CursesPanel(screen, h, w, y, x, text,
|
||||||
text_colorpair=0, deco_colorpair=0, confirm=0):
|
text_colorpair=0, deco_colorpair=0, confirm=0):
|
||||||
new_window = curses.newwin(h, w, y, x)
|
new_window = curses.newwin(h, w, y, x)
|
||||||
@@ -156,8 +176,7 @@ def CursesPanel(screen, h, w, y, x, text,
|
|||||||
new_window.attroff(deco_colorpair)
|
new_window.attroff(deco_colorpair)
|
||||||
sub_window = new_window.subwin(h - 2, w - 2, y + 1, x + 1)
|
sub_window = new_window.subwin(h - 2, w - 2, y + 1, x + 1)
|
||||||
sub_window.insstr(0, 0, text)
|
sub_window.insstr(0, 0, text)
|
||||||
# sub_window.addnstr(0, 0, text, ((h - 2) * (w - 2) - 1))
|
curses.panel.new_panel(new_window)
|
||||||
panel = curses.panel.new_panel(new_window)
|
|
||||||
curses.panel.update_panels()
|
curses.panel.update_panels()
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
if confirm == "password":
|
if confirm == "password":
|
||||||
@@ -194,23 +213,25 @@ def CursesPanel(screen, h, w, y, x, text,
|
|||||||
else:
|
else:
|
||||||
screen.getch()
|
screen.getch()
|
||||||
|
|
||||||
|
|
||||||
def CMDOptions():
|
def CMDOptions():
|
||||||
class FormatedParser(OptionParser):
|
class FormatedParser(OptionParser):
|
||||||
|
|
||||||
def format_epilog(self, formatter):
|
def format_epilog(self, formatter):
|
||||||
return self.epilog
|
return self.epilog
|
||||||
usage = "usage: %prog [options] [aliases]"
|
usage = "usage: %prog [options] [aliases]"
|
||||||
progname = path.basename(__file__)
|
progname = path.basename(__file__)
|
||||||
epilog = ("Examples:\n " +
|
epilog = ("".join(["Examples:\n ",
|
||||||
progname + " existingalias\n " +
|
progname, " existingalias\n ",
|
||||||
progname + " -a newremoteserver\n " +
|
progname, " -a newremoteserver\n ",
|
||||||
progname + " --edit=newremoteserver -p newremoteserver\n " +
|
progname, " --edit=newremoteserver -p newremoteserver\n ",
|
||||||
progname + ' -c "ls -l" newremoteserver\n ' +
|
progname, ' -c "ls -l" newremoteserver\n ',
|
||||||
progname + " -c reboot existingalias newremoteserver\n"
|
progname, " -c reboot existingalias newremoteserver\n",
|
||||||
"Examples of connection string:\n " +
|
"Examples of connection string:\n ",
|
||||||
"ssh user@somehost.com\n " +
|
"ssh user@somehost.com\n ",
|
||||||
"ssh gates@8.8.8.8 -p 667\n " +
|
"ssh gates@8.8.8.8 -p 667\n ",
|
||||||
"ssh root@somehost.com -t tmux a\n" +
|
"ssh root@somehost.com -t tmux a\n",
|
||||||
"Also, you can edit config file manually: " + conf_file + "\n")
|
"Also, you can edit config file manually: ", conf_file, "\n"]))
|
||||||
opts = FormatedParser(usage=usage, version="%prog " + version,
|
opts = FormatedParser(usage=usage, version="%prog " + version,
|
||||||
epilog=epilog)
|
epilog=epilog)
|
||||||
opts.add_option('-l', '--list', action="callback",
|
opts.add_option('-l', '--list', action="callback",
|
||||||
@@ -234,27 +255,34 @@ def CMDOptions():
|
|||||||
dest='remove', metavar="alias", default=False,
|
dest='remove', metavar="alias", default=False,
|
||||||
help="remove existing alias of connection string")
|
help="remove existing alias of connection string")
|
||||||
options, alias = opts.parse_args()
|
options, alias = opts.parse_args()
|
||||||
if options.add: CMDAdd(options.add)
|
if options.add:
|
||||||
if options.edit: CMDEdit(options.edit)
|
CMDAdd(options.add)
|
||||||
if options.password: CMDPassword(options.password)
|
if options.edit:
|
||||||
if options.remove: CMDRemove(options.remove)
|
CMDEdit(options.edit)
|
||||||
if alias: CMDConnect(alias, options.command)
|
if options.password:
|
||||||
|
CMDPassword(options.password)
|
||||||
|
if options.remove:
|
||||||
|
CMDRemove(options.remove)
|
||||||
|
if alias:
|
||||||
|
CMDConnect(alias, options.command)
|
||||||
|
|
||||||
# curses template from: https://stackoverflow.com/a/30828805/6224462
|
# curses template from: https://stackoverflow.com/a/30828805/6224462
|
||||||
|
|
||||||
|
|
||||||
def CursesMain():
|
def CursesMain():
|
||||||
help_screen = (" Press:\n" +
|
help_screen = ("".join([" Press:\n",
|
||||||
" 'z'/'x' or arrows - navigation\n" +
|
" 'z'/'x' or arrows - navigation\n",
|
||||||
" 'a'/'F2' - add new alias\n" +
|
" 'a'/'F2' - add new alias\n",
|
||||||
" 'e'/'F4' - edit existing alias\n" +
|
" 'e'/'F4' - edit existing alias\n",
|
||||||
" 'p'/'F6' - set alias's password for sshpass [UNSAFE]\n" +
|
" 'p'/'F6' - set alias's password for sshpass [UNSAFE]\n",
|
||||||
" 'space'/'insert' - select\n" +
|
" 'space'/'insert' - select\n",
|
||||||
" 'r'/'F8' - remove selected alias/aliases\n" +
|
" 'r'/'F8' - remove selected alias/aliases\n",
|
||||||
" 'c'/'F3' - execute specific command with selected alias/aliases\n" +
|
" 'c'/'F3' - execute specific command with selected alias/aliases\n",
|
||||||
" 'enter'/'F9' - connect to selected alias/aliases\n" +
|
" 'enter'/'F9' - connect to selected alias/aliases\n",
|
||||||
" 'q'/'F10' - quit\n" +
|
" 'q'/'F10' - quit\n",
|
||||||
" Run program with '--help' option to view command line help.\n" +
|
" Run program with '--help' option to view command line help.\n",
|
||||||
" Also, you can edit config file manually:\n" +
|
" Also, you can edit config file manually:\n",
|
||||||
" " + conf_file)
|
" ", conf_file]))
|
||||||
strings = conf.sections()
|
strings = conf.sections()
|
||||||
row_num = len(strings)
|
row_num = len(strings)
|
||||||
selected_strings = [" " for i in range(0, row_num + 1)]
|
selected_strings = [" " for i in range(0, row_num + 1)]
|
||||||
@@ -279,21 +307,20 @@ def CursesMain():
|
|||||||
page = 1
|
page = 1
|
||||||
for i in range(1, max_row + 1):
|
for i in range(1, max_row + 1):
|
||||||
if row_num == 0:
|
if row_num == 0:
|
||||||
box.addnstr(1, 1, "There aren't any aliases yet. Press 'a'" +
|
box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.",
|
||||||
" to add new one.", width - 6, highlight_text)
|
width - 6, highlight_text)
|
||||||
else:
|
else:
|
||||||
|
if conf.has_option(strings[i - 1], "password"):
|
||||||
|
password = " [password]"
|
||||||
|
else:
|
||||||
|
password = ""
|
||||||
|
exec_string = ["[", selected_strings[i], "] ", str(i), " ",
|
||||||
|
strings[i - 1], " (", conf.get(strings[i - 1], "exec_string"),
|
||||||
|
")", password]
|
||||||
if (i == position):
|
if (i == position):
|
||||||
box.addnstr(i, 2, "[" + selected_strings[i] + "] " +
|
box.addnstr(i, 2, "".join(exec_string), width - 6, highlight_text)
|
||||||
str(i) + " " + strings[i - 1] + " (" +
|
|
||||||
conf.get(strings[i - 1], "exec_string") + ")" +
|
|
||||||
(" [password]" if conf.has_option(strings[i - 1],
|
|
||||||
"password") else ""), width - 6, highlight_text)
|
|
||||||
else:
|
else:
|
||||||
box.addnstr(i, 2, "[" + selected_strings[i] + "] " +
|
box.addnstr(i, 2, "".join(exec_string), width - 6, normal_text)
|
||||||
str(i) + " " + strings[i - 1] + " (" +
|
|
||||||
conf.get(strings[i - 1], "exec_string") + ")" +
|
|
||||||
(" [password]" if conf.has_option(strings[i - 1],
|
|
||||||
"password") else ""), width - 6, normal_text)
|
|
||||||
if i == row_num:
|
if i == row_num:
|
||||||
break
|
break
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
@@ -316,7 +343,8 @@ def CursesMain():
|
|||||||
add_alias = new_alias_textpad.edit(CursesTextpadConfirm)
|
add_alias = new_alias_textpad.edit(CursesTextpadConfirm)
|
||||||
if not add_alias.rstrip() == "":
|
if not add_alias.rstrip() == "":
|
||||||
add_result = AddNewAlias(add_alias.rstrip())
|
add_result = AddNewAlias(add_alias.rstrip())
|
||||||
if not add_result == True: CursesPanel(screen, 3,
|
if not add_result:
|
||||||
|
CursesPanel(screen, 3,
|
||||||
width - 6, (height // 2) - 1, 3, add_result,
|
width - 6, (height // 2) - 1, 3, add_result,
|
||||||
normal_text, highlight_text)
|
normal_text, highlight_text)
|
||||||
else:
|
else:
|
||||||
@@ -352,8 +380,8 @@ def CursesMain():
|
|||||||
set_password = ""
|
set_password = ""
|
||||||
set_password = CursesPanel(screen, 4, width - 6,
|
set_password = CursesPanel(screen, 4, width - 6,
|
||||||
(height // 2) - 1, 3,
|
(height // 2) - 1, 3,
|
||||||
" Enter user password for sshpass and press 'enter':" +
|
" Enter user password for sshpass and press 'enter':\n>",
|
||||||
"\n>", normal_text, highlight_text, "password")
|
normal_text, highlight_text, "password")
|
||||||
if not set_password == "":
|
if not set_password == "":
|
||||||
SetPassword(strings[position - 1], set_password)
|
SetPassword(strings[position - 1], set_password)
|
||||||
if (key_pressed == ord('r') or key_pressed == ord(
|
if (key_pressed == ord('r') or key_pressed == ord(
|
||||||
@@ -364,11 +392,12 @@ def CursesMain():
|
|||||||
if selected_strings[i] == "*":
|
if selected_strings[i] == "*":
|
||||||
selected.append(strings[i - 1])
|
selected.append(strings[i - 1])
|
||||||
if len(selected) > 0:
|
if len(selected) > 0:
|
||||||
remove_confirm = ("Are you sure to remove " +
|
remove_confirm = (
|
||||||
str(len(selected)) + " selected aliases? (y/N)")
|
"".join(["Are you sure to remove ",
|
||||||
|
str(len(selected)), " selected aliases? (y/N)"]))
|
||||||
else:
|
else:
|
||||||
remove_confirm = ("Are you sure to remove '" +
|
remove_confirm = ("".join(["Are you sure to remove '",
|
||||||
strings[position - 1] + "' alias? (y/N)")
|
strings[position - 1], "' alias? (y/N)"]))
|
||||||
selected.append(strings[position - 1])
|
selected.append(strings[position - 1])
|
||||||
remove_result = CursesPanel(screen, 4, width - 6,
|
remove_result = CursesPanel(screen, 4, width - 6,
|
||||||
(height // 2) - 1, 3, remove_confirm, normal_text,
|
(height // 2) - 1, 3, remove_confirm, normal_text,
|
||||||
@@ -392,8 +421,10 @@ def CursesMain():
|
|||||||
selected.append(strings[position - 1])
|
selected.append(strings[position - 1])
|
||||||
command_textpad = CursesTextpad(screen, 3, width - 8,
|
command_textpad = CursesTextpad(screen, 3, width - 8,
|
||||||
(height // 2) - 1, 4,
|
(height // 2) - 1, 4,
|
||||||
"Enter specific command to execute with selected " +
|
"".join([
|
||||||
"alias/aliases:", "", normal_text, highlight_text)
|
"Enter specific command to execute with selected ",
|
||||||
|
"alias/aliases:"]
|
||||||
|
), "", normal_text, highlight_text)
|
||||||
command_string = command_textpad.edit(CursesTextpadConfirm)
|
command_string = command_textpad.edit(CursesTextpadConfirm)
|
||||||
CursesConnect(screen, selected,
|
CursesConnect(screen, selected,
|
||||||
command_string.replace("\n", "").rstrip())
|
command_string.replace("\n", "").rstrip())
|
||||||
@@ -410,7 +441,8 @@ def CursesMain():
|
|||||||
curses.KEY_IC)) and row_num != 0:
|
curses.KEY_IC)) and row_num != 0:
|
||||||
if selected_strings[position] == ' ':
|
if selected_strings[position] == ' ':
|
||||||
selected_strings[position] = '*'
|
selected_strings[position] = '*'
|
||||||
else: selected_strings[position] = ' '
|
else:
|
||||||
|
selected_strings[position] = ' '
|
||||||
if page == 1:
|
if page == 1:
|
||||||
if position < i:
|
if position < i:
|
||||||
position = position + 1
|
position = position + 1
|
||||||
@@ -472,25 +504,22 @@ def CursesMain():
|
|||||||
for i in range(1 + (max_row * (page - 1)), max_row + 1 +
|
for i in range(1 + (max_row * (page - 1)), max_row + 1 +
|
||||||
(max_row * (page - 1))):
|
(max_row * (page - 1))):
|
||||||
if row_num == 0:
|
if row_num == 0:
|
||||||
box.addnstr(1, 1, "There aren't any aliases yet. " +
|
box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.",
|
||||||
"Press 'a' to add new one.", width - 6,
|
width - 6, highlight_text)
|
||||||
highlight_text)
|
|
||||||
else:
|
else:
|
||||||
if (i + (max_row * (page - 1)) == (position +
|
if conf.has_option(strings[i - 1], "password"):
|
||||||
(max_row * (page - 1)))):
|
password = " [password]"
|
||||||
box.addnstr(i - (max_row * (page - 1)), 2, "[" +
|
|
||||||
selected_strings[i] + "] " + str(i) + " " +
|
|
||||||
strings[i - 1] + " (" + conf.get(strings[i - 1],
|
|
||||||
"exec_string") + ")" + (" [password]" if
|
|
||||||
conf.has_option(strings[i - 1], "password") else
|
|
||||||
""), width - 6, highlight_text)
|
|
||||||
else:
|
else:
|
||||||
box.addnstr(i - (max_row * (page - 1)), 2, "[" +
|
password = ""
|
||||||
selected_strings[i] + "] " + str(i) + " " +
|
exec_string = ["[", selected_strings[i], "] ", str(i), " ",
|
||||||
strings[i - 1] + " (" + conf.get(strings[i - 1],
|
strings[i - 1], " (", conf.get(strings[i - 1], "exec_string"),
|
||||||
"exec_string") + ")" + (" [password]" if
|
")", password]
|
||||||
conf.has_option(strings[i - 1], "password") else
|
if (i + (max_row * (page - 1)) == (position + (max_row * (page - 1)))):
|
||||||
""), width - 6, normal_text)
|
box.addnstr(i - (max_row * (page - 1)), 2, "".join(
|
||||||
|
exec_string), width - 6, highlight_text)
|
||||||
|
else:
|
||||||
|
box.addnstr(i - (max_row * (page - 1)), 2, "".join(
|
||||||
|
exec_string), width - 6, normal_text)
|
||||||
if i == row_num:
|
if i == row_num:
|
||||||
break
|
break
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
@@ -498,6 +527,7 @@ def CursesMain():
|
|||||||
key_pressed = screen.getch()
|
key_pressed = screen.getch()
|
||||||
CursesExit()
|
CursesExit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
conf = ConfigParser.RawConfigParser()
|
conf = ConfigParser.RawConfigParser()
|
||||||
if not path.exists(conf_file):
|
if not path.exists(conf_file):
|
||||||
@@ -509,8 +539,7 @@ if __name__ == "__main__":
|
|||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
exit()
|
exit()
|
||||||
except ConfigParser.Error:
|
except ConfigParser.Error:
|
||||||
print ("Error: can't parse your config file, please check" +
|
print ("Error: can't parse your config file, please check it manually or make new one")
|
||||||
" it manually or make new one")
|
|
||||||
exit()
|
exit()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@@ -518,8 +547,8 @@ if __name__ == "__main__":
|
|||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
CursesExit()
|
CursesExit()
|
||||||
except ConfigParser.NoOptionError:
|
except ConfigParser.NoOptionError:
|
||||||
CursesExit("Error: can't parse your config file, please " +
|
CursesExit("".join(["Error: can't parse your config file, please ",
|
||||||
"check it manually or make new one")
|
"check it manually or make new one"]))
|
||||||
except curses.error:
|
except curses.error:
|
||||||
CursesExit("Error: can't show some curses element, maybe " +
|
CursesExit("".join(["Error: can't show some curses element, maybe ",
|
||||||
"your terminal is too small")
|
"your terminal is too small"]))
|
||||||
BIN
sshch_screenshot.png
Normal file
BIN
sshch_screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Reference in New Issue
Block a user