11 from collections import namedtuple
13 tuerSock = "/run/tuer.sock"
16 histfile = os.path.join(os.path.expanduser("~"), ".tyshellhist")
18 readline.read_history_file(histfile)
22 atexit.register(readline.write_history_file, histfile)
27 print(commands.get(c[1],(None,'Can\'t find help for command %s'%(c[1]))).helpstring)
29 print("Available commands: %s" % ", ".join(sorted(commands.keys())))
30 print("Use 'help command' to get more information on the command 'command'")
34 ret = subprocess.call(cmd)
36 print("Command returned non-zero exit statis %d" % ret)
39 def sendcmd(addr, cmd):
41 print("206 Sending command %s..." % (cmd))
42 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
48 if not len(data): break
49 print(data.decode('utf-8'))
58 for n in grp.getgrnam("tuer").gr_mem:
60 print (p.pw_name, " - ", p.pw_gecos)
62 def alias (cmds, aliases):
63 for newname, oldname in aliases.items():
64 cmds[newname] = cmds[oldname]
67 def prompt_sure(f,msg):
70 command = input("%s Are you sure? (yes/no) > " % msg)
78 CmdEntry = namedtuple('CmdEntry','function helpstring')
81 'exit': CmdEntry(exitcmd, 'Quits this shell'),
82 'help': CmdEntry(helpcmd, 'Helps you getting to know the available commands'),
83 'unlock': CmdEntry(sendcmd(tuerSock, 'unlock'), 'Will try to unlock the apartment door'),
84 'lock': CmdEntry(sendcmd(tuerSock, 'lock'), 'If in fallback mode, try to lock the apartment door. If not in fallback mode, you must use the switch near the door.'),
85 'buzz': CmdEntry(sendcmd(tuerSock, 'buzz'), 'Will buzz the buzzer for the street door'),
86 'who': CmdEntry(whocmd, 'Shows the list of people, who are allowed to control this system'),
87 'fallback_mode_on': CmdEntry(prompt_sure(sendcmd(tuerSock, 'fallback_mode_on'),'WARNING: This action will be reported to the admins. Use this only in case of Sphinx hardware failure when you need to ignore erroneous sensor input!'), 'Sets the system in a state where it is less dependent on sensoric input. Use it only when sensors are broken.'),
88 'fallback_mode_off': CmdEntry(prompt_sure(sendcmd(tuerSock, 'fallback_mode_off'),'WARNING: This action will be reported to the admins. Use this only if you have fixed the sensors of the Sphinx or activated fallback mode by accident!'), 'Resets the system to the default state. Use this when you have just repaired the sensors of the Sphinx.'),
89 'status': CmdEntry(sendcmd(tuerSock, 'status'), 'Shows internal state and sensor information.'),
95 def complete_command(cmd):
96 '''returns a list of commands (as strings) starting with cmd'''
97 return list(filter(lambda x: x.startswith(cmd), commands.keys()))
98 readline.set_completer(lambda cmd, num: (complete_command(cmd)+[None])[num]) # wrap complete_command for readline's weird completer API
99 readline.parse_and_bind("tab: complete") # run completion on tab
102 print("Welcome to tyshell. Use help to see what you can do.")
105 command = input("$ ")
109 command = shlex.split(command)
110 if not len(command): continue
111 # find suiting commands
112 if command[0] in commands: # needed in case a complete command is a prefix of another one
113 cmdoptions = [command[0]]
115 cmdoptions = complete_command(command[0])
116 # check how many we found
117 if len(cmdoptions) == 0: # no commands fit prefix
118 print("Command %s not found. Use help." % command[0])
119 elif len(cmdoptions) == 1: # exactly one command fits (prefix)
121 res = commands[cmdoptions[0]].function(command)
123 except Exception as e:
124 print("Error while executing %s: %s" % (command[0], str(e)))
125 #print(traceback.format_exc())
126 else: # multiple commands fit the prefix
127 print("Ambiguous command prefix, please choose one of the following:")
128 print("\t", " ".join(cmdoptions))
129 # TODO: put current "command[0]" into the shell for the next command, but such that it is deletable with backspace