/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
1
#!/usr/bin/python
2
# -*- mode: python; coding: utf-8 -*-
444 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
3
# 
4
# Mandos Monitor - Control and monitor the Mandos server
5
# 
544 by Teddy Hogeborn
Updated year in copyright notices.
6
# Copyright © 2009-2012 Teddy Hogeborn
7
# Copyright © 2009-2012 Björn Påhlsson
444 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
8
# 
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 3 of the License, or
12
# (at your option) any later version.
13
#
14
#     This program is distributed in the hope that it will be useful,
15
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
#     GNU General Public License for more details.
18
# 
19
# You should have received a copy of the GNU General Public License
20
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
# 
505.1.2 by Teddy Hogeborn
Change "fukt.bsnet.se" to "recompile.se" throughout.
22
# Contact the authors at <mandos@recompile.se>.
444 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
23
# 
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
24
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
25
from __future__ import (division, absolute_import, print_function,
26
                        unicode_literals)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
27
28
import sys
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
29
import os
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
30
import signal
31
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
32
import datetime
33
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
34
import urwid.curses_display
35
import urwid
36
37
from dbus.mainloop.glib import DBusGMainLoop
38
import gobject
39
40
import dbus
41
42
import UserList
43
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
44
import locale
45
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
46
locale.setlocale(locale.LC_ALL, '')
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
47
24.1.153 by Björn Påhlsson
early commit to ease todays coding
48
import logging
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
49
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
24.1.153 by Björn Påhlsson
early commit to ease todays coding
50
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
51
# Some useful constants
24.1.186 by Björn Påhlsson
transitional stuff actually working
52
domain = 'se.recompile'
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
53
server_interface = domain + '.Mandos'
54
client_interface = domain + '.Mandos.Client'
237.4.28 by Teddy Hogeborn
* Makefile (version): Changed to "1.5.3".
55
version = "1.5.3"
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
56
57
# Always run in monochrome mode
58
urwid.curses_display.curses.has_colors = lambda : False
59
60
# Urwid doesn't support blinking, but we want it.  Since we have no
61
# use for underline on its own, we make underline also always blink.
62
urwid.curses_display.curses.A_UNDERLINE |= (
63
    urwid.curses_display.curses.A_BLINK)
64
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
65
def isoformat_to_datetime(iso):
66
    "Parse an ISO 8601 date string to a datetime.datetime()"
67
    if not iso:
68
        return None
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
69
    d, t = iso.split("T", 1)
70
    year, month, day = d.split("-", 2)
71
    hour, minute, second = t.split(":", 2)
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
72
    second, fraction = divmod(float(second), 1)
73
    return datetime.datetime(int(year),
74
                             int(month),
75
                             int(day),
76
                             int(hour),
77
                             int(minute),
78
                             int(second),           # Whole seconds
79
                             int(fraction*1000000)) # Microseconds
80
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
81
class MandosClientPropertyCache(object):
82
    """This wraps a Mandos Client D-Bus proxy object, caches the
83
    properties and calls a hook function when any of them are
84
    changed.
85
    """
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
86
    def __init__(self, proxy_object=None, *args, **kwargs):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
87
        self.proxy = proxy_object # Mandos Client proxy object
88
        
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
89
        self.properties = dict()
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
90
        self.property_changed_match = (
91
            self.proxy.connect_to_signal("PropertyChanged",
92
                                         self.property_changed,
93
                                         client_interface,
94
                                         byte_arrays=True))
24.1.153 by Björn Påhlsson
early commit to ease todays coding
95
        
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
96
        self.properties.update(
97
            self.proxy.GetAll(client_interface,
98
                              dbus_interface = dbus.PROPERTIES_IFACE))
24.1.154 by Björn Påhlsson
merge
99
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
100
        #XXX This breaks good super behaviour
24.1.154 by Björn Påhlsson
merge
101
#        super(MandosClientPropertyCache, self).__init__(
102
#            *args, **kwargs)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
103
    
104
    def property_changed(self, property=None, value=None):
105
        """This is called whenever we get a PropertyChanged signal
106
        It updates the changed property in the "properties" dict.
107
        """
108
        # Update properties dict with new value
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
109
        self.properties[property] = value
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
110
    
111
    def delete(self, *args, **kwargs):
112
        self.property_changed_match.remove()
113
        super(MandosClientPropertyCache, self).__init__(
114
            *args, **kwargs)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
115
116
117
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
118
    """A Mandos Client which is visible on the screen.
119
    """
120
    
121
    def __init__(self, server_proxy_object=None, update_hook=None,
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
122
                 delete_hook=None, logger=None, *args, **kwargs):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
123
        # Called on update
124
        self.update_hook = update_hook
125
        # Called on delete
126
        self.delete_hook = delete_hook
127
        # Mandos Server proxy object
128
        self.server_proxy_object = server_proxy_object
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
129
        # Logger
130
        self.logger = logger
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
131
        
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
132
        self._update_timer_callback_tag = None
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
133
        self._update_timer_callback_lock = 0
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
134
        
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
135
        # The widget shown normally
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
136
        self._text_widget = urwid.Text("")
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
137
        # The widget shown when we have focus
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
138
        self._focus_text_widget = urwid.Text("")
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
139
        super(MandosClientWidget, self).__init__(
140
            update_hook=update_hook, delete_hook=delete_hook,
141
            *args, **kwargs)
142
        self.update()
143
        self.opened = False
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
144
        
145
        last_checked_ok = isoformat_to_datetime(self.properties
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
146
                                                ["LastCheckedOK"])
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
147
        
557 by Teddy Hogeborn
Use the new Client.LastCheckerStatus property.
148
        if self.properties ["LastCheckerStatus"] != 0:
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
149
            self.using_timer(True)
150
        
151
        if self.need_approval:
152
            self.using_timer(True)
153
        
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
154
        self.match_objects = (
155
            self.proxy.connect_to_signal("CheckerCompleted",
156
                                         self.checker_completed,
157
                                         client_interface,
158
                                         byte_arrays=True),
159
            self.proxy.connect_to_signal("CheckerStarted",
160
                                         self.checker_started,
161
                                         client_interface,
162
                                         byte_arrays=True),
163
            self.proxy.connect_to_signal("GotSecret",
164
                                         self.got_secret,
165
                                         client_interface,
166
                                         byte_arrays=True),
167
            self.proxy.connect_to_signal("NeedApproval",
168
                                         self.need_approval,
169
                                         client_interface,
170
                                         byte_arrays=True),
171
            self.proxy.connect_to_signal("Rejected",
172
                                         self.rejected,
173
                                         client_interface,
174
                                         byte_arrays=True))
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
175
        #self.logger('Created client {0}'
176
        #            .format(self.properties["Name"]))
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
177
    
178
    def property_changed(self, property=None, value=None):
179
        super(self, MandosClientWidget).property_changed(property,
180
                                                         value)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
181
        if property == "ApprovalPending":
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
182
            using_timer(bool(value))
557 by Teddy Hogeborn
Use the new Client.LastCheckerStatus property.
183
        if property == "LastCheckerStatus":
184
            using_timer(value != 0)
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
185
            #self.logger('Checker for client {0} (command "{1}") was '
186
            #            ' successful'.format(self.properties["Name"],
187
            #                                 command))
557 by Teddy Hogeborn
Use the new Client.LastCheckerStatus property.
188
    
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
189
    def using_timer(self, flag):
190
        """Call this method with True or False when timer should be
191
        activated or deactivated.
192
        """
193
        old = self._update_timer_callback_lock
194
        if flag:
195
            self._update_timer_callback_lock += 1
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
196
        else:
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
197
            self._update_timer_callback_lock -= 1
198
        if old == 0 and self._update_timer_callback_lock:
24.1.179 by Björn Påhlsson
New feature:
199
            # Will update the shown timer value every second
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
200
            self._update_timer_callback_tag = (gobject.timeout_add
201
                                               (1000,
202
                                                self.update_timer))
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
203
        elif old and self._update_timer_callback_lock == 0:
204
            gobject.source_remove(self._update_timer_callback_tag)
205
            self._update_timer_callback_tag = None
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
206
    
207
    def checker_completed(self, exitstatus, condition, command):
208
        if exitstatus == 0:
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
209
            self.update()
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
210
            return
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
211
        # Checker failed
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
212
        if os.WIFEXITED(condition):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
213
            self.logger('Checker for client {0} (command "{1}")'
214
                        ' failed with exit code {2}'
215
                        .format(self.properties["Name"], command,
216
                                os.WEXITSTATUS(condition)))
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
217
        elif os.WIFSIGNALED(condition):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
218
            self.logger('Checker for client {0} (command "{1}") was'
219
                        ' killed by signal {2}'
220
                        .format(self.properties["Name"], command,
221
                                os.WTERMSIG(condition)))
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
222
        elif os.WCOREDUMP(condition):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
223
            self.logger('Checker for client {0} (command "{1}")'
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
224
                        ' dumped core'
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
225
                        .format(self.properties["Name"], command))
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
226
        else:
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
227
            self.logger('Checker for client {0} completed'
228
                        ' mysteriously'
229
                        .format(self.properties["Name"]))
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
230
        self.update()
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
231
    
232
    def checker_started(self, command):
537 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
233
        """Server signals that a checker started. This could be useful
234
           to log in the future. """
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
235
        #self.logger('Client {0} started checker "{1}"'
236
        #            .format(self.properties["Name"],
237
        #                    unicode(command)))
24.1.153 by Björn Påhlsson
early commit to ease todays coding
238
        pass
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
239
    
240
    def got_secret(self):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
241
        self.logger('Client {0} received its secret'
242
                    .format(self.properties["Name"]))
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
243
    
24.1.153 by Björn Påhlsson
early commit to ease todays coding
244
    def need_approval(self, timeout, default):
245
        if not default:
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
246
            message = 'Client {0} needs approval within {1} seconds'
24.1.153 by Björn Påhlsson
early commit to ease todays coding
247
        else:
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
248
            message = 'Client {0} will get its secret in {1} seconds'
249
        self.logger(message.format(self.properties["Name"],
250
                                   timeout/1000))
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
251
        self.using_timer(True)
24.1.153 by Björn Påhlsson
early commit to ease todays coding
252
    
253
    def rejected(self, reason):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
254
        self.logger('Client {0} was rejected; reason: {1}'
255
                    .format(self.properties["Name"], reason))
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
256
    
257
    def selectable(self):
258
        """Make this a "selectable" widget.
259
        This overrides the method from urwid.FlowWidget."""
260
        return True
261
    
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
262
    def rows(self, maxcolrow, focus=False):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
263
        """How many rows this widget will occupy might depend on
264
        whether we have focus or not.
265
        This overrides the method from urwid.FlowWidget"""
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
266
        return self.current_widget(focus).rows(maxcolrow, focus=focus)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
267
    
268
    def current_widget(self, focus=False):
269
        if focus or self.opened:
270
            return self._focus_widget
271
        return self._widget
272
    
273
    def update(self):
274
        "Called when what is visible on the screen should be updated."
275
        # How to add standout mode to a style
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
276
        with_standout = { "normal": "standout",
277
                          "bold": "bold-standout",
278
                          "underline-blink":
279
                              "underline-blink-standout",
280
                          "bold-underline-blink":
281
                              "bold-underline-blink-standout",
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
282
                          }
24.1.154 by Björn Påhlsson
merge
283
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
284
        # Rebuild focus and non-focus widgets using current properties
24.1.154 by Björn Påhlsson
merge
285
286
        # Base part of a client. Name!
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
287
        base = '{name}: '.format(name=self.properties["Name"])
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
288
        if not self.properties["Enabled"]:
289
            message = "DISABLED"
290
        elif self.properties["ApprovalPending"]:
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
291
            timeout = datetime.timedelta(milliseconds
292
                                         = self.properties
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
293
                                         ["ApprovalDelay"])
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
294
            last_approval_request = isoformat_to_datetime(
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
295
                self.properties["LastApprovalRequest"])
442 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
296
            if last_approval_request is not None:
297
                timer = timeout - (datetime.datetime.utcnow()
298
                                   - last_approval_request)
299
            else:
300
                timer = datetime.timedelta()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
301
            if self.properties["ApprovedByDefault"]:
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
302
                message = "Approval in {0}. (d)eny?"
24.1.159 by Björn Påhlsson
added approval to mandos-ctl
303
            else:
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
304
                message = "Denial in {0}. (a)pprove?"
305
            message = message.format(unicode(timer).rsplit(".", 1)[0])
557 by Teddy Hogeborn
Use the new Client.LastCheckerStatus property.
306
        elif self.properties["LastCheckerStatus"] != 0:
24.1.179 by Björn Påhlsson
New feature:
307
            # When checker has failed, print a timer until client expires
308
            expires = self.properties["Expires"]
309
            if expires == "":
310
                timer = datetime.timedelta(0)
311
            else:
312
                expires = datetime.datetime.strptime(expires,
313
                                                     '%Y-%m-%dT%H:%M:%S.%f')
314
                timer = expires - datetime.datetime.utcnow()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
315
            message = ('A checker has failed! Time until client'
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
316
                       ' gets disabled: {0}'
317
                       .format(unicode(timer).rsplit(".", 1)[0]))
24.1.154 by Björn Påhlsson
merge
318
        else:
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
319
            message = "enabled"
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
320
        self._text = "{0}{1}".format(base, message)
24.1.156 by Björn Påhlsson
merge
321
            
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
322
        if not urwid.supports_unicode():
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
323
            self._text = self._text.encode("ascii", "replace")
324
        textlist = [("normal", self._text)]
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
325
        self._text_widget.set_text(textlist)
326
        self._focus_text_widget.set_text([(with_standout[text[0]],
327
                                           text[1])
328
                                          if isinstance(text, tuple)
329
                                          else text
330
                                          for text in textlist])
331
        self._widget = self._text_widget
332
        self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
333
                                            "standout")
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
334
        # Run update hook, if any
335
        if self.update_hook is not None:
336
            self.update_hook()
337
    
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
338
    def update_timer(self):
24.1.179 by Björn Påhlsson
New feature:
339
        """called by gobject. Will indefinitely loop until
340
        gobject.source_remove() on tag is called"""
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
341
        self.update()
342
        return True             # Keep calling this
343
    
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
344
    def delete(self, *args, **kwargs):
417 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
345
        if self._update_timer_callback_tag is not None:
346
            gobject.source_remove(self._update_timer_callback_tag)
347
            self._update_timer_callback_tag = None
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
348
        for match in self.match_objects:
349
            match.remove()
350
        self.match_objects = ()
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
351
        if self.delete_hook is not None:
352
            self.delete_hook(self)
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
353
        return super(MandosClientWidget, self).delete(*args, **kwargs)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
354
    
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
355
    def render(self, maxcolrow, focus=False):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
356
        """Render differently if we have focus.
357
        This overrides the method from urwid.FlowWidget"""
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
358
        return self.current_widget(focus).render(maxcolrow,
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
359
                                                 focus=focus)
360
    
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
361
    def keypress(self, maxcolrow, key):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
362
        """Handle keys.
363
        This overrides the method from urwid.FlowWidget"""
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
364
        if key == "+":
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
365
            self.proxy.Enable(dbus_interface = client_interface,
366
                              ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
367
        elif key == "-":
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
368
            self.proxy.Disable(dbus_interface = client_interface,
369
                               ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
370
        elif key == "a":
24.1.154 by Björn Påhlsson
merge
371
            self.proxy.Approve(dbus.Boolean(True, variant_level=1),
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
372
                               dbus_interface = client_interface,
373
                               ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
374
        elif key == "d":
24.1.154 by Björn Påhlsson
merge
375
            self.proxy.Approve(dbus.Boolean(False, variant_level=1),
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
376
                                  dbus_interface = client_interface,
377
                               ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
378
        elif key == "R" or key == "_" or key == "ctrl k":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
379
            self.server_proxy_object.RemoveClient(self.proxy
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
380
                                                  .object_path,
381
                                                  ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
382
        elif key == "s":
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
383
            self.proxy.StartChecker(dbus_interface = client_interface,
384
                                    ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
385
        elif key == "S":
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
386
            self.proxy.StopChecker(dbus_interface = client_interface,
387
                                   ignore_reply=True)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
388
        elif key == "C":
482 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
389
            self.proxy.CheckedOK(dbus_interface = client_interface,
390
                                 ignore_reply=True)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
391
        # xxx
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
392
#         elif key == "p" or key == "=":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
393
#             self.proxy.pause()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
394
#         elif key == "u" or key == ":":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
395
#             self.proxy.unpause()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
396
#         elif key == "RET":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
397
#             self.open()
398
        else:
399
            return key
400
    
401
    def property_changed(self, property=None, value=None,
402
                         *args, **kwargs):
403
        """Call self.update() if old value is not new value.
404
        This overrides the method from MandosClientPropertyCache"""
405
        property_name = unicode(property)
406
        old_value = self.properties.get(property_name)
407
        super(MandosClientWidget, self).property_changed(
408
            property=property, value=value, *args, **kwargs)
409
        if self.properties.get(property_name) != old_value:
410
            self.update()
411
412
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
413
class ConstrainedListBox(urwid.ListBox):
414
    """Like a normal urwid.ListBox, but will consume all "up" or
415
    "down" key presses, thus not allowing any containing widgets to
416
    use them as an excuse to shift focus away from this widget.
417
    """
463.1.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
418
    def keypress(self, maxcolrow, key):
419
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
420
        if ret in ("up", "down"):
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
421
            return
422
        return ret
423
424
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
425
class UserInterface(object):
426
    """This is the entire user interface - the whole screen
427
    with boxes, lists of client widgets, etc.
428
    """
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
429
    def __init__(self, max_log_length=1000):
430
        DBusGMainLoop(set_as_default=True)
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
431
        
432
        self.screen = urwid.curses_display.Screen()
433
        
434
        self.screen.register_palette((
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
435
                ("normal",
436
                 "default", "default", None),
437
                ("bold",
438
                 "default", "default", "bold"),
439
                ("underline-blink",
440
                 "default", "default", "underline"),
441
                ("standout",
442
                 "default", "default", "standout"),
443
                ("bold-underline-blink",
444
                 "default", "default", ("bold", "underline")),
445
                ("bold-standout",
446
                 "default", "default", ("bold", "standout")),
447
                ("underline-blink-standout",
448
                 "default", "default", ("underline", "standout")),
449
                ("bold-underline-blink-standout",
450
                 "default", "default", ("bold", "underline",
451
                                          "standout")),
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
452
                ))
453
        
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
454
        if urwid.supports_unicode():
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
455
            self.divider = "─" # \u2500
456
            #self.divider = "━" # \u2501
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
457
        else:
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
458
            #self.divider = "-" # \u002d
459
            self.divider = "_" # \u005f
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
460
        
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
461
        self.screen.start()
462
        
463
        self.size = self.screen.get_cols_rows()
464
        
465
        self.clients = urwid.SimpleListWalker([])
466
        self.clients_dict = {}
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
467
        
468
        # We will add Text widgets to this list
469
        self.log = []
470
        self.max_log_length = max_log_length
471
        
472
        # We keep a reference to the log widget so we can remove it
473
        # from the ListWalker without it getting destroyed
474
        self.logbox = ConstrainedListBox(self.log)
475
        
476
        # This keeps track of whether self.uilist currently has
477
        # self.logbox in it or not
478
        self.log_visible = True
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
479
        self.log_wrap = "any"
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
480
        
481
        self.rebuild()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
482
        self.log_message_raw(("bold",
483
                              "Mandos Monitor version " + version))
484
        self.log_message_raw(("bold",
485
                              "q: Quit  ?: Help"))
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
486
        
487
        self.busname = domain + '.Mandos'
488
        self.main_loop = gobject.MainLoop()
489
    
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
490
    def client_not_found(self, fingerprint, address):
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
491
        self.log_message("Client with address {0} and fingerprint"
492
                         " {1} could not be found"
493
                         .format(address, fingerprint))
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
494
    
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
495
    def rebuild(self):
496
        """This rebuilds the User Interface.
497
        Call this when the widget layout needs to change"""
498
        self.uilist = []
499
        #self.uilist.append(urwid.ListBox(self.clients))
422 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
500
        self.uilist.append(urwid.Frame(ConstrainedListBox(self.
501
                                                          clients),
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
502
                                       #header=urwid.Divider(),
503
                                       header=None,
422 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
504
                                       footer=
505
                                       urwid.Divider(div_char=
506
                                                     self.divider)))
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
507
        if self.log_visible:
508
            self.uilist.append(self.logbox)
509
        self.topwidget = urwid.Pile(self.uilist)
510
    
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
511
    def log_message(self, message):
512
        timestamp = datetime.datetime.now().isoformat()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
513
        self.log_message_raw(timestamp + ": " + message)
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
514
    
515
    def log_message_raw(self, markup):
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
516
        """Add a log message to the log buffer."""
517
        self.log.append(urwid.Text(markup, wrap=self.log_wrap))
518
        if (self.max_log_length
519
            and len(self.log) > self.max_log_length):
520
            del self.log[0:len(self.log)-self.max_log_length-1]
408 by Teddy Hogeborn
* debian/rules: Only set BROKEN_PIE if binutils is a specific range of
521
        self.logbox.set_focus(len(self.logbox.body.contents),
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
522
                              coming_from="above")
409 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
523
        self.refresh()
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
524
    
525
    def toggle_log_display(self):
526
        """Toggle visibility of the log buffer."""
527
        self.log_visible = not self.log_visible
528
        self.rebuild()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
529
        #self.log_message("Log visibility changed to: "
430 by teddy at bsnet
* mandos-monitor.xml: New.
530
        #                 + unicode(self.log_visible))
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
531
    
532
    def change_log_display(self):
533
        """Change type of log display.
534
        Currently, this toggles wrapping of text lines."""
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
535
        if self.log_wrap == "clip":
536
            self.log_wrap = "any"
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
537
        else:
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
538
            self.log_wrap = "clip"
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
539
        for textwidget in self.log:
540
            textwidget.set_wrap_mode(self.log_wrap)
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
541
        #self.log_message("Wrap mode: " + self.log_wrap)
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
542
    
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
543
    def find_and_remove_client(self, path, name):
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
544
        """Find a client by its object path and remove it.
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
545
        
546
        This is connected to the ClientRemoved signal from the
547
        Mandos server object."""
548
        try:
549
            client = self.clients_dict[path]
550
        except KeyError:
551
            # not found?
567 by Teddy Hogeborn
* mandos-monitor: Use new string format method.
552
            self.log_message("Unknown client {0!r} ({1!r}) removed"
553
                             .format(name, path))
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
554
            return
488 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
555
        client.delete()
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
556
    
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
557
    def add_new_client(self, path):
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
558
        client_proxy_object = self.bus.get_object(self.busname, path)
559
        self.add_client(MandosClientWidget(server_proxy_object
560
                                           =self.mandos_serv,
561
                                           proxy_object
562
                                           =client_proxy_object,
563
                                           update_hook
564
                                           =self.refresh,
565
                                           delete_hook
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
566
                                           =self.remove_client,
567
                                           logger
568
                                           =self.log_message),
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
569
                        path=path)
570
    
571
    def add_client(self, client, path=None):
572
        self.clients.append(client)
573
        if path is None:
574
            path = client.proxy.object_path
575
        self.clients_dict[path] = client
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
576
        self.clients.sort(None, lambda c: c.properties["Name"])
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
577
        self.refresh()
578
    
579
    def remove_client(self, client, path=None):
580
        self.clients.remove(client)
581
        if path is None:
582
            path = client.proxy.object_path
583
        del self.clients_dict[path]
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
584
        if not self.clients_dict:
585
            # Work around bug in Urwid 0.9.8.3 - if a SimpleListWalker
586
            # is completely emptied, we need to recreate it.
587
            self.clients = urwid.SimpleListWalker([])
588
            self.rebuild()
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
589
        self.refresh()
590
    
591
    def refresh(self):
592
        """Redraw the screen"""
593
        canvas = self.topwidget.render(self.size, focus=True)
594
        self.screen.draw_screen(self.size, canvas)
595
    
596
    def run(self):
597
        """Start the main loop and exit when it's done."""
537 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
598
        self.bus = dbus.SystemBus()
599
        mandos_dbus_objc = self.bus.get_object(
600
            self.busname, "/", follow_name_owner_changes=True)
601
        self.mandos_serv = dbus.Interface(mandos_dbus_objc,
602
                                          dbus_interface
603
                                          = server_interface)
604
        try:
605
            mandos_clients = (self.mandos_serv
606
                              .GetAllClientsWithProperties())
607
        except dbus.exceptions.DBusException:
608
            mandos_clients = dbus.Dictionary()
609
        
610
        (self.mandos_serv
611
         .connect_to_signal("ClientRemoved",
612
                            self.find_and_remove_client,
613
                            dbus_interface=server_interface,
614
                            byte_arrays=True))
615
        (self.mandos_serv
616
         .connect_to_signal("ClientAdded",
617
                            self.add_new_client,
618
                            dbus_interface=server_interface,
619
                            byte_arrays=True))
620
        (self.mandos_serv
621
         .connect_to_signal("ClientNotFound",
622
                            self.client_not_found,
623
                            dbus_interface=server_interface,
624
                            byte_arrays=True))
625
        for path, client in mandos_clients.iteritems():
626
            client_proxy_object = self.bus.get_object(self.busname,
627
                                                      path)
628
            self.add_client(MandosClientWidget(server_proxy_object
629
                                               =self.mandos_serv,
630
                                               proxy_object
631
                                               =client_proxy_object,
632
                                               properties=client,
633
                                               update_hook
634
                                               =self.refresh,
635
                                               delete_hook
636
                                               =self.remove_client,
637
                                               logger
638
                                               =self.log_message),
639
                            path=path)
640
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
641
        self.refresh()
642
        self._input_callback_tag = (gobject.io_add_watch
643
                                    (sys.stdin.fileno(),
644
                                     gobject.IO_IN,
645
                                     self.process_input))
646
        self.main_loop.run()
647
        # Main loop has finished, we should close everything now
648
        gobject.source_remove(self._input_callback_tag)
649
        self.screen.stop()
650
    
651
    def stop(self):
652
        self.main_loop.quit()
653
    
654
    def process_input(self, source, condition):
655
        keys = self.screen.get_input()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
656
        translations = { "ctrl n": "down",      # Emacs
657
                         "ctrl p": "up",        # Emacs
658
                         "ctrl v": "page down", # Emacs
659
                         "meta v": "page up",   # Emacs
660
                         " ": "page down",      # less
661
                         "f": "page down",      # less
662
                         "b": "page up",        # less
663
                         "j": "down",           # vi
664
                         "k": "up",             # vi
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
665
                         }
666
        for key in keys:
667
            try:
668
                key = translations[key]
669
            except KeyError:    # :-)
670
                pass
671
            
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
672
            if key == "q" or key == "Q":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
673
                self.stop()
674
                break
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
675
            elif key == "window resize":
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
676
                self.size = self.screen.get_cols_rows()
677
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
678
            elif key == "\f":  # Ctrl-L
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
679
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
680
            elif key == "l" or key == "D":
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
681
                self.toggle_log_display()
682
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
683
            elif key == "w" or key == "i":
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
684
                self.change_log_display()
685
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
686
            elif key == "?" or key == "f1" or key == "esc":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
687
                if not self.log_visible:
688
                    self.log_visible = True
689
                    self.rebuild()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
690
                self.log_message_raw(("bold",
691
                                      "  ".
692
                                      join(("q: Quit",
693
                                            "?: Help",
694
                                            "l: Log window toggle",
695
                                            "TAB: Switch window",
696
                                            "w: Wrap (log)"))))
697
                self.log_message_raw(("bold",
698
                                      "  "
699
                                      .join(("Clients:",
700
                                             "+: Enable",
701
                                             "-: Disable",
702
                                             "R: Remove",
703
                                             "s: Start new checker",
704
                                             "S: Stop checker",
705
                                             "C: Checker OK",
706
                                             "a: Approve",
707
                                             "d: Deny"))))
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
708
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
709
            elif key == "tab":
405 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
710
                if self.topwidget.get_focus() is self.logbox:
711
                    self.topwidget.set_focus(0)
712
                else:
713
                    self.topwidget.set_focus(self.logbox)
714
                self.refresh()
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
715
            #elif (key == "end" or key == "meta >" or key == "G"
716
            #      or key == ">"):
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
717
            #    pass            # xxx end-of-buffer
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
718
            #elif (key == "home" or key == "meta <" or key == "g"
719
            #      or key == "<"):
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
720
            #    pass            # xxx beginning-of-buffer
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
721
            #elif key == "ctrl e" or key == "$":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
722
            #    pass            # xxx move-end-of-line
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
723
            #elif key == "ctrl a" or key == "^":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
724
            #    pass            # xxx move-beginning-of-line
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
725
            #elif key == "ctrl b" or key == "meta (" or key == "h":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
726
            #    pass            # xxx left
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
727
            #elif key == "ctrl f" or key == "meta )" or key == "l":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
728
            #    pass            # xxx right
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
729
            #elif key == "a":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
730
            #    pass            # scroll up log
463.1.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
731
            #elif key == "z":
407 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
732
            #    pass            # scroll down log
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
733
            elif self.topwidget.selectable():
734
                self.topwidget.keypress(self.size, key)
735
                self.refresh()
736
        return True
737
738
ui = UserInterface()
739
try:
740
    ui.run()
24.1.159 by Björn Påhlsson
added approval to mandos-ctl
741
except KeyboardInterrupt:
742
    ui.screen.stop()
411 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
743
except Exception, e:
744
    ui.log_message(unicode(e))
404 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
745
    ui.screen.stop()
746
    raise