sshch/sshch/sshch

809 lines
33 KiB
Plaintext
Raw Normal View History

2017-11-19 22:34:25 +00:00
#!/usr/bin/env python3
2017-07-15 15:11:06 +00:00
# -*- coding: utf-8 -*-
2017-07-18 17:18:16 +00:00
from __future__ import division
2017-11-19 22:34:25 +00:00
from __future__ import print_function
try:
import configparser
except ImportError:
import ConfigParser as configparser # Python 2.x import
2017-07-15 15:11:06 +00:00
from os import path
from sys import argv
2017-07-25 13:39:02 +00:00
from math import ceil
2017-07-16 10:12:20 +00:00
from getpass import getpass
2017-07-19 11:25:42 +00:00
from optparse import OptionParser
2017-07-15 15:11:06 +00:00
import subprocess
import base64
2017-07-25 14:21:54 +00:00
import time
2017-11-19 22:34:25 +00:00
import curses
from curses import textpad, panel
2017-07-15 15:11:06 +00:00
2017-07-16 10:12:20 +00:00
# https://github.com/zlaxy/sshch
version = "0.997"
2017-07-16 10:12:20 +00:00
# path to conf file, default: ~/.config/sshch.conf
2017-07-15 15:11:06 +00:00
conf_file = path.expanduser("~") + '/.config/sshch.conf'
2018-04-04 21:31:37 +00:00
# expand groups by default
expand_default = True
2017-07-15 15:11:06 +00:00
2017-07-25 13:39:02 +00:00
2017-07-18 17:18:16 +00:00
def AddNewAlias(alias):
if not conf.has_section(alias):
conf.add_section(alias)
conf.write(open(conf_file, "w"))
2017-07-19 11:25:42 +00:00
return True
2017-07-18 17:18:16 +00:00
else:
return "error: '" + alias + "' alias or group already exists"
2017-07-18 17:18:16 +00:00
2017-07-25 13:39:02 +00:00
2017-07-18 17:18:16 +00:00
def SetAliasString(alias, string):
conf.set(alias, "exec_string", string)
conf.write(open(conf_file, "w"))
2017-07-25 13:39:02 +00:00
2018-04-04 21:31:37 +00:00
def SetGroupString(alias, string):
conf.set(alias, "group", string)
conf.write(open(conf_file, "w"))
2017-07-18 17:18:16 +00:00
def SetPassword(alias, string):
string = base64.b64encode(base64.b16encode(
base64.b32encode(string)))
conf.set(alias, "password", string)
conf.write(open(conf_file, "w"))
2017-07-25 13:39:02 +00:00
2017-07-18 17:18:16 +00:00
def RemoveAliases(aliases):
for alias in aliases:
conf.remove_section(alias)
conf.write(open(conf_file, "w"))
2017-07-25 13:39:02 +00:00
2017-07-18 17:18:16 +00:00
def ConnectAlias(alias, command=False):
exec_string = ""
if conf.has_option(alias, "password"):
password = base64.b32decode(base64.b16decode(
2018-04-04 21:31:37 +00:00
base64.b64decode(conf.get(alias, "password"))))
exec_string = 'sshpass -p "' + password + '" '
if conf.has_option(alias, "exec_string"):
exec_string = exec_string + conf.get(alias, "exec_string")
2017-07-18 17:18:16 +00:00
if command:
exec_string = exec_string + " " + command
2017-07-25 14:21:54 +00:00
subprocess.Popen(exec_string, shell=True).communicate()[0]
2017-07-25 14:39:18 +00:00
2017-07-25 14:21:54 +00:00
def HoldConnection(alias):
2018-04-04 21:31:37 +00:00
groups = []
connectaliases = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
if alias in groups:
print("Can't hold connection with group.")
else:
print("Connecting to " + alias + ". Press CTRL+C to cancel.")
time.sleep(1)
while True:
ConnectAlias(alias)
time.sleep(5)
2017-07-18 17:18:16 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CMDAdd(alias):
alias = alias.split()[0].strip()
2017-07-19 11:25:42 +00:00
result = AddNewAlias(alias)
if result == True:
2017-07-25 13:39:02 +00:00
prompt_add = ("".join(["Enter connection string for new alias ",
"(example: ssh user@somehost.com):\n"]))
2017-07-19 11:25:42 +00:00
string = ""
while string == "":
2017-11-19 22:34:25 +00:00
string = input(prompt_add)
2017-07-19 11:25:42 +00:00
SetAliasString(alias, string)
else:
2017-11-19 22:34:25 +00:00
print(result)
2017-07-19 11:25:42 +00:00
2017-07-25 13:39:02 +00:00
2018-04-04 21:31:37 +00:00
def CMDGroup(group):
group = group.split()[0].strip()
2018-04-04 21:31:37 +00:00
result = AddNewAlias(group)
if result == True:
2018-04-04 21:31:37 +00:00
prompt_add = ("".join(["Enter aliases for new group ",
"(example: alias1 alias2):\n"]))
2017-07-19 11:25:42 +00:00
string = ""
while string == "":
2018-04-04 21:31:37 +00:00
string = input(prompt_add)
SetGroupString(group, string)
2017-07-19 11:25:42 +00:00
else:
2018-04-04 21:31:37 +00:00
print(result)
2017-07-19 11:25:42 +00:00
2017-07-25 13:39:02 +00:00
2018-04-04 21:31:37 +00:00
def CMDEdit(alias):
2017-07-19 11:25:42 +00:00
if conf.has_section(alias):
2018-04-04 21:31:37 +00:00
if conf.has_option(alias, "string"):
prompt_edit = ("".join(["Enter connection string for existing alias ",
"(example: ssh user@somehost.com):\n"]))
string = ""
while string == "":
string = input(prompt_edit)
SetAliasString(alias, string)
elif conf.has_option(alias, "group"):
prompt_edit = ("".join(["Enter aliases for existing group ",
"(example: alias1 alias2):\n"]))
string = ""
while string == "":
string = input(prompt_edit)
SetGroupString(alias, string)
else:
print("error: '" + alias + "' is not correct alias or group")
2017-07-19 11:25:42 +00:00
else:
2018-04-04 21:31:37 +00:00
print("error: '" + alias + "' alias or group does not exists")
def CMDPassword(alias):
groups = []
connectaliases = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
if alias in groups:
print("Can't set password for group.")
else:
if conf.has_section(alias):
prompt_pass = ("[UNSAFE] Enter password for sshpass: ")
string = ""
string = getpass(prompt_pass)
if not string == "":
SetPassword(alias, string)
else:
print("error: '" + alias + "' alias does not exists")
2017-07-19 11:25:42 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CMDRemove(alias):
if conf.has_section(alias):
2018-04-04 21:31:37 +00:00
prompt_remove = ("Type 'yes' if you sure to remove '" + alias + "' alias or group: ")
2017-11-19 22:34:25 +00:00
string = input(prompt_remove)
2017-07-19 11:25:42 +00:00
if string == "yes":
RemoveAliases([alias])
else:
2018-04-08 09:23:29 +00:00
print("'" + alias + "' alias or group was not deleted.")
2017-07-19 11:25:42 +00:00
else:
2018-04-04 21:31:37 +00:00
print("error: '" + alias + "' alias or group does not exists.")
2017-07-18 17:18:16 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CMDConnect(aliases, command=False):
2018-04-04 21:31:37 +00:00
groups = []
connectaliases = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
2017-07-16 10:12:20 +00:00
for alias in aliases:
2018-04-04 21:31:37 +00:00
if alias in groups:
group_aliases = conf.get(alias, "group").split()
for ga in group_aliases:
if not ga in connectaliases:
connectaliases.append(ga)
else:
if not alias in connectaliases:
connectaliases.append(alias)
for alias in connectaliases:
2017-07-16 10:12:20 +00:00
if conf.has_section(alias):
2017-11-19 22:34:25 +00:00
print("Connecting to " + alias + "...")
2017-07-19 11:25:42 +00:00
ConnectAlias(alias, command)
2017-11-19 22:34:25 +00:00
print("... " + alias + " session finished.")
2017-07-16 10:12:20 +00:00
else:
2018-04-04 21:31:37 +00:00
print("error: '" + alias + "' alias does not exists")
2017-07-16 10:12:20 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CMDList(option, opt, value, parser):
print(' '.join(str(p) for p in conf.sections()))
2017-07-16 10:12:20 +00:00
2017-07-25 13:39:02 +00:00
2018-04-04 21:31:37 +00:00
def GetTreeList(strings=True, expandlist=True):
aliases = []
groups = []
resultalias = []
resultstring = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
elif conf.has_option(a, "exec_string"):
aliases.append(a)
for g in groups:
resultalias.append(g)
resultstring.append(">> "+g)
group_aliases = conf.get(g, "group").split()
for ga in group_aliases:
if expandlist == False:
pass
elif expandlist == True or g in expandlist:
if conf.has_option(ga, "exec_string"):
resultalias.append(ga+" "+g)
result = "".join([" ", str(ga), " (", (conf.get(ga, "exec_string") if
conf.has_option(ga, "exec_string") else ""), ")",
(" [password]" if conf.has_option(ga, "password") else "")])
resultstring.append(result)
try:
aliases.remove(ga)
except ValueError:
pass
for a in aliases:
resultalias.append(a)
result = "".join([str(a), " (", (conf.get(a, "exec_string") if
conf.has_option(a, "exec_string") else ""), ")",
(" [password]" if conf.has_option(a, "password") else "")])
resultstring.append(result)
if strings:
return resultstring;
else:
return resultalias;
2017-07-24 14:50:08 +00:00
def CMDFullList(option, opt, value, parser):
2018-04-04 21:31:37 +00:00
for p in GetTreeList():
print (p)
2017-07-25 13:39:02 +00:00
2017-07-24 14:50:08 +00:00
2017-07-19 11:25:42 +00:00
def CursesConnect(screen, aliases, command=False):
curses.endwin()
2018-04-04 21:31:37 +00:00
groups = []
connectaliases = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
2017-07-19 11:25:42 +00:00
for alias in aliases:
2018-04-04 21:31:37 +00:00
if alias in groups:
group_aliases = conf.get(alias, "group").split()
for ga in group_aliases:
if not ga in connectaliases:
connectaliases.append(ga)
else:
if not alias in connectaliases:
connectaliases.append(alias)
for alias in connectaliases:
2017-11-19 22:34:25 +00:00
print("Connecting to " + alias + "...")
2017-07-19 11:25:42 +00:00
ConnectAlias(alias, command)
2017-11-19 22:34:25 +00:00
print("... " + alias + " session finished.")
print("Press 'enter' to continue.")
2017-07-19 11:25:42 +00:00
screen.getch()
2017-07-16 10:12:20 +00:00
2017-07-25 13:39:02 +00:00
2017-07-24 14:50:08 +00:00
def CursesExit(error=False):
2017-07-19 11:25:42 +00:00
curses.endwin()
2017-07-25 13:39:02 +00:00
if error:
2017-11-19 22:34:25 +00:00
print(error)
2017-07-19 11:25:42 +00:00
exit()
2017-07-16 10:12:20 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CursesTextpadConfirm(value):
2017-07-18 17:18:16 +00:00
if value == 10:
value = 7
return value
2017-07-19 11:25:42 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CursesTextpad(screen, h, w, y, x, title="", value="",
text_colorpair=0, deco_colorpair=0):
new_window = curses.newwin(h + 3, w + 2, y - 1, x - 1)
2017-07-25 13:39:02 +00:00
title_window = new_window.subwin(1, w, y, x)
title_window.addnstr(0, 0, title, w, text_colorpair)
2017-07-19 11:25:42 +00:00
title_window.refresh()
sub_window = new_window.subwin(h, w, y + 1, x)
textbox_field = textpad.Textbox(sub_window, insert_mode=True)
new_window.attron(deco_colorpair)
new_window.box()
new_window.attroff(deco_colorpair)
new_window.refresh()
2017-07-25 13:39:02 +00:00
sub_window.addnstr(0, 0, value, h * w, text_colorpair)
2017-07-19 11:25:42 +00:00
sub_window.attron(text_colorpair)
return textbox_field
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CursesPanel(screen, h, w, y, x, text,
text_colorpair=0, deco_colorpair=0, confirm=0):
2017-07-18 17:18:16 +00:00
new_window = curses.newwin(h, w, y, x)
new_window.erase()
new_window.attron(deco_colorpair)
new_window.box()
new_window.attroff(deco_colorpair)
2017-07-25 13:39:02 +00:00
sub_window = new_window.subwin(h - 2, w - 2, y + 1, x + 1)
2017-07-24 14:50:08 +00:00
sub_window.insstr(0, 0, text)
2017-07-25 14:21:54 +00:00
panel = curses.panel.new_panel(new_window)
2017-07-18 17:18:16 +00:00
curses.panel.update_panels()
screen.refresh()
if confirm == "password":
hidden_password = ""
keych = ""
position = 2
2017-07-19 11:25:42 +00:00
while True:
2017-07-18 17:18:16 +00:00
keych = screen.getch()
if keych == ord("\n"):
break
if keych == 27:
hidden_password = ""
break
if keych == curses.KEY_BACKSPACE:
if position > 2:
2017-07-24 14:50:08 +00:00
if position == len(hidden_password) + 2:
sub_window.addstr(1, position - 1, " ",
text_colorpair)
sub_window.refresh()
position = position - 1
2017-07-18 17:18:16 +00:00
hidden_password = hidden_password[0:-1]
2017-07-24 14:50:08 +00:00
if keych > 31 and keych < 127:
2017-07-18 17:18:16 +00:00
hidden_password += curses.keyname(keych)
sub_window.addstr(1, position, "*", text_colorpair)
2017-07-24 14:50:08 +00:00
if position < w - 4:
position += 1
2017-07-18 17:18:16 +00:00
sub_window.refresh()
return hidden_password
elif confirm == "remove":
keych = screen.getch()
if keych == ord("y") or keych == ord("Y"):
return "confirm"
return False
else:
screen.getch()
2017-07-16 10:12:20 +00:00
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CMDOptions():
class FormatedParser(OptionParser):
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def format_epilog(self, formatter):
return self.epilog
usage = "usage: %prog [options] [aliases]"
progname = path.basename(__file__)
2017-07-25 13:39:02 +00:00
epilog = ("".join(["Examples:\n ",
progname, " existingalias\n ",
progname, " -a newremoteserver\n ",
progname, " --edit=newremoteserver -p newremoteserver\n ",
progname, ' -c "ls -l" newremoteserver\n ',
progname, " -c reboot existingalias newremoteserver\n",
"Examples of connection string:\n ",
"ssh user@somehost.com\n ",
"ssh gates@8.8.8.8 -p 667\n ",
"ssh root@somehost.com -t tmux a\n",
"Also, you can edit config file manually: ", conf_file, "\n"]))
2017-07-19 11:25:42 +00:00
opts = FormatedParser(usage=usage, version="%prog " + version,
epilog=epilog)
2017-07-25 13:39:02 +00:00
opts.add_option('-l', '--list', action="callback",
callback=CMDList, help="show list of all existing aliases")
opts.add_option('-f', '--fulllist', action="callback",
callback=CMDFullList, help=("show list of all existing " +
"aliases with connection strings"))
2017-07-19 11:25:42 +00:00
opts.add_option('-a', '--add', action="store", type="string",
2017-07-25 13:39:02 +00:00
dest="add", metavar="alias", default=False,
help="add new alias for connection string")
2018-04-04 21:31:37 +00:00
opts.add_option('-g', '--group', action="store", type="string",
dest="group", metavar="group", default=False,
help="add new group for aliases")
2017-07-19 11:25:42 +00:00
opts.add_option('-c', '--command', action="store", type="string",
2017-07-25 13:39:02 +00:00
dest="command", metavar="command", default=False,
help="execute command for aliases or group")
2017-07-25 14:21:54 +00:00
opts.add_option('-k', '--keep', action="store", type="string",
dest="keep", metavar="alias", default=False,
help="hold connection with specified alias")
2017-07-19 11:25:42 +00:00
opts.add_option('-e', '--edit', action="store", type="string",
2017-07-25 13:39:02 +00:00
dest='edit', metavar="alias", default=False,
2018-04-04 21:31:37 +00:00
help="edit existing alias or group")
2017-07-19 11:25:42 +00:00
opts.add_option('-p', '--password', action="store", type="string",
2017-07-25 13:39:02 +00:00
dest='password', metavar="alias", default=False,
help="set and store password for sshpass [UNSAFE]")
2017-07-19 11:25:42 +00:00
opts.add_option('-r', '--remove', action="store", type="string",
2017-07-25 13:39:02 +00:00
dest='remove', metavar="alias", default=False,
2018-04-04 21:31:37 +00:00
help="remove existing alias or group")
2017-07-19 11:25:42 +00:00
options, alias = opts.parse_args()
2017-07-25 13:39:02 +00:00
if options.add:
CMDAdd(options.add)
2018-04-04 21:31:37 +00:00
if options.group:
CMDGroup(options.group)
2017-07-25 13:39:02 +00:00
if options.edit:
CMDEdit(options.edit)
if options.password:
CMDPassword(options.password)
if options.remove:
CMDRemove(options.remove)
2017-07-25 14:21:54 +00:00
if options.keep:
HoldConnection(options.keep)
2017-07-25 13:39:02 +00:00
if alias:
CMDConnect(alias, options.command)
2017-07-18 17:18:16 +00:00
# curses template from: https://stackoverflow.com/a/30828805/6224462
2017-07-25 13:39:02 +00:00
2017-07-19 11:25:42 +00:00
def CursesMain():
2017-07-25 13:39:02 +00:00
help_screen = ("".join([" Press:\n",
" 'z'/'x' or arrows - navigation\n",
" 'a'/'F2' - add new alias (without spaces)\n",
" 'g'/'F5' - add new group (spaces will be stripped)\n",
2018-04-04 21:31:37 +00:00
" 'e'/'F4' - edit existing alias/group\n",
2017-07-25 13:39:02 +00:00
" 'p'/'F6' - set alias's password for sshpass [UNSAFE]\n",
" 'space'/'insert' - select\n",
" 'r'/'F8' - remove selected alias/aliases\n",
" 'c'/'F3' - execute specific command with selected alias/aliases\n",
2017-07-25 14:21:54 +00:00
" 'k'/'F7' - hold connection with selected alias\n",
2018-04-04 21:31:37 +00:00
" 'enter'/'F9' - connect to selected alias/aliases,\n",
" expand/collapse group\n",
2017-07-25 13:39:02 +00:00
" 'q'/'F10' - quit\n",
" Run program with '--help' option to view command line help.\n",
" Also, you can edit config file manually:\n",
" ", conf_file]))
2018-04-04 21:31:37 +00:00
if expand_default == True:
groups = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
expanded = groups
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
elif expand_default == False:
groups = []
expanded = groups
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
2017-07-18 17:18:16 +00:00
row_num = len(strings)
selected_strings = [" " for i in range(0, row_num + 1)]
screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad(1)
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN)
highlight_text = curses.color_pair(1)
normal_text = curses.A_NORMAL
height, width = screen.getmaxyx()
screen.border(0)
curses.curs_set(0)
max_row = height - 5
2017-07-24 14:50:08 +00:00
screen.addnstr(1, 2, "sshch " + version + ", press 'h' for help",
width - 4)
2017-07-18 17:18:16 +00:00
box = curses.newwin(max_row + 2, width - 2, 2, 1)
box.box()
pages = int(ceil(row_num / max_row))
position = 1
page = 1
for i in range(1, max_row + 1):
if row_num == 0:
2017-07-25 13:39:02 +00:00
box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.",
width - 6, highlight_text)
2017-07-18 17:18:16 +00:00
else:
2018-04-04 21:31:37 +00:00
exec_string = ["[", selected_strings[i], "] ", stringsfull[i - 1]]
2017-07-18 17:18:16 +00:00
if (i == position):
2017-07-25 13:39:02 +00:00
box.addnstr(i, 2, "".join(exec_string), width - 6, highlight_text)
2017-07-18 17:18:16 +00:00
else:
2017-07-25 13:39:02 +00:00
box.addnstr(i, 2, "".join(exec_string), width - 6, normal_text)
2017-07-18 17:18:16 +00:00
if i == row_num:
break
screen.refresh()
box.refresh()
key_pressed = screen.getch()
2017-07-19 11:25:42 +00:00
while True:
2017-07-18 17:18:16 +00:00
if key_pressed == ord('q') or key_pressed == ord(
2017-07-25 13:39:02 +00:00
'Q') or key_pressed == (
27) or key_pressed == curses.KEY_F10:
2017-07-19 11:25:42 +00:00
CursesExit()
2017-07-18 17:18:16 +00:00
if key_pressed == ord('h') or key_pressed == ord(
2017-07-25 13:39:02 +00:00
'H') or key_pressed == curses.KEY_F1:
2017-07-19 11:25:42 +00:00
CursesPanel(screen, height - 4, width - 6, 2, 3,
help_screen, normal_text, highlight_text)
if key_pressed == ord('a') or key_pressed == ord(
2017-07-25 13:39:02 +00:00
'A') or key_pressed == curses.KEY_F2:
2018-04-08 08:31:20 +00:00
curses.curs_set(1)
2017-07-19 11:25:42 +00:00
new_alias_textpad = CursesTextpad(screen, 1, width - 8,
2017-07-25 13:39:02 +00:00
(height // 2) - 1, 4, "Enter new alias:", "",
normal_text, highlight_text)
2017-07-19 11:25:42 +00:00
add_alias = new_alias_textpad.edit(CursesTextpadConfirm)
add_alias = add_alias.split()[0].strip()
if not add_alias == "":
add_result = AddNewAlias(add_alias)
if add_result == True:
2017-07-19 11:25:42 +00:00
add_string = ""
while add_string == "":
2017-07-19 11:25:42 +00:00
string_textpad = CursesTextpad(screen, 3,
2017-07-25 13:39:02 +00:00
width - 8, (height // 2) - 1, 4,
"Enter full execution string:",
"ssh ", normal_text, highlight_text)
2017-07-19 11:25:42 +00:00
add_string = string_textpad.edit(
CursesTextpadConfirm)
SetAliasString(add_alias,
2017-07-25 13:39:02 +00:00
add_string.replace("\n", "").rstrip())
2018-04-04 21:31:37 +00:00
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
2017-07-18 17:18:16 +00:00
row_num = len(strings)
selected_strings.append(" ")
pages = int(ceil(row_num / max_row))
box.refresh()
else:
curses.curs_set(0)
CursesPanel(screen, 3,
width - 6, (height // 2) - 1, 3, add_result,
normal_text, highlight_text)
2018-04-08 08:31:20 +00:00
curses.curs_set(0)
2018-04-04 21:31:37 +00:00
if key_pressed == ord('g') or key_pressed == ord(
'G') or key_pressed == curses.KEY_F5:
2018-04-08 08:31:20 +00:00
curses.curs_set(1)
2018-04-04 21:31:37 +00:00
new_group_textpad = CursesTextpad(screen, 1, width - 8,
2018-04-08 09:33:27 +00:00
(height // 2) - 1, 4, "Enter group name (without spaces):", "",
2018-04-04 21:31:37 +00:00
normal_text, highlight_text)
add_group = new_group_textpad.edit(CursesTextpadConfirm)
add_group = add_group.split()[0].strip()
if not add_group == "":
add_result = AddNewAlias(add_group)
if add_result == True:
2018-04-04 21:31:37 +00:00
add_string = ""
while add_string.rstrip() == "":
string_textpad = CursesTextpad(screen, 3,
width - 8, (height // 2) - 1, 4,
"Enter aliases for new group (example: alias1 alias2):",
"", normal_text, highlight_text)
add_string = string_textpad.edit(
CursesTextpadConfirm)
SetGroupString(add_group,
2018-04-04 21:31:37 +00:00
add_string.replace("\n", "").rstrip())
expanded.append(add_group)
2018-04-04 21:31:37 +00:00
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
row_num = len(strings)
selected_strings = [" " for i in range(0, row_num + 1)]
pages = int(ceil(row_num / max_row))
box.refresh()
else:
curses.curs_set(0)
CursesPanel(screen, 3,
width - 6, (height // 2) - 1, 3, add_result,
normal_text, highlight_text)
2018-04-08 08:31:20 +00:00
curses.curs_set(0)
2017-07-19 11:25:42 +00:00
if (key_pressed == ord('e') or key_pressed == ord(
'E') or key_pressed == curses.KEY_F4) and row_num != 0:
edit_string = ""
2018-04-04 21:31:37 +00:00
groups = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
2018-04-08 08:31:20 +00:00
curses.curs_set(1)
2018-04-04 21:31:37 +00:00
if strings[position - 1] in groups:
while edit_string.rstrip() == "":
string_textpad = CursesTextpad(screen, 3, width - 8,
2018-04-08 09:23:29 +00:00
(height // 2) - 1, 4, "Enter new aliases for existing group:",
2018-04-04 21:31:37 +00:00
(conf.get(strings[position - 1],
"group") if conf.has_option(strings[position - 1],
"group") else ""),
normal_text, highlight_text)
edit_string = string_textpad.edit(CursesTextpadConfirm)
SetGroupString(strings[position - 1],
edit_string.replace("\n", "").rstrip())
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
row_num = len(strings)
selected_strings.append(" ")
pages = int(ceil(row_num / max_row))
box.refresh()
else:
while edit_string.rstrip() == "":
string_textpad = CursesTextpad(screen, 3, width - 8,
(height // 2) - 1, 4, "Enter new execution string:",
(conf.get(strings[position - 1].split()[0].strip(),
"exec_string") if conf.has_option(strings[position - 1].split()[0].strip(),
"exec_string") else ""),
normal_text, highlight_text)
edit_string = string_textpad.edit(CursesTextpadConfirm)
SetAliasString(strings[position - 1].split()[0].strip(),
edit_string.replace("\n", "").rstrip())
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
2018-04-08 08:31:20 +00:00
curses.curs_set(0)
2017-07-19 11:25:42 +00:00
if (key_pressed == ord('p') or key_pressed == ord(
'P') or key_pressed == curses.KEY_F6) and row_num != 0:
2018-04-04 21:31:37 +00:00
groups = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
if not strings[position - 1].split()[0].strip() in groups:
set_password = ""
set_password = CursesPanel(screen, 4, width - 6,
(height // 2) - 1, 3,
" Enter user password for sshpass and press 'enter':\n>",
normal_text, highlight_text, "password")
if not set_password == "":
SetPassword(strings[position - 1].split()[0].strip(), set_password)
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
2017-07-19 11:25:42 +00:00
if (key_pressed == ord('r') or key_pressed == ord(
'R') or key_pressed == curses.KEY_F8 or key_pressed == (
curses.KEY_DC)) and row_num != 0:
2017-07-18 17:18:16 +00:00
selected = []
for i in range(1, row_num + 1):
if selected_strings[i] == "*":
selected.append(strings[i - 1])
if len(selected) > 0:
2017-07-25 13:39:02 +00:00
remove_confirm = (
"".join(["Are you sure to remove ",
str(len(selected)), " selected aliases? (y/N)"]))
2017-07-18 17:18:16 +00:00
else:
2017-07-25 13:39:02 +00:00
remove_confirm = ("".join(["Are you sure to remove '",
2018-04-04 21:31:37 +00:00
strings[position - 1].split()[0].strip(), "' alias? (y/N)"]))
selected.append(strings[position - 1].split()[0].strip())
2017-07-19 11:25:42 +00:00
remove_result = CursesPanel(screen, 4, width - 6,
2017-07-25 13:39:02 +00:00
(height // 2) - 1, 3, remove_confirm, normal_text,
highlight_text, "remove")
2017-07-19 11:25:42 +00:00
if remove_result == "confirm":
2017-07-25 13:39:02 +00:00
RemoveAliases(selected)
2018-04-04 21:31:37 +00:00
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
2017-07-18 17:18:16 +00:00
row_num = len(strings)
selected_strings = [" " for i in range(0, row_num + 1)]
pages = int(ceil(row_num / max_row))
position = 1
page = 1
box.refresh()
2017-07-19 11:25:42 +00:00
if (key_pressed == ord('c') or key_pressed == ord(
'C') or key_pressed == curses.KEY_F3) and row_num != 0:
2017-07-18 17:18:16 +00:00
selected = []
for i in range(1, row_num + 1):
if selected_strings[i] == "*":
selected.append(strings[i - 1])
if not len(selected) > 0:
2018-04-04 21:31:37 +00:00
selected.append(strings[position - 1].split()[0].strip())
2018-04-08 08:31:20 +00:00
curses.curs_set(1)
2017-07-19 11:25:42 +00:00
command_textpad = CursesTextpad(screen, 3, width - 8,
2017-07-25 13:39:02 +00:00
(height // 2) - 1, 4,
"".join([
"Enter specific command to execute with selected ",
"alias/aliases:"]
), "", normal_text, highlight_text)
2017-07-19 11:25:42 +00:00
command_string = command_textpad.edit(CursesTextpadConfirm)
2017-07-24 14:50:08 +00:00
CursesConnect(screen, selected,
2017-07-25 13:39:02 +00:00
command_string.replace("\n", "").rstrip())
2018-04-08 08:31:20 +00:00
curses.curs_set(0)
2017-07-25 14:21:54 +00:00
if (key_pressed == ord('k') or key_pressed == ord('K') or
key_pressed == (curses.KEY_F7)) and row_num != 0:
2018-04-04 21:31:37 +00:00
groups = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
if not strings[position - 1] in groups:
curses.endwin()
HoldConnection(strings[position - 1].split()[0].strip())
2017-07-19 11:25:42 +00:00
if (key_pressed == ord("\n") or key_pressed == (
curses.KEY_F9)) and row_num != 0:
2018-04-04 21:31:37 +00:00
groups = []
for a in conf.sections():
if conf.has_option(a, "group"):
groups.append(a)
if strings[position - 1] in groups:
if strings[position - 1] in expanded:
expanded.remove(strings[position - 1])
else:
expanded.append(strings[position - 1])
strings = GetTreeList(False, expanded)
stringsfull = GetTreeList(True, expanded)
row_num = len(strings)
selected_strings.append(" ")
pages = int(ceil(row_num / max_row))
box.refresh()
else:
selected = []
for i in range(1, row_num + 1):
if selected_strings[i] == "*":
selected.append(strings[i - 1])
if not len(selected) > 0:
selected.append(strings[position - 1].split()[0].strip())
CursesConnect(screen, selected)
2018-04-08 13:27:16 +00:00
selected_strings = [" " for i in range(0, row_num + 1)]
2017-07-24 14:50:08 +00:00
if (key_pressed == 32 or key_pressed == (
curses.KEY_IC)) and row_num != 0:
2017-07-19 11:25:42 +00:00
if selected_strings[position] == ' ':
selected_strings[position] = '*'
2017-07-25 13:39:02 +00:00
else:
selected_strings[position] = ' '
2017-07-19 11:25:42 +00:00
if page == 1:
if position < i:
position = position + 1
else:
if pages > 1:
page = page + 1
position = 1 + (max_row * (page - 1))
elif page == pages:
if position < row_num:
position = position + 1
else:
if position < max_row + (max_row * (page - 1)):
position = position + 1
else:
page = page + 1
position = 1 + (max_row * (page - 1))
2017-07-18 17:18:16 +00:00
if key_pressed == curses.KEY_DOWN or key_pressed == ord(
2017-07-25 13:39:02 +00:00
'x') or key_pressed == ord('X'):
2017-07-18 17:18:16 +00:00
if page == 1:
if position < i:
position = position + 1
else:
if pages > 1:
page = page + 1
position = 1 + (max_row * (page - 1))
elif page == pages:
if position < row_num:
position = position + 1
else:
if position < max_row + (max_row * (page - 1)):
position = position + 1
else:
page = page + 1
position = 1 + (max_row * (page - 1))
if key_pressed == curses.KEY_UP or key_pressed == ord(
2017-07-25 13:39:02 +00:00
'z') or key_pressed == ord('Z'):
2017-07-18 17:18:16 +00:00
if page == 1:
if position > 1:
position = position - 1
else:
if position > (1 + (max_row * (page - 1))):
position = position - 1
else:
page = page - 1
position = max_row + (max_row * (page - 1))
2017-07-25 13:39:02 +00:00
if key_pressed == curses.KEY_LEFT or (key_pressed ==
curses.KEY_PPAGE):
2017-07-18 17:18:16 +00:00
if page > 1:
page = page - 1
position = 1 + (max_row * (page - 1))
if key_pressed == curses.KEY_RIGHT or (key_pressed ==
2017-07-25 13:39:02 +00:00
curses.KEY_NPAGE):
2017-07-18 17:18:16 +00:00
if page < pages:
page = page + 1
position = (1 + (max_row * (page - 1)))
if key_pressed == curses.KEY_HOME:
page = 1
position = 1
if key_pressed == curses.KEY_END:
page = pages
position = row_num
2017-07-18 17:18:16 +00:00
box.erase()
screen.border(0)
box.border(0)
for i in range(1 + (max_row * (page - 1)), max_row + 1 +
(max_row * (page - 1))):
if row_num == 0:
2017-07-25 13:39:02 +00:00
box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.",
width - 6, highlight_text)
2017-07-18 17:18:16 +00:00
else:
2018-04-04 21:31:37 +00:00
exec_string = ["[", selected_strings[i], "] ", stringsfull[i - 1]]
2017-07-25 13:39:02 +00:00
if (i + (max_row * (page - 1)) == (position + (max_row * (page - 1)))):
box.addnstr(i - (max_row * (page - 1)), 2, "".join(
exec_string), width - 6, highlight_text)
2017-07-18 17:18:16 +00:00
else:
2017-07-25 13:39:02 +00:00
box.addnstr(i - (max_row * (page - 1)), 2, "".join(
exec_string), width - 6, normal_text)
2017-07-18 17:18:16 +00:00
if i == row_num:
break
screen.refresh()
box.refresh()
2017-07-25 13:39:02 +00:00
key_pressed = screen.getch()
2017-07-19 11:25:42 +00:00
CursesExit()
2017-07-18 17:18:16 +00:00
2017-07-25 13:39:02 +00:00
2017-07-18 17:18:16 +00:00
if __name__ == "__main__":
2017-11-19 22:34:25 +00:00
try:
input = raw_input # Fix for Python 2.x
except NameError:
pass
conf = configparser.RawConfigParser()
2017-07-18 17:18:16 +00:00
if not path.exists(conf_file):
open(conf_file, 'w')
conf.read(conf_file)
if len(argv) > 1:
2017-07-24 14:50:08 +00:00
try:
CMDOptions()
except KeyboardInterrupt:
exit()
2017-11-19 22:34:25 +00:00
except configparser.Error:
print("Error: can't parse your config file, please check it manually or make new one")
2017-07-24 14:50:08 +00:00
exit()
2017-07-18 17:18:16 +00:00
else:
2017-07-24 14:50:08 +00:00
try:
CursesMain()
except KeyboardInterrupt:
CursesExit()
2017-11-19 22:34:25 +00:00
except configparser.NoOptionError:
2017-07-25 13:39:02 +00:00
CursesExit("".join(["Error: can't parse your config file, please ",
"check it manually or make new one"]))
2017-07-24 14:50:08 +00:00
except curses.error:
2017-07-25 13:39:02 +00:00
CursesExit("".join(["Error: can't show some curses element, maybe ",
"your terminal is too small"]))