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