Compare commits
	
		
			No commits in common. "master" and "GHPS/ZSH-Completion" have entirely different histories.
		
	
	
		
			master
			...
			GHPS/ZSH-C
		
	
		
							
								
								
									
										17
									
								
								LICENSE
								
								
								
								
							
							
						
						
									
										17
									
								
								LICENSE
								
								
								
								
							|  | @ -4,26 +4,27 @@ 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. | This program is free software; you can redistribute it and/or modify it under the terms of the Do What Thou Wilt License. | ||||||
| 
 | 
 | ||||||
| Boundless Public License | DO WHAT THAU WILT | ||||||
| DO WHAT THOU WILT |  | ||||||
| TO PUBLIC LICENSE | TO PUBLIC LICENSE | ||||||
| 
 | 
 | ||||||
| Version 2.55 | Version 2.5 | ||||||
| 
 | 
 | ||||||
| Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it in full or in part is allowed without any restrictions. | 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 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||||
| 
 | 
 | ||||||
| 0. Do what thou wilt shall be the whole of the Law. | 0. Do what thou wilt shall be the whole of the Law. | ||||||
| 
 | 
 | ||||||
| DWTWL – a license with a single requirement: DO WHAT THOU WILT | 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.  | The license provides more freedom than any other one (such as GPL or BSD) and does not require saving the license text on copying.  | ||||||
| 
 | 
 | ||||||
| DWTWL – an accomplished and eligible license for free text, code and any other symbols (including the software, documentation and artwork). | DWTW – an accomplished and eligible license for free text (including the software, documentation and artwork).  | ||||||
| 
 | 
 | ||||||
| The license does not contain a "no warranty" clause. DWTWL can be used in countries that do not legally acknowledge the transition to public domain. | 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:  | Summary:  | ||||||
| 
 | 
 | ||||||
| An author-creator gives their source code to the world for free, without becoming distracted by worldly thinking regarding how and why the others will use it. | 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. | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								README.md
								
								
								
								
							
							
						
						
									
										40
									
								
								README.md
								
								
								
								
							|  | @ -1,49 +1,31 @@ | ||||||
| SSH connection and aliases manager with curses and command line interface | SSH connection manager with curses interface | ||||||
| ====== | ====== | ||||||
| sshch is released under DWTWL 2.55 license | sshch is released under DWTWL 2.5 license | ||||||
| 
 |  | ||||||
| sshch compatible with pyhon2 and python3, no additional libraries are required |  | ||||||
| ### Screenshot | ### Screenshot | ||||||
|  |  | ||||||
| 
 |  | ||||||
| ### Installing | ### Installing | ||||||
| **You can install a release version from pip:** |  | ||||||
| ```bash |  | ||||||
| pip install sshch |  | ||||||
| ``` |  | ||||||
| **Manual installation from the package or git repository also available:** |  | ||||||
| 
 |  | ||||||
| To install for all users: | To install for all users: | ||||||
| ```bash | ``` | ||||||
| sudo python setup.py install | sudo python setup.py install | ||||||
| ``` | ``` | ||||||
| To install just for current user: | To install just for current user: | ||||||
| ```bash | ``` | ||||||
| mkdir ~/.local/bin | mkdir ~/.local/bin | ||||||
| cp sshch/sshch ~/.local/bin/ | cp sshch/sshch ~/.local/bin/ | ||||||
| ``` | ``` | ||||||
| ### Using | ### Using | ||||||
| To run curses interface: | To run curses interface: | ||||||
| ```bash | ``` | ||||||
| sshch | sshch | ||||||
| ``` | ``` | ||||||
| To run command line help: | To run command line help: | ||||||
| ```bash | ``` | ||||||
| sshch -h | sshch -h | ||||||
| ``` | ``` | ||||||
| For exit from current ssh session press `Ctrl+D`. | **If you want to use unsafe 'password' feature you must install 'sshpass' first.** | ||||||
| 
 | 
 | ||||||
| **Additional Features** | If you want to use bash autocompletion function with sshch, copy autocompletion script to /etc/bash_completion.d/: | ||||||
| - If you want to use unsafe 'password' feature you must install `sshpass` first. | ``` | ||||||
| - If you want to use bash autocompletion function with sshch, copy autocompletion script to /etc/bash_completion.d/: | sudo cp sshch_bash_completion.sh /etc/bash_completion.d/sshch | ||||||
| ```bash |  | ||||||
| sudo cp completion/sshch_bash_completion.sh /etc/bash_completion.d/sshch |  | ||||||
| ``` | ``` | ||||||
| (changes will come into effect with new bash session) | (changes will come into effect with new bash session) | ||||||
| - If you want to use zsh autocompletion: |  | ||||||
| 1) Place File in a Directory where ZSH can find it |  | ||||||
| 
 |  | ||||||
|      -> Search Path is Stored in $fpath |  | ||||||
| 
 |  | ||||||
|      -> echo $fpath |  | ||||||
| 2) Rename File to '_sshch' |  | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								setup.py
								
								
								
								
							
							
						
						
									
										17
									
								
								setup.py
								
								
								
								
							|  | @ -7,27 +7,22 @@ def main(): | ||||||
| 
 | 
 | ||||||
|     setup(name='sshch', |     setup(name='sshch', | ||||||
|           author='zlaxy', |           author='zlaxy', | ||||||
|           author_email='zlaxyi@gmail.com', |           url='https://github.com/zlaxy/sshch/', | ||||||
|           url='https://gitlab.com/zlax/sshch', |           description='Ssh connection manager', | ||||||
|           description='Ssh connection and aliases manager', |           license='DWTWL 2.5', | ||||||
|           long_description='SSH connection and aliases manager with curses and command line interface', |           version='0.8', | ||||||
|           long_description_content_type='text/x-rst', |  | ||||||
|           license='DWTWL 2.55', |  | ||||||
|           version='1.09.7', |  | ||||||
|           py_modules=['sshch'], |           py_modules=['sshch'], | ||||||
|           scripts=['sshch/sshch'], |           scripts=['sshch/sshch'], | ||||||
|           keywords='sshch ssh aliases curses manager', |  | ||||||
|           python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4', |  | ||||||
| 
 | 
 | ||||||
|           # http://pypi.python.org/pypi?%3Aaction=list_classifiers |           # http://pypi.python.org/pypi?%3Aaction=list_classifiers | ||||||
|           classifiers=[ |           classifiers=[ | ||||||
|               'Development Status :: 5 - Production/Stable', |               'Development Status :: 4 - Beta', | ||||||
|               'Environment :: Console :: Curses', |               'Environment :: Console :: Curses', | ||||||
|               'Intended Audience :: System Administrators', |               'Intended Audience :: System Administrators', | ||||||
|               'License :: Freeware', |               'License :: Freeware', | ||||||
|               'Natural Language :: English', |               'Natural Language :: English', | ||||||
|               'Operating System :: POSIX', |               'Operating System :: POSIX', | ||||||
|               'Programming Language :: Python', |               'Programming Language :: Python :: 2.7', | ||||||
|               'Topic :: Internet', |               'Topic :: Internet', | ||||||
|               'Topic :: System :: Networking', |               'Topic :: System :: Networking', | ||||||
|               'Topic :: System :: Systems Administration', |               'Topic :: System :: Systems Administration', | ||||||
|  |  | ||||||
							
								
								
									
										609
									
								
								sshch/sshch
								
								
								
								
							
							
						
						
									
										609
									
								
								sshch/sshch
								
								
								
								
							|  | @ -1,4 +1,4 @@ | ||||||
| #!/usr/bin/env python | #!/usr/bin/env python3 | ||||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||||
| 
 | 
 | ||||||
| from __future__ import division | from __future__ import division | ||||||
|  | @ -7,8 +7,7 @@ try: | ||||||
|     import configparser |     import configparser | ||||||
| except ImportError: | except ImportError: | ||||||
|     import ConfigParser as configparser  # Python 2.x import |     import ConfigParser as configparser  # Python 2.x import | ||||||
|     import locale | 
 | ||||||
|     locale.setlocale(locale.LC_ALL, '') |  | ||||||
| from os import path | from os import path | ||||||
| from sys import argv | from sys import argv | ||||||
| from math import ceil | from math import ceil | ||||||
|  | @ -19,24 +18,11 @@ import base64 | ||||||
| import time | import time | ||||||
| import curses | import curses | ||||||
| from curses import textpad, panel | from curses import textpad, panel | ||||||
| from threading import Thread |  | ||||||
| 
 | 
 | ||||||
| # https://gitlab.com/zlax/sshch | # https://github.com/zlaxy/sshch | ||||||
| version = "1.09.7" | version = "0.9" | ||||||
| # expand groups by default | # path to conf file, default: ~/.config/sshch.conf | ||||||
| expand_default = True | conf_file = path.expanduser("~") + '/.config/sshch.conf' | ||||||
| # path to conf dir and file, default: ~/.config/sshch.conf |  | ||||||
| conf_dir = path.expanduser("~") + '/.config' |  | ||||||
| conf_file = conf_dir + '/' + 'sshch.conf' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class GroupTree(object): |  | ||||||
|     """Group object with relatives information""" |  | ||||||
|     def __init__(self, group): |  | ||||||
|         self.group = group |  | ||||||
|         self.aliases = [] |  | ||||||
|         self.children = [] |  | ||||||
|         self.parent = [] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def AddNewAlias(alias): | def AddNewAlias(alias): | ||||||
|  | @ -45,7 +31,7 @@ def AddNewAlias(alias): | ||||||
|         conf.write(open(conf_file, "w")) |         conf.write(open(conf_file, "w")) | ||||||
|         return True |         return True | ||||||
|     else: |     else: | ||||||
|         return "error: '" + alias + "' alias or group already exists" |         return "error: '" + alias + "' already exists" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def SetAliasString(alias, string): | def SetAliasString(alias, string): | ||||||
|  | @ -53,19 +39,9 @@ def SetAliasString(alias, string): | ||||||
|     conf.write(open(conf_file, "w")) |     conf.write(open(conf_file, "w")) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def SetGroupString(alias, string): |  | ||||||
|     conf.set(alias, "group", string) |  | ||||||
|     conf.write(open(conf_file, "w")) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def SetPassword(alias, string): | def SetPassword(alias, string): | ||||||
|     if string == "" or string == b'': |  | ||||||
|         conf.remove_option(alias, "password") |  | ||||||
|     else: |  | ||||||
|         string = string.encode() |  | ||||||
|     string = base64.b64encode(base64.b16encode( |     string = base64.b64encode(base64.b16encode( | ||||||
|                               base64.b32encode(string))) |                               base64.b32encode(string))) | ||||||
|         string = string.decode('utf-8') |  | ||||||
|     conf.set(alias, "password", string) |     conf.set(alias, "password", string) | ||||||
|     conf.write(open(conf_file, "w")) |     conf.write(open(conf_file, "w")) | ||||||
| 
 | 
 | ||||||
|  | @ -76,85 +52,21 @@ def RemoveAliases(aliases): | ||||||
|         conf.write(open(conf_file, "w")) |         conf.write(open(conf_file, "w")) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def ConvertPassword(password): | def ConnectAlias(alias, command=False): | ||||||
|     password_string = "'" |  | ||||||
|     for char in password: |  | ||||||
|         if char == "'": |  | ||||||
|             password_string += "'"+'"'+"'"+'"'+"'" |  | ||||||
|         elif char == '"': |  | ||||||
|             password_string += "''"+'"'+"''" |  | ||||||
|         elif char == ';': |  | ||||||
|             password_string += "'"+r'\;'+"'" |  | ||||||
|         elif char == "\\": |  | ||||||
|             password_string += "'"+'"'+"\\"+"\\"+'"'+"'" |  | ||||||
|         else: |  | ||||||
|             password_string += char |  | ||||||
|     password_string += "'" |  | ||||||
|     return password_string |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def Connect(aliases, command=False, threading=False, screen=False): |  | ||||||
|     if screen: |  | ||||||
|         curses.endwin() |  | ||||||
|     groups = [] |  | ||||||
|     connectaliases = [] |  | ||||||
|     for a in conf.sections(): |  | ||||||
|         if conf.has_option(a, "group"): |  | ||||||
|             groups.append(a) |  | ||||||
|     for alias in aliases: |  | ||||||
|         if alias in groups: |  | ||||||
|             group_aliases = GroupChildAliases(alias) |  | ||||||
|             for ga in group_aliases: |  | ||||||
|                 connectaliases.append(ga) |  | ||||||
|         else: |  | ||||||
|             connectaliases.append(alias) |  | ||||||
|     connectaliases = setSeq(connectaliases) |  | ||||||
|     threads = {} |  | ||||||
|     for alias in connectaliases: |  | ||||||
|         if conf.has_section(alias): |  | ||||||
|             print("Connecting to " + alias + "...") |  | ||||||
|             if threading: |  | ||||||
|                 threads[alias] = Thread(target=ConnectAlias, args=(alias, |  | ||||||
|                                         command, True)) |  | ||||||
|                 threads[alias].start() |  | ||||||
|             else: |  | ||||||
|                 ConnectAlias(alias, command) |  | ||||||
|             if not threading: |  | ||||||
|                 print("... " + alias + " session finished.") |  | ||||||
|         else: |  | ||||||
|             print("error: '" + alias + "' alias does not exists") |  | ||||||
|     if screen: |  | ||||||
|         print("Press 'enter' to continue.") |  | ||||||
|         screen.getch() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def ConnectAlias(alias, command=False, threading=False): |  | ||||||
|     exec_string = "" |     exec_string = "" | ||||||
|     if conf.has_option(alias, "password"): |     if conf.has_option(alias, "password"): | ||||||
|         password = base64.b32decode(base64.b16decode( |         password = base64.b32decode(base64.b16decode( | ||||||
|             base64.b64decode(conf.get(alias, "password")))) |             base64.b64decode(conf.get(alias, "password")))) | ||||||
|         exec_string = "sshpass -p " + ConvertPassword(password.decode('utf-8')) + " " |         exec_string = 'sshpass -p "' + password + '" ' | ||||||
|     if conf.has_option(alias, "exec_string"): |     if conf.has_option(alias, "exec_string"): | ||||||
|         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 | ||||||
|     try: |     # Variables bellow is newer used | ||||||
|     subprocess.Popen(exec_string, shell=True).communicate()[0] |     subprocess.Popen(exec_string, shell=True).communicate()[0] | ||||||
|     except: |  | ||||||
|         pass |  | ||||||
|     if threading: |  | ||||||
|         print ("... "+alias+" session output finished.") |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def HoldConnection(alias): | def HoldConnection(alias): | ||||||
|     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.") |     print("Connecting to " + alias + ". Press CTRL+C to cancel.") | ||||||
|     time.sleep(1) |     time.sleep(1) | ||||||
|     while True: |     while True: | ||||||
|  | @ -163,9 +75,8 @@ def HoldConnection(alias): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def CMDAdd(alias): | def CMDAdd(alias): | ||||||
|     alias = alias.split()[0].strip() |  | ||||||
|     result = AddNewAlias(alias) |     result = AddNewAlias(alias) | ||||||
|     if result == True: |     if result: | ||||||
|         prompt_add = ("".join(["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 = "" | ||||||
|  | @ -176,179 +87,71 @@ def CMDAdd(alias): | ||||||
|         print(result) |         print(result) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def CMDGroup(group): |  | ||||||
|     group = group.split()[0].strip() |  | ||||||
|     result = AddNewAlias(group) |  | ||||||
|     if result == True: |  | ||||||
|         prompt_add = ("".join(["Enter aliases for new group ", |  | ||||||
|                                "(example: alias1 alias2):\n"])) |  | ||||||
|         string = "" |  | ||||||
|         while string == "": |  | ||||||
|             string = input(prompt_add) |  | ||||||
|         SetGroupString(group, string) |  | ||||||
|     else: |  | ||||||
|         print(result) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def CMDEdit(alias): | def CMDEdit(alias): | ||||||
|     if conf.has_section(alias): |     if conf.has_section(alias): | ||||||
|         if conf.has_option(alias, "exec_string"): |         prompt_edit = ("".join(["Enter connection string for existing alias ", | ||||||
|             prompt_edit = ("".join(["Enter connection string for existing ", |                        "(example: ssh user@somehost.com):\n"])) | ||||||
|                            "alias (example: ssh user@somehost.com):\n"])) |  | ||||||
|         string = "" |         string = "" | ||||||
|         while string == "": |         while string == "": | ||||||
|             string = input(prompt_edit) |             string = input(prompt_edit) | ||||||
|         SetAliasString(alias, string) |         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: |     else: | ||||||
|             print("error: '" + alias + "' is not correct alias or group") |         print("error: '" + alias + "' alias is not exists") | ||||||
|     else: |  | ||||||
|         print("error: '" + alias + "' alias or group does not exists") |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def CMDPassword(alias): | 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): |     if conf.has_section(alias): | ||||||
|             prompt_pass = ("[UNSAFE] Enter password for sshpass (Ctrl+C" + |         prompt_pass = ("[UNSAFE] Enter password for sshpass: ") | ||||||
|                             " - cancel, blank - clear password):\n") |  | ||||||
|         string = "" |         string = "" | ||||||
|         string = getpass(prompt_pass) |         string = getpass(prompt_pass) | ||||||
|  |         if not string == "": | ||||||
|             SetPassword(alias, string) |             SetPassword(alias, string) | ||||||
|     else: |     else: | ||||||
|             print("error: '" + alias + "' alias does 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 '" + alias + |         prompt_remove = ("Type 'yes' if you sure to remove '" + alias + "' alias: ") | ||||||
|                          "' alias or group: ") |  | ||||||
|         string = input(prompt_remove) |         string = input(prompt_remove) | ||||||
|         if string == "yes": |         if string == "yes": | ||||||
|             RemoveAliases([alias]) |             RemoveAliases([alias]) | ||||||
|         else: |         else: | ||||||
|             print("'" + alias + "' alias or group was not deleted.") |             print("'" + alias + "' alias was not deleted.") | ||||||
|     else: |     else: | ||||||
|         print("error: '" + alias + "' alias or group does not exists.") |         print("error: '" + alias + "' alias is not exists.") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def CMDConnect(aliases, command=False): | ||||||
|  |     for alias in aliases: | ||||||
|  |         if conf.has_section(alias): | ||||||
|  |             print("Connecting to " + alias + "...") | ||||||
|  |             ConnectAlias(alias, command) | ||||||
|  |             print("... " + alias + " session finished.") | ||||||
|  |         else: | ||||||
|  |             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 setSeq(seq): |  | ||||||
|     # py2&3 fastest way to remove duplicates from a list: |  | ||||||
|     # https://www.rupython.com/x432-4-496.html |  | ||||||
|     seen = set() |  | ||||||
|     seen_add = seen.add |  | ||||||
|     return [x for x in seq if not (x in seen or seen_add(x))] |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def GroupChildRecursion(group, childaliases, treelist): |  | ||||||
|     if treelist[group].children: |  | ||||||
|         for a in treelist[group].children: |  | ||||||
|             GroupChildRecursion(a, childaliases, treelist) |  | ||||||
|     if treelist[group].aliases: |  | ||||||
|         for a in treelist[group].aliases: |  | ||||||
|             childaliases.append(a) |  | ||||||
|     return childaliases |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def GroupChildAliases(group): |  | ||||||
|     aliases = [] |  | ||||||
|     groups = [] |  | ||||||
|     rootgroups = [] |  | ||||||
|     treelist = {} |  | ||||||
|     for a in conf.sections(): |  | ||||||
|         if conf.has_option(a, "group"): |  | ||||||
|             groups.append(a) |  | ||||||
|         elif conf.has_option(a, "exec_string"): |  | ||||||
|             aliases.append(a) |  | ||||||
|     rootaliases = list(aliases) |  | ||||||
|     for g in groups: |  | ||||||
|         treelist[g] = GroupTree(g) |  | ||||||
|         group_aliases = conf.get(g, "group").split() |  | ||||||
|         for ga in group_aliases: |  | ||||||
|             if ga in groups: |  | ||||||
|                 treelist[g].children.append(ga) |  | ||||||
|             elif ga in aliases: |  | ||||||
|                 treelist[g].aliases.append(ga) |  | ||||||
|                 try: |  | ||||||
|                     rootaliases.remove(ga) |  | ||||||
|                 except ValueError: |  | ||||||
|                     pass |  | ||||||
|     for g in groups: |  | ||||||
|         if treelist[g].children: |  | ||||||
|             for child in treelist[g].children: |  | ||||||
|                 treelist[child].parent.append(g) |  | ||||||
|     for g in groups: |  | ||||||
|         if not treelist[g].parent: |  | ||||||
|             rootgroups.append(g) |  | ||||||
|     if group == False: |  | ||||||
|         return aliases, groups, rootaliases, rootgroups, treelist |  | ||||||
|     else: |  | ||||||
|         childaliases = GroupChildRecursion(group, [], treelist) |  | ||||||
|         return setSeq(childaliases) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def GroupTreeRecursion(level, group, treelist, resultalias, resultstring, |  | ||||||
|                         expandlist, previousgroups): |  | ||||||
|     if group in previousgroups: |  | ||||||
|         return resultalias, resultstring |  | ||||||
|     previousgroups.append(group) |  | ||||||
|     resultalias.append(group) |  | ||||||
|     if expandlist == True or group in expandlist: |  | ||||||
|         resultstring.append('  '*(level-1)+">> "+group) |  | ||||||
|         for g in treelist[group].children: |  | ||||||
|             resultalias, resultstring = GroupTreeRecursion(level+1, g, |  | ||||||
|                     treelist, resultalias, resultstring, expandlist, previousgroups) |  | ||||||
|         for ga in treelist[group].aliases: |  | ||||||
|             if conf.has_option(ga, "exec_string"): |  | ||||||
|                 resultalias.append(ga) |  | ||||||
|                 result = "".join(['  '*(level-1)+" ~ ", 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) |  | ||||||
|     else: |  | ||||||
|         resultstring.append('  '*(level-1)+"<> "+group) |  | ||||||
|     return resultalias, resultstring |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def GetTreeList(strings=True, expandlist=True): |  | ||||||
|     resultalias = [] |  | ||||||
|     resultstring = [] |  | ||||||
|     aliases, groups, rootaliases, rootgroups, treelist = GroupChildAliases(False) |  | ||||||
|     for g in rootgroups: |  | ||||||
|         resultalias, resultstring = GroupTreeRecursion(1, g, treelist, |  | ||||||
|                 resultalias, resultstring, expandlist, []) |  | ||||||
|     for a in rootaliases: |  | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def CMDFullList(option, opt, value, parser): | def CMDFullList(option, opt, value, parser): | ||||||
|     for p in GetTreeList(): |     for p in conf.sections(): | ||||||
|         print (p) |         to_print = "".join([str(p), " - ", (conf.get(p, "exec_string") if | ||||||
|  |                             conf.has_option(p, "exec_string") else ""), | ||||||
|  |                             (" [password]" if conf.has_option(p, "password") else "")]) | ||||||
|  |         print(to_print) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def CursesConnect(screen, aliases, command=False): | ||||||
|  |     curses.endwin() | ||||||
|  |     for alias in aliases: | ||||||
|  |         print("Connecting to " + alias + "...") | ||||||
|  |         ConnectAlias(alias, command) | ||||||
|  |         print("... " + alias + " session finished.") | ||||||
|  |     print("Press 'enter' to continue.") | ||||||
|  |     screen.getch() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def CursesExit(error=False): | def CursesExit(error=False): | ||||||
|  | @ -358,21 +161,9 @@ def CursesExit(error=False): | ||||||
|     exit() |     exit() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CursesTextpadEsc(Exception): |  | ||||||
|     "ESC key has been pressed" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def CursesTextpadConfirm(value): | def CursesTextpadConfirm(value): | ||||||
|     if value == 10:                 # Enter |     if value == 10: | ||||||
|         value = 7 |         value = 7 | ||||||
|     elif value == 27:               # Esc |  | ||||||
|         raise CursesTextpadEsc() |  | ||||||
|     elif value == curses.KEY_DC:    # Del |  | ||||||
|         value = curses.ascii.EOT |  | ||||||
|     elif value == curses.KEY_HOME:  # Home |  | ||||||
|         value = curses.ascii.SOH |  | ||||||
|     elif value == curses.KEY_END:   # End |  | ||||||
|         value = curses.ascii.ENQ |  | ||||||
|     return value |     return value | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -425,7 +216,7 @@ def CursesPanel(screen, h, w, y, x, text, | ||||||
|                         position = position - 1 |                         position = position - 1 | ||||||
|                     hidden_password = hidden_password[0:-1] |                     hidden_password = hidden_password[0:-1] | ||||||
|             if keych > 31 and keych < 127: |             if keych > 31 and keych < 127: | ||||||
|                 hidden_password += curses.keyname(keych).decode('utf-8') |                 hidden_password += curses.keyname(keych) | ||||||
|                 sub_window.addstr(1, position, "*", text_colorpair) |                 sub_window.addstr(1, position, "*", text_colorpair) | ||||||
|                 if position < w - 4: |                 if position < w - 4: | ||||||
|                     position += 1 |                     position += 1 | ||||||
|  | @ -445,7 +236,6 @@ def CMDOptions(): | ||||||
| 
 | 
 | ||||||
|         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 = ("".join(["Examples:\n  ", |     epilog = ("".join(["Examples:\n  ", | ||||||
|  | @ -458,7 +248,7 @@ def CMDOptions(): | ||||||
|                        "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 the 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", | ||||||
|  | @ -469,33 +259,24 @@ def CMDOptions(): | ||||||
|     opts.add_option('-a', '--add', action="store", type="string", |     opts.add_option('-a', '--add', action="store", type="string", | ||||||
|                     dest="add", metavar="alias", default=False, |                     dest="add", metavar="alias", default=False, | ||||||
|                     help="add new alias for connection string") |                     help="add new alias for connection string") | ||||||
|     opts.add_option('-g', '--group', action="store", type="string", |  | ||||||
|                     dest="group", metavar="group", default=False, |  | ||||||
|                     help="add new group for aliases") |  | ||||||
|     opts.add_option('-c', '--command', action="store", type="string", |     opts.add_option('-c', '--command', action="store", type="string", | ||||||
|                     dest="command", metavar="command", default=False, |                     dest="command", metavar="command", default=False, | ||||||
|                     help="execute command for aliases and groups") |                     help="add command for executing alias") | ||||||
|     opts.add_option('-t', '--thread', action="store", type="string", |  | ||||||
|                     dest="thread", metavar="command", default=False, |  | ||||||
|                     help="parallel command execution for aliases and groups " + |  | ||||||
|                     "(ssh key authentication or set password required)" ) |  | ||||||
|     opts.add_option('-k', '--keep', action="store", type="string", |     opts.add_option('-k', '--keep', action="store", type="string", | ||||||
|                     dest="keep", metavar="alias", default=False, |                     dest="keep", metavar="alias", default=False, | ||||||
|                     help="hold connection with specified alias") |                     help="hold connection with specified alias") | ||||||
|     opts.add_option('-e', '--edit', action="store", type="string", |     opts.add_option('-e', '--edit', action="store", type="string", | ||||||
|                     dest='edit', metavar="alias", default=False, |                     dest='edit', metavar="alias", default=False, | ||||||
|                     help="edit existing alias or group") |                     help="edit existing connection string") | ||||||
|     opts.add_option('-p', '--password', action="store", type="string", |     opts.add_option('-p', '--password', action="store", type="string", | ||||||
|                     dest='password', metavar="alias", default=False, |                     dest='password', metavar="alias", default=False, | ||||||
|                     help="set and store password for sshpass [UNSAFE]") |                     help="set and store password for sshpass [UNSAFE]") | ||||||
|     opts.add_option('-r', '--remove', action="store", type="string", |     opts.add_option('-r', '--remove', action="store", type="string", | ||||||
|                     dest='remove', metavar="alias", default=False, |                     dest='remove', metavar="alias", default=False, | ||||||
|                     help="remove existing alias or group") |                     help="remove existing alias of connection string") | ||||||
|     options, alias = opts.parse_args() |     options, alias = opts.parse_args() | ||||||
|     if options.add: |     if options.add: | ||||||
|         CMDAdd(options.add) |         CMDAdd(options.add) | ||||||
|     if options.group: |  | ||||||
|         CMDGroup(options.group) |  | ||||||
|     if options.edit: |     if options.edit: | ||||||
|         CMDEdit(options.edit) |         CMDEdit(options.edit) | ||||||
|     if options.password: |     if options.password: | ||||||
|  | @ -504,46 +285,28 @@ def CMDOptions(): | ||||||
|         CMDRemove(options.remove) |         CMDRemove(options.remove) | ||||||
|     if options.keep: |     if options.keep: | ||||||
|         HoldConnection(options.keep) |         HoldConnection(options.keep) | ||||||
|     if options.thread: |     if alias: | ||||||
|         Connect(alias, options.thread, True) |         CMDConnect(alias, options.command) | ||||||
|     elif alias: |  | ||||||
|         Connect(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 = ("".join([" Press:\n", |     help_screen = ("".join([" Press:\n", | ||||||
|         "  'z'/'x', 'w'/'s' or arrows - navigation\n", |                             "  'z'/'x' or arrows - navigation\n", | ||||||
|         "  'a'/'F2' - add new alias (without spaces)\n", |                             "  'a'/'F2' - add new alias\n", | ||||||
|         "  'g'/'F5' - add new group (spaces will be stripped)\n", |                             "  'e'/'F4' - edit existing alias\n", | ||||||
|         "  'e'/'F4' - edit existing alias/group\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' - command execution for alias (group/aliases - in turn)\n", |                             "  'c'/'F3' - execute specific command with selected alias/aliases\n", | ||||||
|         "  't'/'F11' - parallel command execution for aliases and groups\n", |  | ||||||
|         "              (ssh key authentication or set password required)\n", |  | ||||||
|                             "  'k'/'F7' - hold connection with selected alias\n", |                             "  'k'/'F7' - hold connection with selected alias\n", | ||||||
|         "  'enter'/'F9' - connect to selected alias/aliases,\n", |                             "  'enter'/'F9' - connect to selected alias/aliases\n", | ||||||
|         "                 expand/collapse group\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 the config file manually:\n", |                             " Also, you can edit config file manually:\n", | ||||||
|                             "  ", conf_file])) |                             "  ", conf_file])) | ||||||
|     if expand_default == True: |     strings = conf.sections() | ||||||
|         groups = [] |  | ||||||
|         for a in conf.sections(): |  | ||||||
|             if conf.has_option(a, "group"): |  | ||||||
|                 groups.append(a) |  | ||||||
|         expanded = list(groups) |  | ||||||
|         strings = GetTreeList(False, expanded) |  | ||||||
|         stringsfull = GetTreeList(True, expanded) |  | ||||||
|     elif expand_default == False: |  | ||||||
|         groups = [] |  | ||||||
|         expanded = [] |  | ||||||
|         strings = GetTreeList(False, expanded) |  | ||||||
|         stringsfull = GetTreeList(True, expanded) |  | ||||||
|     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)] | ||||||
|     screen = curses.initscr() |     screen = curses.initscr() | ||||||
|  | @ -570,7 +333,14 @@ def CursesMain(): | ||||||
|             box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", |             box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", | ||||||
|                         width - 6, highlight_text) |                         width - 6, highlight_text) | ||||||
|         else: |         else: | ||||||
|             exec_string = ["[", selected_strings[i], "] ", stringsfull[i - 1]] |             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") if conf.has_option(strings[i - 1], | ||||||
|  |                            "exec_string") else ""), ")", password] | ||||||
|             if (i == position): |             if (i == position): | ||||||
|                 box.addnstr(i, 2, "".join(exec_string), width - 6, highlight_text) |                 box.addnstr(i, 2, "".join(exec_string), width - 6, highlight_text) | ||||||
|             else: |             else: | ||||||
|  | @ -591,151 +361,55 @@ def CursesMain(): | ||||||
|                         help_screen, normal_text, highlight_text) |                         help_screen, normal_text, highlight_text) | ||||||
|         if key_pressed == ord('a') or key_pressed == ord( |         if key_pressed == ord('a') or key_pressed == ord( | ||||||
|                 'A') or key_pressed == curses.KEY_F2: |                 'A') or key_pressed == curses.KEY_F2: | ||||||
|             curses.curs_set(1) |  | ||||||
|             new_alias_textpad = CursesTextpad(screen, 1, width - 8, |             new_alias_textpad = CursesTextpad(screen, 1, width - 8, | ||||||
|                                               (height // 2) - 1, 4, "Enter new alias:", "", |                                               (height // 2) - 1, 4, "Enter new alias:", "", | ||||||
|                                               normal_text, highlight_text) |                                               normal_text, highlight_text) | ||||||
|             try: |  | ||||||
|             add_alias = new_alias_textpad.edit(CursesTextpadConfirm) |             add_alias = new_alias_textpad.edit(CursesTextpadConfirm) | ||||||
|             except CursesTextpadEsc: |             if not add_alias.rstrip() == "": | ||||||
|                 add_alias = "" |                 add_result = AddNewAlias(add_alias.rstrip()) | ||||||
|             if not add_alias == "": |                 if not add_result: | ||||||
|                 add_alias = add_alias.split()[0].strip() |                     CursesPanel(screen, 3, | ||||||
|             if not add_alias == "": |                                 width - 6, (height // 2) - 1, 3, add_result, | ||||||
|                 add_result = AddNewAlias(add_alias) |                                 normal_text, highlight_text) | ||||||
|                 if add_result == True: |                 else: | ||||||
|                     add_string = "" |                     add_string = "" | ||||||
|                     try: |                     while add_string.rstrip() == "": | ||||||
|                         while add_string == "": |  | ||||||
|                         string_textpad = CursesTextpad(screen, 3, |                         string_textpad = CursesTextpad(screen, 3, | ||||||
|                                                        width - 8, (height // 2) - 1, 4, |                                                        width - 8, (height // 2) - 1, 4, | ||||||
|                                                        "Enter full execution string:", |                                                        "Enter full execution string:", | ||||||
|                                                        "ssh ", normal_text, highlight_text) |                                                        "ssh ", normal_text, highlight_text) | ||||||
|                         add_string = string_textpad.edit( |                         add_string = string_textpad.edit( | ||||||
|                             CursesTextpadConfirm) |                             CursesTextpadConfirm) | ||||||
|                         SetAliasString(add_alias, |                     SetAliasString(add_alias.rstrip(), | ||||||
|                                    add_string.replace("\n", "").rstrip()) |                                    add_string.replace("\n", "").rstrip()) | ||||||
|                     except CursesTextpadEsc: |                     strings = conf.sections() | ||||||
|                         RemoveAliases([add_alias]) |  | ||||||
|                         add_alias = "" |  | ||||||
|                     strings = GetTreeList(False, expanded) |  | ||||||
|                     stringsfull = GetTreeList(True, expanded) |  | ||||||
|                     row_num = len(strings) |                     row_num = len(strings) | ||||||
|                     selected_strings.append(" ") |                     selected_strings.append(" ") | ||||||
|                     pages = int(ceil(row_num / max_row)) |                     pages = int(ceil(row_num / max_row)) | ||||||
|                     box.refresh() |                     box.refresh() | ||||||
|                 else: |  | ||||||
|                     curses.curs_set(0) |  | ||||||
|                     CursesPanel(screen, 3, |  | ||||||
|                                 width - 6, (height // 2) - 1, 3, add_result, |  | ||||||
|                                 normal_text, highlight_text) |  | ||||||
|             curses.curs_set(0) |  | ||||||
|         if key_pressed == ord('g') or key_pressed == ord( |  | ||||||
|                 'G') or key_pressed == curses.KEY_F5: |  | ||||||
|             curses.curs_set(1) |  | ||||||
|             new_group_textpad = CursesTextpad(screen, 1, width - 8, |  | ||||||
|                 (height // 2) - 1, 4, "Enter group name (without spaces):", "", |  | ||||||
|                 normal_text, highlight_text) |  | ||||||
|             try: |  | ||||||
|                 add_group = new_group_textpad.edit(CursesTextpadConfirm) |  | ||||||
|             except CursesTextpadEsc: |  | ||||||
|                 add_group = "" |  | ||||||
|             if not add_group == "": |  | ||||||
|                 add_group = add_group.split()[0].strip() |  | ||||||
|             if not add_group == "": |  | ||||||
|                 add_result = AddNewAlias(add_group) |  | ||||||
|                 if add_result == True: |  | ||||||
|                     add_string = "" |  | ||||||
|                     try: |  | ||||||
|                         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, |  | ||||||
|                                        add_string.replace("\n", "").rstrip()) |  | ||||||
|                         expanded.append(add_group) |  | ||||||
|                     except CursesTextpadEsc: |  | ||||||
|                         RemoveAliases([add_group]) |  | ||||||
|                         add_group = "" |  | ||||||
|                     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) |  | ||||||
|             curses.curs_set(0) |  | ||||||
|         if (key_pressed == ord('e') or key_pressed == ord( |         if (key_pressed == ord('e') or key_pressed == ord( | ||||||
|                 'E') or key_pressed == curses.KEY_F4) and row_num != 0: |                 'E') or key_pressed == curses.KEY_F4) and row_num != 0: | ||||||
|             edit_string = "" |             edit_string = "" | ||||||
|             groups = [] |  | ||||||
|             for a in conf.sections(): |  | ||||||
|                 if conf.has_option(a, "group"): |  | ||||||
|                     groups.append(a) |  | ||||||
|             curses.curs_set(1) |  | ||||||
|             if strings[position - 1] in groups: |  | ||||||
|                 while edit_string.rstrip() == "": |  | ||||||
|                     string_textpad = CursesTextpad(screen, 3, width - 8, |  | ||||||
|                         (height // 2) - 1, 4, "Enter new aliases for existing group:", |  | ||||||
|                         (conf.get(strings[position - 1], |  | ||||||
|                         "group") if conf.has_option(strings[position - 1], |  | ||||||
|                         "group") else ""), |  | ||||||
|                         normal_text, highlight_text) |  | ||||||
|                     try: |  | ||||||
|                         edit_string = string_textpad.edit(CursesTextpadConfirm) |  | ||||||
|                     except CursesTextpadEsc: |  | ||||||
|                         edit_string = conf.get(strings[position - 1], |  | ||||||
|                             "group") if conf.has_option(strings[position - 1], |  | ||||||
|                             "group") else "" |  | ||||||
|                 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() == "": |             while edit_string.rstrip() == "": | ||||||
|                 string_textpad = CursesTextpad(screen, 3, width - 8, |                 string_textpad = CursesTextpad(screen, 3, width - 8, | ||||||
|                                                (height // 2) - 1, 4, "Enter new execution string:", |                                                (height // 2) - 1, 4, "Enter new execution string:", | ||||||
|                         (conf.get(strings[position - 1].split()[0].strip(), |                                                (conf.get(strings[position - 1], | ||||||
|                         "exec_string") if conf.has_option(strings[position - 1].split()[0].strip(), |                                                "exec_string") if conf.has_option(strings[position - 1], | ||||||
|                                                "exec_string") else ""), |                                                "exec_string") else ""), | ||||||
|                                                normal_text, highlight_text) |                                                normal_text, highlight_text) | ||||||
|                     try: |  | ||||||
|                 edit_string = string_textpad.edit(CursesTextpadConfirm) |                 edit_string = string_textpad.edit(CursesTextpadConfirm) | ||||||
|                     except CursesTextpadEsc: |             SetAliasString(strings[position - 1], | ||||||
|                         edit_string = conf.get(strings[position - 1].split()[0].strip(), |  | ||||||
|                             "exec_string") if conf.has_option(strings[position - 1].split()[0].strip(), |  | ||||||
|                             "exec_string") else "" |  | ||||||
|                 SetAliasString(strings[position - 1].split()[0].strip(), |  | ||||||
|                            edit_string.replace("\n", "").rstrip()) |                            edit_string.replace("\n", "").rstrip()) | ||||||
|                 strings = GetTreeList(False, expanded) |             strings = conf.sections() | ||||||
|                 stringsfull = GetTreeList(True, expanded) |  | ||||||
|             curses.curs_set(0) |  | ||||||
|         if (key_pressed == ord('p') or key_pressed == ord( |         if (key_pressed == ord('p') or key_pressed == ord( | ||||||
|                 'P') or key_pressed == curses.KEY_F6) and row_num != 0: |                 'P') or key_pressed == curses.KEY_F6) and row_num != 0: | ||||||
|             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 = "" | ||||||
|             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':\n>", |                                        " Enter user password for sshpass and press 'enter':\n>", | ||||||
|                                        normal_text, highlight_text, "password") |                                        normal_text, highlight_text, "password") | ||||||
|                 SetPassword(strings[position - 1].split()[0].strip(), set_password) |             if not set_password == "": | ||||||
|                 strings = GetTreeList(False, expanded) |                 SetPassword(strings[position - 1], set_password) | ||||||
|                 stringsfull = GetTreeList(True, expanded) |  | ||||||
|         if (key_pressed == ord('r') or key_pressed == ord( |         if (key_pressed == ord('r') or key_pressed == ord( | ||||||
|                 'R') or key_pressed == curses.KEY_F8 or key_pressed == ( |                 'R') or key_pressed == curses.KEY_F8 or key_pressed == ( | ||||||
|                 curses.KEY_DC)) and row_num != 0: |                 curses.KEY_DC)) and row_num != 0: | ||||||
|  | @ -749,15 +423,14 @@ def CursesMain(): | ||||||
|                              str(len(selected)), " selected aliases? (y/N)"])) |                              str(len(selected)), " selected aliases? (y/N)"])) | ||||||
|             else: |             else: | ||||||
|                 remove_confirm = ("".join(["Are you sure to remove '", |                 remove_confirm = ("".join(["Are you sure to remove '", | ||||||
|                     strings[position - 1].split()[0].strip(), "' alias? (y/N)"])) |                                            strings[position - 1], "' alias? (y/N)"])) | ||||||
|                 selected.append(strings[position - 1].split()[0].strip()) |                 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, | ||||||
|                                         highlight_text, "remove") |                                         highlight_text, "remove") | ||||||
|             if remove_result == "confirm": |             if remove_result == "confirm": | ||||||
|                 RemoveAliases(selected) |                 RemoveAliases(selected) | ||||||
|                 strings = GetTreeList(False, expanded) |                 strings = conf.sections() | ||||||
|                 stringsfull = GetTreeList(True, expanded) |  | ||||||
|                 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)] | ||||||
|                 pages = int(ceil(row_num / max_row)) |                 pages = int(ceil(row_num / max_row)) | ||||||
|  | @ -771,78 +444,29 @@ def CursesMain(): | ||||||
|                 if selected_strings[i] == "*": |                 if selected_strings[i] == "*": | ||||||
|                     selected.append(strings[i - 1]) |                     selected.append(strings[i - 1]) | ||||||
|             if not len(selected) > 0: |             if not len(selected) > 0: | ||||||
|                 selected.append(strings[position - 1].split()[0].strip()) |                 selected.append(strings[position - 1]) | ||||||
|             curses.curs_set(1) |  | ||||||
|             command_textpad = CursesTextpad(screen, 3, width - 8, |             command_textpad = CursesTextpad(screen, 3, width - 8, | ||||||
|                                             (height // 2) - 1, 4, |                                             (height // 2) - 1, 4, | ||||||
|                                             "".join([ |                                             "".join([ | ||||||
|                                                 "Enter specific command to execute with selected ", |                                                 "Enter specific command to execute with selected ", | ||||||
|                                                 "alias/aliases:"] |                                                 "alias/aliases:"] | ||||||
|                                             ), "", normal_text, highlight_text) |                                             ), "", normal_text, highlight_text) | ||||||
|             try: |  | ||||||
|             command_string = command_textpad.edit(CursesTextpadConfirm) |             command_string = command_textpad.edit(CursesTextpadConfirm) | ||||||
|                 Connect(selected, command_string.replace("\n", "").rstrip(),  |             CursesConnect(screen, selected, | ||||||
|                         False, screen) |                           command_string.replace("\n", "").rstrip()) | ||||||
|             except CursesTextpadEsc: |  | ||||||
|                 command_string = "" |  | ||||||
|             curses.curs_set(0) |  | ||||||
|         if (key_pressed == ord('t') or key_pressed == ord( |  | ||||||
|                 'T') or key_pressed == curses.KEY_F11) and row_num != 0: |  | ||||||
|             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()) |  | ||||||
|             curses.curs_set(1) |  | ||||||
|             command_textpad = CursesTextpad(screen, 3, width - 8, |  | ||||||
|                 (height // 2) - 1, 4, |  | ||||||
|                 "".join([ |  | ||||||
|                     "Enter specific command to execute with selected ", |  | ||||||
|                     "alias/aliases:"] |  | ||||||
|                 ), "", normal_text, highlight_text) |  | ||||||
|             try: |  | ||||||
|                 command_string = command_textpad.edit(CursesTextpadConfirm) |  | ||||||
|                 Connect(selected, command_string.replace("\n", "").rstrip(), |  | ||||||
|                         True, screen) |  | ||||||
|             except CursesTextpadEsc: |  | ||||||
|                 command_string = "" |  | ||||||
|             curses.curs_set(0) |  | ||||||
|         if (key_pressed == ord('k') or key_pressed == ord('K') or |         if (key_pressed == ord('k') or key_pressed == ord('K') or | ||||||
|                 key_pressed == (curses.KEY_F7)) and row_num != 0: |                 key_pressed == (curses.KEY_F7)) and row_num != 0: | ||||||
|             groups = [] |  | ||||||
|             for a in conf.sections(): |  | ||||||
|                 if conf.has_option(a, "group"): |  | ||||||
|                     groups.append(a) |  | ||||||
|             if not strings[position - 1] in groups: |  | ||||||
|             curses.endwin() |             curses.endwin() | ||||||
|                 HoldConnection(strings[position - 1].split()[0].strip()) |             HoldConnection(strings[position - 1]) | ||||||
|         if (key_pressed == ord("\n") or key_pressed == ( |         if (key_pressed == ord("\n") or key_pressed == ( | ||||||
|                 curses.KEY_F9)) and row_num != 0: |                 curses.KEY_F9)) and row_num != 0: | ||||||
|             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 = [] |             selected = [] | ||||||
|             for i in range(1, row_num + 1): |             for i in range(1, row_num + 1): | ||||||
|                 if selected_strings[i] == "*": |                 if selected_strings[i] == "*": | ||||||
|                     selected.append(strings[i - 1]) |                     selected.append(strings[i - 1]) | ||||||
|             if not len(selected) > 0: |             if not len(selected) > 0: | ||||||
|                     selected.append(strings[position - 1].split()[0].strip()) |                 selected.append(strings[position - 1]) | ||||||
|                 Connect(selected, False, False, screen) |             CursesConnect(screen, selected) | ||||||
|             selected_strings = [" " for i in range(0, row_num + 1)] |  | ||||||
|         if (key_pressed == 32 or key_pressed == ( |         if (key_pressed == 32 or key_pressed == ( | ||||||
|                 curses.KEY_IC)) and row_num != 0: |                 curses.KEY_IC)) and row_num != 0: | ||||||
|             if selected_strings[position] == ' ': |             if selected_strings[position] == ' ': | ||||||
|  | @ -866,8 +490,7 @@ def CursesMain(): | ||||||
|                     page = page + 1 |                     page = page + 1 | ||||||
|                     position = 1 + (max_row * (page - 1)) |                     position = 1 + (max_row * (page - 1)) | ||||||
|         if key_pressed == curses.KEY_DOWN or key_pressed == ord( |         if key_pressed == curses.KEY_DOWN or key_pressed == ord( | ||||||
|                 'x') or key_pressed == ord('X') or key_pressed == ord( |                 'x') or key_pressed == ord('X'): | ||||||
|                 's') or key_pressed == ord('S'): |  | ||||||
|             if page == 1: |             if page == 1: | ||||||
|                 if position < i: |                 if position < i: | ||||||
|                     position = position + 1 |                     position = position + 1 | ||||||
|  | @ -885,8 +508,7 @@ def CursesMain(): | ||||||
|                     page = page + 1 |                     page = page + 1 | ||||||
|                     position = 1 + (max_row * (page - 1)) |                     position = 1 + (max_row * (page - 1)) | ||||||
|         if key_pressed == curses.KEY_UP or key_pressed == ord( |         if key_pressed == curses.KEY_UP or key_pressed == ord( | ||||||
|                 'z') or key_pressed == ord('Z') or key_pressed == ord( |                 'z') or key_pressed == ord('Z'): | ||||||
|                 'w') or key_pressed == ord('W'): |  | ||||||
|             if page == 1: |             if page == 1: | ||||||
|                 if position > 1: |                 if position > 1: | ||||||
|                     position = position - 1 |                     position = position - 1 | ||||||
|  | @ -906,12 +528,6 @@ def CursesMain(): | ||||||
|             if page < pages: |             if page < pages: | ||||||
|                 page = page + 1 |                 page = page + 1 | ||||||
|                 position = (1 + (max_row * (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 |  | ||||||
|         box.erase() |         box.erase() | ||||||
|         screen.border(0) |         screen.border(0) | ||||||
|         box.border(0) |         box.border(0) | ||||||
|  | @ -921,7 +537,14 @@ def CursesMain(): | ||||||
|                 box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", |                 box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", | ||||||
|                             width - 6, highlight_text) |                             width - 6, highlight_text) | ||||||
|             else: |             else: | ||||||
|                 exec_string = ["[", selected_strings[i], "] ", stringsfull[i - 1]] |                 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") if conf.has_option(strings[i - 1], | ||||||
|  |                                "exec_string") else ""), ")", password] | ||||||
|                 if (i + (max_row * (page - 1)) == (position + (max_row * (page - 1)))): |                 if (i + (max_row * (page - 1)) == (position + (max_row * (page - 1)))): | ||||||
|                     box.addnstr(i - (max_row * (page - 1)), 2, "".join( |                     box.addnstr(i - (max_row * (page - 1)), 2, "".join( | ||||||
|                         exec_string), width - 6, highlight_text) |                         exec_string), width - 6, highlight_text) | ||||||
|  | @ -942,29 +565,10 @@ if __name__ == "__main__": | ||||||
|     except NameError: |     except NameError: | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|     if not path.exists(conf_dir): |  | ||||||
|         try: |  | ||||||
|             from os import makedirs  |  | ||||||
|             makedirs(conf_dir) |  | ||||||
|         except: |  | ||||||
|             print("Can't make dir " + conf_dir) |  | ||||||
|             exit() |  | ||||||
| 
 |  | ||||||
|     conf = configparser.RawConfigParser() |     conf = configparser.RawConfigParser() | ||||||
| 
 |  | ||||||
|     if not path.exists(conf_file): |     if not path.exists(conf_file): | ||||||
|         try: |  | ||||||
|         open(conf_file, 'w') |         open(conf_file, 'w') | ||||||
|         except: |  | ||||||
|             print("Can't make file at " + conf_dir) |  | ||||||
|             exit() |  | ||||||
|      |  | ||||||
|     try: |  | ||||||
|     conf.read(conf_file) |     conf.read(conf_file) | ||||||
|     except: |  | ||||||
|         print("Error: can't read config file " + conf_file) |  | ||||||
|         exit() |  | ||||||
| 
 |  | ||||||
|     if len(argv) > 1: |     if len(argv) > 1: | ||||||
|         try: |         try: | ||||||
|             CMDOptions() |             CMDOptions() | ||||||
|  | @ -973,10 +577,6 @@ if __name__ == "__main__": | ||||||
|         except configparser.Error: |         except configparser.Error: | ||||||
|             print("Error: can't parse your config file, please check it manually or make new one") |             print("Error: can't parse your config file, please check it manually or make new one") | ||||||
|             exit() |             exit() | ||||||
|         except IOError: |  | ||||||
|             print("Error: can't use your config file, please check permissionss of " + conf_file) |  | ||||||
|             exit() |  | ||||||
| 
 |  | ||||||
|     else: |     else: | ||||||
|         try: |         try: | ||||||
|             CursesMain() |             CursesMain() | ||||||
|  | @ -988,6 +588,3 @@ if __name__ == "__main__": | ||||||
|         except curses.error: |         except curses.error: | ||||||
|             CursesExit("".join(["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"])) | ||||||
|         except IOError: |  | ||||||
|             CursesExit("".join(["Error: can't use your config file, please ", |  | ||||||
|                        "check permissionss of ", conf_file])) |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue