Compare commits
	
		
			No commits in common. "master" and "Difrex/master" have entirely different histories.
		
	
	
		
			master
			...
			Difrex/mas
		
	
		
							
								
								
									
										21
									
								
								LICENSE
								
								
								
								
							
							
						
						
									
										21
									
								
								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. | ||||
| 
 | ||||
| Boundless Public License | ||||
| DO WHAT THOU WILT | ||||
| DO WHAT THAU WILT | ||||
| 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 | ||||
| 
 | ||||
| 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.  | ||||
| 
 | ||||
| The license provides more freedom than any other one (such as GPL or BSD) and does not require saving the license text on copying. | ||||
| DWTW – a license with a single requirement: DO WHAT THOU WILT  | ||||
| 
 | ||||
| DWTWL – an accomplished and eligible license for free text, code and any other symbols (including the software, documentation and artwork). | ||||
| 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 does not contain a "no warranty" clause. DWTWL can be used in countries that do not legally acknowledge the transition to public domain. | ||||
| DWTW – an accomplished and eligible license for free text (including the software, documentation and artwork).  | ||||
| 
 | ||||
| Summary: | ||||
| The license does not contain "no warranty" clause. DWTW can be used in countries that do not legally acknowledge the transition to public domain.  | ||||
| 
 | ||||
| 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. | ||||
| Summary:  | ||||
| 
 | ||||
| An author-creator gives his or her source code to the world for free, without becoming distracted by worldly thinking regarding how and why the others will use it. | ||||
|  |  | |||
							
								
								
									
										40
									
								
								README.md
								
								
								
								
							
							
						
						
									
										40
									
								
								README.md
								
								
								
								
							|  | @ -1,49 +1,25 @@ | |||
| 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 compatible with pyhon2 and python3, no additional libraries are required | ||||
| sshch is released under DWTWL 2.5 license | ||||
| ### Screenshot | ||||
|  | ||||
| 
 | ||||
|  | ||||
| ### 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: | ||||
| ```bash | ||||
| ``` | ||||
| sudo python setup.py install | ||||
| ``` | ||||
| To install just for current user: | ||||
| ```bash | ||||
| ``` | ||||
| mkdir ~/.local/bin | ||||
| cp sshch/sshch ~/.local/bin/ | ||||
| ``` | ||||
| ### Using | ||||
| To run curses interface: | ||||
| ```bash | ||||
| ``` | ||||
| sshch | ||||
| ``` | ||||
| To run command line help: | ||||
| ```bash | ||||
| ``` | ||||
| sshch -h | ||||
| ``` | ||||
| For exit from current ssh session press `Ctrl+D`. | ||||
| 
 | ||||
| **Additional Features** | ||||
| - 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/: | ||||
| ```bash | ||||
| sudo cp completion/sshch_bash_completion.sh /etc/bash_completion.d/sshch | ||||
| ``` | ||||
| (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' | ||||
| **If you want to use unsafe 'password' feature you must install 'sshpass' first.** | ||||
|  | @ -1,11 +0,0 @@ | |||
| _sshch_complete() | ||||
| { | ||||
|         local cur_word alias_list | ||||
|         cur_word="${COMP_WORDS[COMP_CWORD]}" | ||||
|         alias_list=`sshch -l` | ||||
|         COMPREPLY=($(compgen -W "$alias_list" -- $cur_word)) | ||||
|         return 0 | ||||
| } | ||||
| 
 | ||||
| complete -F _sshch_complete sshch | ||||
| 
 | ||||
|  | @ -1,27 +0,0 @@ | |||
| #compdef sshch | ||||
| # | ||||
| # ZSH Completion for SSHCH | ||||
| # Usage: | ||||
| #  1) Place File in a Directory where ZSH can find it | ||||
| #     -> Search Path is Stored in $fpath | ||||
| #     -> echo $fpath | ||||
| #  2) Rename File to '_sshch' | ||||
| # | ||||
| _arguments '::aliasname:->getAlias' \ | ||||
| 	   '-e[Edit Alias]:aliasname:->getAlias' '--edit[Edit Alias]:aliasname:->getAlias' \ | ||||
| 	   '-p[Set Password]:aliasname:->getAlias' '--password[Set Password]:aliasname:->getAlias' \ | ||||
| 	   '-r[Remove Alias]:aliasname:->getAlias' '--remove[Remove Alias]:aliasname:->getAlias' \ | ||||
| 	   '-k[Keep Connection]:aliasname:->getAlias' '--keep[Keep Connection]:aliasname:->getAlias' \ | ||||
|            '-a[Add Alias]'     '--add[Add Alias]'\ | ||||
|            '-c[Add Command for Executing Alias]'     '--command[Add Command for Executing Alias]'\ | ||||
|            '-h[Show Help Message]'     '--help[Show Help Message]'\ | ||||
|            '-l[List Existing Alias]' '--list[List Existing Alias]'\ | ||||
|            '-f[List Existing Alias with Connection String]' '--fulllist[List Existing Alias with Connection String]'\ | ||||
|            '--version[Show Program Version]' | ||||
| case "$state" in | ||||
|     getAlias) | ||||
|         local -a alias_list | ||||
|         alias_list=($(sshch -l)) | ||||
| 	_values -s ' '  'Aliases' $alias_list | ||||
|         ;; | ||||
| esac | ||||
							
								
								
									
										17
									
								
								setup.py
								
								
								
								
							
							
						
						
									
										17
									
								
								setup.py
								
								
								
								
							|  | @ -7,27 +7,22 @@ def main(): | |||
| 
 | ||||
|     setup(name='sshch', | ||||
|           author='zlaxy', | ||||
|           author_email='zlaxyi@gmail.com', | ||||
|           url='https://gitlab.com/zlax/sshch', | ||||
|           description='Ssh connection and aliases manager', | ||||
|           long_description='SSH connection and aliases manager with curses and command line interface', | ||||
|           long_description_content_type='text/x-rst', | ||||
|           license='DWTWL 2.55', | ||||
|           version='1.09.7', | ||||
|           url='https://github.com/zlaxy/sshch/', | ||||
|           description='Ssh connection manager', | ||||
|           license='DWTWL 2.5', | ||||
|           version='0.55', | ||||
|           py_modules=['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 | ||||
|           classifiers=[ | ||||
|               'Development Status :: 5 - Production/Stable', | ||||
|               'Development Status :: 4 - Beta', | ||||
|               'Environment :: Console :: Curses', | ||||
|               'Intended Audience :: System Administrators', | ||||
|               'License :: Freeware', | ||||
|               'Natural Language :: English', | ||||
|               'Operating System :: POSIX', | ||||
|               'Programming Language :: Python', | ||||
|               'Programming Language :: Python :: 2.7', | ||||
|               'Topic :: Internet', | ||||
|               'Topic :: System :: Networking', | ||||
|               'Topic :: System :: Systems Administration', | ||||
|  |  | |||
							
								
								
									
										777
									
								
								sshch/sshch
								
								
								
								
							
							
						
						
									
										777
									
								
								sshch/sshch
								
								
								
								
							|  | @ -2,41 +2,21 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| 
 | ||||
| from __future__ import division | ||||
| from __future__ import print_function | ||||
| try: | ||||
|     import configparser | ||||
| except ImportError: | ||||
|     import ConfigParser as configparser  # Python 2.x import | ||||
|     import locale | ||||
|     locale.setlocale(locale.LC_ALL, '') | ||||
| from os import path | ||||
| from sys import argv | ||||
| from math import ceil | ||||
| from getpass import getpass | ||||
| from optparse import OptionParser | ||||
| from curses import textpad | ||||
| import ConfigParser | ||||
| import subprocess | ||||
| import base64 | ||||
| import time | ||||
| import curses | ||||
| from curses import textpad, panel | ||||
| from threading import Thread | ||||
| 
 | ||||
| # https://gitlab.com/zlax/sshch | ||||
| version = "1.09.7" | ||||
| # expand groups by default | ||||
| expand_default = True | ||||
| # 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 = [] | ||||
| # https://github.com/zlaxy/sshch | ||||
| version = "0.55" | ||||
| # path to conf file, default: ~/.config/sshch.conf | ||||
| conf_file = path.expanduser("~") + '/.config/sshch.conf' | ||||
| 
 | ||||
| 
 | ||||
| def AddNewAlias(alias): | ||||
|  | @ -45,7 +25,7 @@ def AddNewAlias(alias): | |||
|         conf.write(open(conf_file, "w")) | ||||
|         return True | ||||
|     else: | ||||
|         return "error: '" + alias + "' alias or group already exists" | ||||
|         return "error: '" + alias + "' already exists" | ||||
| 
 | ||||
| 
 | ||||
| def SetAliasString(alias, string): | ||||
|  | @ -53,20 +33,10 @@ def SetAliasString(alias, string): | |||
|     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): | ||||
|     if string == "" or string == b'': | ||||
|         conf.remove_option(alias, "password") | ||||
|     else: | ||||
|         string = string.encode() | ||||
|         string = base64.b64encode(base64.b16encode( | ||||
|                                   base64.b32encode(string))) | ||||
|         string = string.decode('utf-8') | ||||
|         conf.set(alias, "password", string) | ||||
|     string = base64.b64encode(base64.b16encode( | ||||
|                               base64.b32encode(string))) | ||||
|     conf.set(alias, "password", string) | ||||
|     conf.write(open(conf_file, "w")) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -76,303 +46,107 @@ def RemoveAliases(aliases): | |||
|         conf.write(open(conf_file, "w")) | ||||
| 
 | ||||
| 
 | ||||
| def ConvertPassword(password): | ||||
|     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): | ||||
| def ConnectAlias(alias, command=False): | ||||
|     print "Connecting to " + alias + "..." | ||||
|     exec_string = "" | ||||
|     if conf.has_option(alias, "password"): | ||||
|         password = base64.b32decode(base64.b16decode( | ||||
|                                     base64.b64decode(conf.get(alias, "password")))) | ||||
|         exec_string = "sshpass -p " + ConvertPassword(password.decode('utf-8')) + " " | ||||
|     if conf.has_option(alias, "exec_string"): | ||||
|         exec_string = exec_string + conf.get(alias, "exec_string") | ||||
|             base64.b64decode(conf.get(alias, "password")))) | ||||
|         exec_string = "sshpass -p " + password + " " | ||||
|     exec_string = exec_string + conf.get(alias, "exec_string") | ||||
|     if command: | ||||
|         exec_string = exec_string + " " + command | ||||
|     try: | ||||
|         subprocess.Popen(exec_string, shell=True).communicate()[0] | ||||
|     except: | ||||
|         pass | ||||
|     if threading: | ||||
|         print ("... "+alias+" session output finished.") | ||||
| 
 | ||||
| 
 | ||||
| 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.") | ||||
|         time.sleep(1) | ||||
|         while True: | ||||
|             ConnectAlias(alias) | ||||
|             time.sleep(5) | ||||
|     # Variables bellow is newer used | ||||
|     subprocess.Popen(exec_string, shell=True) | ||||
|     # p.communicate()[0] | ||||
|     print "... " + alias + " session finished." | ||||
| 
 | ||||
| 
 | ||||
| def CMDAdd(alias): | ||||
|     alias = alias.split()[0].strip() | ||||
|     result = AddNewAlias(alias) | ||||
|     if result == True: | ||||
|     if result: | ||||
|         prompt_add = ("".join(["Enter connection string for new alias ", | ||||
|                                "(example: ssh user@somehost.com):\n"])) | ||||
|         string = "" | ||||
|         while string == "": | ||||
|             string = input(prompt_add) | ||||
|             string = raw_input(prompt_add) | ||||
|         SetAliasString(alias, string) | ||||
|     else: | ||||
|         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) | ||||
|         print result | ||||
| 
 | ||||
| 
 | ||||
| def CMDEdit(alias): | ||||
|     if conf.has_section(alias): | ||||
|         if conf.has_option(alias, "exec_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") | ||||
|         prompt_edit = ("".join(["Enter connection string for existing alias ", | ||||
|                        "(example: ssh user@somehost.com):\n"])) | ||||
|         string = "" | ||||
|         while string == "": | ||||
|             string = raw_input(prompt_edit) | ||||
|         SetAliasString(alias, string) | ||||
|     else: | ||||
|         print("error: '" + alias + "' alias or group does not exists") | ||||
|         print "error: '" + alias + "' alias is 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 (Ctrl+C" + | ||||
|                             " - cancel, blank - clear password):\n") | ||||
|             string = "" | ||||
|             string = getpass(prompt_pass) | ||||
|     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") | ||||
|     else: | ||||
|         print "error: '" + alias + "' alias is not exists" | ||||
| 
 | ||||
| 
 | ||||
| def CMDRemove(alias): | ||||
|     if conf.has_section(alias): | ||||
|         prompt_remove = ("Type 'yes' if you sure to remove '" + alias + | ||||
|                          "' alias or group: ") | ||||
|         string = input(prompt_remove) | ||||
|         prompt_remove = ("Type 'yes' if you sure to remove '" + alias + "' alias: ") | ||||
|         string = raw_input(prompt_remove) | ||||
|         if string == "yes": | ||||
|             RemoveAliases([alias]) | ||||
|         else: | ||||
|             print("'" + alias + "' alias or group was not deleted.") | ||||
|             print "'" + alias + "' alias was not deleted." | ||||
|     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): | ||||
|             ConnectAlias(alias, command) | ||||
|         else: | ||||
|             print "error: '" + alias + "' alias is not exists" | ||||
| 
 | ||||
| 
 | ||||
| def CMDList(option, opt, value, parser): | ||||
|     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 | ||||
|     print ', '.join(str(p) for p in conf.sections()) | ||||
| 
 | ||||
| 
 | ||||
| def CMDFullList(option, opt, value, parser): | ||||
|     for p in GetTreeList(): | ||||
|         print (p) | ||||
|     for p in conf.sections(): | ||||
|         to_print = "".join([str(p), " - ", conf.get(p, "exec_string"), | ||||
|                             (" [password]" if conf.has_option(p, "password") else ""), "\n"]) | ||||
|         print(to_print) | ||||
| 
 | ||||
| 
 | ||||
| def CursesConnect(screen, aliases, command=False): | ||||
|     curses.endwin() | ||||
|     for alias in aliases: | ||||
|         ConnectAlias(alias, command) | ||||
|     print "Press 'enter' to continue." | ||||
|     screen.getch() | ||||
| 
 | ||||
| 
 | ||||
| def CursesExit(error=False): | ||||
|     curses.endwin() | ||||
|     if error: | ||||
|         print(error) | ||||
|         print error | ||||
|     exit() | ||||
| 
 | ||||
| 
 | ||||
| class CursesTextpadEsc(Exception): | ||||
|     "ESC key has been pressed" | ||||
| 
 | ||||
| 
 | ||||
| def CursesTextpadConfirm(value): | ||||
|     if value == 10:                 # Enter | ||||
|     if value == 10: | ||||
|         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 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -402,7 +176,7 @@ def CursesPanel(screen, h, w, y, x, text, | |||
|     new_window.attroff(deco_colorpair) | ||||
|     sub_window = new_window.subwin(h - 2, w - 2, y + 1, x + 1) | ||||
|     sub_window.insstr(0, 0, text) | ||||
|     panel = curses.panel.new_panel(new_window) | ||||
|     curses.panel.new_panel(new_window) | ||||
|     curses.panel.update_panels() | ||||
|     screen.refresh() | ||||
|     if confirm == "password": | ||||
|  | @ -425,7 +199,7 @@ def CursesPanel(screen, h, w, y, x, text, | |||
|                         position = position - 1 | ||||
|                     hidden_password = hidden_password[0:-1] | ||||
|             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) | ||||
|                 if position < w - 4: | ||||
|                     position += 1 | ||||
|  | @ -445,20 +219,19 @@ def CMDOptions(): | |||
| 
 | ||||
|         def format_epilog(self, formatter): | ||||
|             return self.epilog | ||||
| 
 | ||||
|     usage = "usage: %prog [options] [aliases]" | ||||
|     progname = path.basename(__file__) | ||||
|     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 the config file manually: ", conf_file, "\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"])) | ||||
|     opts = FormatedParser(usage=usage, version="%prog " + version, | ||||
|                           epilog=epilog) | ||||
|     opts.add_option('-l', '--list', action="callback", | ||||
|  | @ -469,81 +242,48 @@ def CMDOptions(): | |||
|     opts.add_option('-a', '--add', action="store", type="string", | ||||
|                     dest="add", metavar="alias", default=False, | ||||
|                     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", | ||||
|                     dest="command", metavar="command", default=False, | ||||
|                     help="execute command for aliases and groups") | ||||
|     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", | ||||
|                     dest="keep", metavar="alias", default=False, | ||||
|                     help="hold connection with specified alias") | ||||
|                     help="add command for executing alias") | ||||
|     opts.add_option('-e', '--edit', action="store", type="string", | ||||
|                     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", | ||||
|                     dest='password', metavar="alias", default=False, | ||||
|                     help="set and store password for sshpass [UNSAFE]") | ||||
|     opts.add_option('-r', '--remove', action="store", type="string", | ||||
|                     dest='remove', metavar="alias", default=False, | ||||
|                     help="remove existing alias or group") | ||||
|                     help="remove existing alias of connection string") | ||||
|     options, alias = opts.parse_args() | ||||
|     if options.add: | ||||
|         CMDAdd(options.add) | ||||
|     if options.group: | ||||
|         CMDGroup(options.group) | ||||
|     if options.edit: | ||||
|         CMDEdit(options.edit) | ||||
|     if options.password: | ||||
|         CMDPassword(options.password) | ||||
|     if options.remove: | ||||
|         CMDRemove(options.remove) | ||||
|     if options.keep: | ||||
|         HoldConnection(options.keep) | ||||
|     if options.thread: | ||||
|         Connect(alias, options.thread, True) | ||||
|     elif alias: | ||||
|         Connect(alias, options.command) | ||||
|     if alias: | ||||
|         CMDConnect(alias, options.command) | ||||
| 
 | ||||
| # curses template from: https://stackoverflow.com/a/30828805/6224462 | ||||
| 
 | ||||
| 
 | ||||
| def CursesMain(): | ||||
|     help_screen = ("".join([" Press:\n", | ||||
|         "  'z'/'x', 'w'/'s' or arrows - navigation\n", | ||||
|         "  'a'/'F2' - add new alias (without spaces)\n", | ||||
|         "  'g'/'F5' - add new group (spaces will be stripped)\n", | ||||
|         "  'e'/'F4' - edit existing alias/group\n", | ||||
|         "  'p'/'F6' - set alias's password for sshpass [UNSAFE]\n", | ||||
|         "  'space'/'insert' - select\n", | ||||
|         "  'r'/'F8' - remove selected alias/aliases\n", | ||||
|         "  'c'/'F3' - command execution for alias (group/aliases - in turn)\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", | ||||
|         "  'enter'/'F9' - connect to selected alias/aliases,\n", | ||||
|         "                 expand/collapse group\n", | ||||
|         "  'q'/'F10' - quit\n", | ||||
|         " Run program with '--help' option to view command line help.\n", | ||||
|         " Also, you can edit the config file manually:\n", | ||||
|         "  ", conf_file])) | ||||
|     if expand_default == True: | ||||
|         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) | ||||
|                             "  'z'/'x' or arrows - navigation\n", | ||||
|                             "  'a'/'F2' - add new alias\n", | ||||
|                             "  'e'/'F4' - edit existing alias\n", | ||||
|                             "  '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", | ||||
|                             "  'enter'/'F9' - connect to selected alias/aliases\n", | ||||
|                             "  '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])) | ||||
|     strings = conf.sections() | ||||
|     row_num = len(strings) | ||||
|     selected_strings = [" " for i in range(0, row_num + 1)] | ||||
|     screen = curses.initscr() | ||||
|  | @ -570,7 +310,13 @@ def CursesMain(): | |||
|             box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", | ||||
|                         width - 6, highlight_text) | ||||
|         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"), | ||||
|                            ")", password] | ||||
|             if (i == position): | ||||
|                 box.addnstr(i, 2, "".join(exec_string), width - 6, highlight_text) | ||||
|             else: | ||||
|  | @ -591,151 +337,53 @@ def CursesMain(): | |||
|                         help_screen, normal_text, highlight_text) | ||||
|         if key_pressed == ord('a') or key_pressed == ord( | ||||
|                 'A') or key_pressed == curses.KEY_F2: | ||||
|             curses.curs_set(1) | ||||
|             new_alias_textpad = CursesTextpad(screen, 1, width - 8, | ||||
|                 (height // 2) - 1, 4, "Enter new alias:", "", | ||||
|                 normal_text, highlight_text) | ||||
|             try: | ||||
|                 add_alias = new_alias_textpad.edit(CursesTextpadConfirm) | ||||
|             except CursesTextpadEsc: | ||||
|                 add_alias = "" | ||||
|             if not add_alias == "": | ||||
|                 add_alias = add_alias.split()[0].strip() | ||||
|             if not add_alias == "": | ||||
|                 add_result = AddNewAlias(add_alias) | ||||
|                 if add_result == True: | ||||
|                                               (height // 2) - 1, 4, "Enter new alias:", "", | ||||
|                                               normal_text, highlight_text) | ||||
|             add_alias = new_alias_textpad.edit(CursesTextpadConfirm) | ||||
|             if not add_alias.rstrip() == "": | ||||
|                 add_result = AddNewAlias(add_alias.rstrip()) | ||||
|                 if not add_result: | ||||
|                     CursesPanel(screen, 3, | ||||
|                                 width - 6, (height // 2) - 1, 3, add_result, | ||||
|                                 normal_text, highlight_text) | ||||
|                 else: | ||||
|                     add_string = "" | ||||
|                     try: | ||||
|                         while add_string == "": | ||||
|                             string_textpad = CursesTextpad(screen, 3, | ||||
|                                 width - 8, (height // 2) - 1, 4, | ||||
|                                 "Enter full execution string:", | ||||
|                                 "ssh ", normal_text, highlight_text) | ||||
|                             add_string = string_textpad.edit( | ||||
|                                 CursesTextpadConfirm) | ||||
|                         SetAliasString(add_alias, | ||||
|                                        add_string.replace("\n", "").rstrip()) | ||||
|                     except CursesTextpadEsc: | ||||
|                         RemoveAliases([add_alias]) | ||||
|                         add_alias = "" | ||||
|                     strings = GetTreeList(False, expanded) | ||||
|                     stringsfull = GetTreeList(True, expanded) | ||||
|                     while add_string.rstrip() == "": | ||||
|                         string_textpad = CursesTextpad(screen, 3, | ||||
|                                                        width - 8, (height // 2) - 1, 4, | ||||
|                                                        "Enter full execution string:", | ||||
|                                                        "ssh ", normal_text, highlight_text) | ||||
|                         add_string = string_textpad.edit( | ||||
|                             CursesTextpadConfirm) | ||||
|                     SetAliasString(add_alias.rstrip(), | ||||
|                                    add_string.replace("\n", "").rstrip()) | ||||
|                     strings = conf.sections() | ||||
|                     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) | ||||
|             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( | ||||
|                 'E') or key_pressed == curses.KEY_F4) and row_num != 0: | ||||
|             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() == "": | ||||
|                     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) | ||||
|                     try: | ||||
|                         edit_string = string_textpad.edit(CursesTextpadConfirm) | ||||
|                     except CursesTextpadEsc: | ||||
|                         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()) | ||||
|                 strings = GetTreeList(False, expanded) | ||||
|                 stringsfull = GetTreeList(True, expanded) | ||||
|             curses.curs_set(0) | ||||
|             while edit_string.rstrip() == "": | ||||
|                 string_textpad = CursesTextpad(screen, 3, width - 8, | ||||
|                                                (height // 2) - 1, 4, "Enter new execution string:", | ||||
|                                                conf.get(strings[position - 1], "exec_string"), | ||||
|                                                normal_text, highlight_text) | ||||
|                 edit_string = string_textpad.edit(CursesTextpadConfirm) | ||||
|             SetAliasString(strings[position - 1], | ||||
|                            edit_string.replace("\n", "").rstrip()) | ||||
|             strings = conf.sections() | ||||
|         if (key_pressed == ord('p') or key_pressed == ord( | ||||
|                 '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 = CursesPanel(screen, 4, width - 6, | ||||
|                     (height // 2) - 1, 3, | ||||
|                     " Enter user password for sshpass and press 'enter':\n>", | ||||
|                     normal_text, highlight_text, "password") | ||||
|                 SetPassword(strings[position - 1].split()[0].strip(), set_password) | ||||
|                 strings = GetTreeList(False, expanded) | ||||
|                 stringsfull = GetTreeList(True, expanded) | ||||
|             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], set_password) | ||||
|         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: | ||||
|  | @ -749,15 +397,14 @@ def CursesMain(): | |||
|                              str(len(selected)), " selected aliases? (y/N)"])) | ||||
|             else: | ||||
|                 remove_confirm = ("".join(["Are you sure to remove '", | ||||
|                     strings[position - 1].split()[0].strip(), "' alias? (y/N)"])) | ||||
|                 selected.append(strings[position - 1].split()[0].strip()) | ||||
|                                            strings[position - 1], "' alias? (y/N)"])) | ||||
|                 selected.append(strings[position - 1]) | ||||
|             remove_result = CursesPanel(screen, 4, width - 6, | ||||
|                 (height // 2) - 1, 3, remove_confirm, normal_text, | ||||
|                 highlight_text, "remove") | ||||
|                                         (height // 2) - 1, 3, remove_confirm, normal_text, | ||||
|                                         highlight_text, "remove") | ||||
|             if remove_result == "confirm": | ||||
|                 RemoveAliases(selected) | ||||
|                 strings = GetTreeList(False, expanded) | ||||
|                 stringsfull = GetTreeList(True, expanded) | ||||
|                 strings = conf.sections() | ||||
|                 row_num = len(strings) | ||||
|                 selected_strings = [" " for i in range(0, row_num + 1)] | ||||
|                 pages = int(ceil(row_num / max_row)) | ||||
|  | @ -771,78 +418,25 @@ def CursesMain(): | |||
|                 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) | ||||
|                 selected.append(strings[position - 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(),  | ||||
|                         False, screen) | ||||
|             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: | ||||
|                                             (height // 2) - 1, 4, | ||||
|                                             "".join([ | ||||
|                                                 "Enter specific command to execute with selected ", | ||||
|                                                 "alias/aliases:"] | ||||
|                                             ), "", normal_text, highlight_text) | ||||
|             command_string = command_textpad.edit(CursesTextpadConfirm) | ||||
|             CursesConnect(screen, selected, | ||||
|                           command_string.replace("\n", "").rstrip()) | ||||
|         if (key_pressed == ord("\n") or key_pressed == ( | ||||
|                 curses.KEY_F9)) 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 | ||||
|                 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() | ||||
|                 HoldConnection(strings[position - 1].split()[0].strip()) | ||||
|         if (key_pressed == ord("\n") or key_pressed == ( | ||||
|                 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 = [] | ||||
|                 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()) | ||||
|                 Connect(selected, False, False, screen) | ||||
|             selected_strings = [" " for i in range(0, row_num + 1)] | ||||
|                 selected.append(strings[position - 1]) | ||||
|             CursesConnect(screen, selected) | ||||
|         if (key_pressed == 32 or key_pressed == ( | ||||
|                 curses.KEY_IC)) and row_num != 0: | ||||
|             if selected_strings[position] == ' ': | ||||
|  | @ -866,8 +460,7 @@ def CursesMain(): | |||
|                     page = page + 1 | ||||
|                     position = 1 + (max_row * (page - 1)) | ||||
|         if key_pressed == curses.KEY_DOWN or key_pressed == ord( | ||||
|                 'x') or key_pressed == ord('X') or key_pressed == ord( | ||||
|                 's') or key_pressed == ord('S'): | ||||
|                 'x') or key_pressed == ord('X'): | ||||
|             if page == 1: | ||||
|                 if position < i: | ||||
|                     position = position + 1 | ||||
|  | @ -885,8 +478,7 @@ def CursesMain(): | |||
|                     page = page + 1 | ||||
|                     position = 1 + (max_row * (page - 1)) | ||||
|         if key_pressed == curses.KEY_UP or key_pressed == ord( | ||||
|                 'z') or key_pressed == ord('Z') or key_pressed == ord( | ||||
|                 'w') or key_pressed == ord('W'): | ||||
|                 'z') or key_pressed == ord('Z'): | ||||
|             if page == 1: | ||||
|                 if position > 1: | ||||
|                     position = position - 1 | ||||
|  | @ -906,12 +498,6 @@ def CursesMain(): | |||
|             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 | ||||
|         box.erase() | ||||
|         screen.border(0) | ||||
|         box.border(0) | ||||
|  | @ -921,7 +507,13 @@ def CursesMain(): | |||
|                 box.addnstr(1, 1, "There aren't any aliases yet. Press 'a' to add new one.", | ||||
|                             width - 6, highlight_text) | ||||
|             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"), | ||||
|                                ")", password] | ||||
|                 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) | ||||
|  | @ -937,57 +529,26 @@ def CursesMain(): | |||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     try: | ||||
|         input = raw_input   # Fix for Python 2.x | ||||
|     except NameError: | ||||
|         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): | ||||
|         try: | ||||
|             open(conf_file, 'w') | ||||
|         except: | ||||
|             print("Can't make file at " + conf_dir) | ||||
|             exit() | ||||
|      | ||||
|     try: | ||||
|         conf.read(conf_file) | ||||
|     except: | ||||
|         print("Error: can't read config file " + conf_file) | ||||
|         exit() | ||||
| 
 | ||||
|         open(conf_file, 'w') | ||||
|     conf.read(conf_file) | ||||
|     if len(argv) > 1: | ||||
|         try: | ||||
|             CMDOptions() | ||||
|         except KeyboardInterrupt: | ||||
|             exit() | ||||
|         except configparser.Error: | ||||
|             print("Error: can't parse your config file, please check it manually or make new one") | ||||
|         except ConfigParser.Error: | ||||
|             print ("Error: can't parse your config file, please check it manually or make new one") | ||||
|             exit() | ||||
|         except IOError: | ||||
|             print("Error: can't use your config file, please check permissionss of " + conf_file) | ||||
|             exit() | ||||
| 
 | ||||
|     else: | ||||
|         try: | ||||
|             CursesMain() | ||||
|         except KeyboardInterrupt: | ||||
|             CursesExit() | ||||
|         except configparser.NoOptionError: | ||||
|         except ConfigParser.NoOptionError: | ||||
|             CursesExit("".join(["Error: can't parse your config file, please ", | ||||
|                        "check it manually or make new one"])) | ||||
|         except curses.error: | ||||
|             CursesExit("".join(["Error: can't show some curses element, maybe ", | ||||
|                        "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