/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-monitor

  • Committer: Teddy Hogeborn
  • Date: 2010-10-11 17:45:21 UTC
  • mto: (237.4.29 release)
  • mto: This revision was merged to the branch mainline in revision 459.
  • Revision ID: teddy@fukt.bsnet.se-20101011174521-e8we3lh7p0ns3oba
Tags: version-1.2.3-1
* Makefile (version): Changed to "1.2.3".
* NEWS (Version 1.2.3): New entry.
* debian/changelog (1.2.3-1): - '' -

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
4
4
# Mandos Monitor - Control and monitor the Mandos server
5
5
6
 
# Copyright © 2009-2011 Teddy Hogeborn
7
 
# Copyright © 2009-2011 Björn Påhlsson
 
6
# Copyright © 2009,2010 Teddy Hogeborn
 
7
# Copyright © 2009,2010 Björn Påhlsson
8
8
9
9
# This program is free software: you can redistribute it and/or modify
10
10
# it under the terms of the GNU General Public License as published by
22
22
# Contact the authors at <mandos@fukt.bsnet.se>.
23
23
24
24
 
25
 
from __future__ import (division, absolute_import, print_function,
26
 
                        unicode_literals)
 
25
from __future__ import division, absolute_import, with_statement
27
26
 
28
27
import sys
29
28
import os
43
42
 
44
43
import locale
45
44
 
46
 
locale.setlocale(locale.LC_ALL, '')
 
45
locale.setlocale(locale.LC_ALL, u'')
47
46
 
48
47
import logging
49
48
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
52
51
domain = 'se.bsnet.fukt'
53
52
server_interface = domain + '.Mandos'
54
53
client_interface = domain + '.Mandos.Client'
55
 
version = "1.3.0"
 
54
version = "1.2.3"
56
55
 
57
56
# Always run in monochrome mode
58
57
urwid.curses_display.curses.has_colors = lambda : False
66
65
    "Parse an ISO 8601 date string to a datetime.datetime()"
67
66
    if not iso:
68
67
        return None
69
 
    d, t = iso.split("T", 1)
70
 
    year, month, day = d.split("-", 2)
71
 
    hour, minute, second = t.split(":", 2)
 
68
    d, t = iso.split(u"T", 1)
 
69
    year, month, day = d.split(u"-", 2)
 
70
    hour, minute, second = t.split(u":", 2)
72
71
    second, fraction = divmod(float(second), 1)
73
72
    return datetime.datetime(int(year),
74
73
                             int(month),
87
86
        self.proxy = proxy_object # Mandos Client proxy object
88
87
        
89
88
        self.properties = dict()
90
 
        self.property_changed_match = (
91
 
            self.proxy.connect_to_signal("PropertyChanged",
92
 
                                         self.property_changed,
93
 
                                         client_interface,
94
 
                                         byte_arrays=True))
 
89
        self.proxy.connect_to_signal(u"PropertyChanged",
 
90
                                     self.property_changed,
 
91
                                     client_interface,
 
92
                                     byte_arrays=True)
95
93
        
96
94
        self.properties.update(
97
95
            self.proxy.GetAll(client_interface,
98
96
                              dbus_interface = dbus.PROPERTIES_IFACE))
99
97
 
100
 
        #XXX This breaks good super behaviour
 
98
        #XXX This break good super behaviour!
101
99
#        super(MandosClientPropertyCache, self).__init__(
102
100
#            *args, **kwargs)
103
101
    
107
105
        """
108
106
        # Update properties dict with new value
109
107
        self.properties[property] = value
110
 
    
111
 
    def delete(self, *args, **kwargs):
112
 
        self.property_changed_match.remove()
113
 
        super(MandosClientPropertyCache, self).__init__(
114
 
            *args, **kwargs)
115
108
 
116
109
 
117
110
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
134
127
        self.last_checker_failed = False
135
128
        
136
129
        # The widget shown normally
137
 
        self._text_widget = urwid.Text("")
 
130
        self._text_widget = urwid.Text(u"")
138
131
        # The widget shown when we have focus
139
 
        self._focus_text_widget = urwid.Text("")
 
132
        self._focus_text_widget = urwid.Text(u"")
140
133
        super(MandosClientWidget, self).__init__(
141
134
            update_hook=update_hook, delete_hook=delete_hook,
142
135
            *args, **kwargs)
144
137
        self.opened = False
145
138
        
146
139
        last_checked_ok = isoformat_to_datetime(self.properties
147
 
                                                ["LastCheckedOK"])
 
140
                                                [u"LastCheckedOK"])
148
141
        if last_checked_ok is None:
149
142
            self.last_checker_failed = True
150
143
        else:
153
146
                                        > datetime.timedelta
154
147
                                        (milliseconds=
155
148
                                         self.properties
156
 
                                         ["Interval"]))
 
149
                                         [u"Interval"]))
157
150
        
158
151
        if self.last_checker_failed:
159
152
            self.using_timer(True)
161
154
        if self.need_approval:
162
155
            self.using_timer(True)
163
156
        
164
 
        self.match_objects = (
165
 
            self.proxy.connect_to_signal("CheckerCompleted",
166
 
                                         self.checker_completed,
167
 
                                         client_interface,
168
 
                                         byte_arrays=True),
169
 
            self.proxy.connect_to_signal("CheckerStarted",
170
 
                                         self.checker_started,
171
 
                                         client_interface,
172
 
                                         byte_arrays=True),
173
 
            self.proxy.connect_to_signal("GotSecret",
174
 
                                         self.got_secret,
175
 
                                         client_interface,
176
 
                                         byte_arrays=True),
177
 
            self.proxy.connect_to_signal("NeedApproval",
178
 
                                         self.need_approval,
179
 
                                         client_interface,
180
 
                                         byte_arrays=True),
181
 
            self.proxy.connect_to_signal("Rejected",
182
 
                                         self.rejected,
183
 
                                         client_interface,
184
 
                                         byte_arrays=True))
185
 
        #self.logger('Created client %s' % (self.properties["Name"]))
 
157
        self.proxy.connect_to_signal(u"CheckerCompleted",
 
158
                                     self.checker_completed,
 
159
                                     client_interface,
 
160
                                     byte_arrays=True)
 
161
        self.proxy.connect_to_signal(u"CheckerStarted",
 
162
                                     self.checker_started,
 
163
                                     client_interface,
 
164
                                     byte_arrays=True)
 
165
        self.proxy.connect_to_signal(u"GotSecret",
 
166
                                     self.got_secret,
 
167
                                     client_interface,
 
168
                                     byte_arrays=True)
 
169
        self.proxy.connect_to_signal(u"NeedApproval",
 
170
                                     self.need_approval,
 
171
                                     client_interface,
 
172
                                     byte_arrays=True)
 
173
        self.proxy.connect_to_signal(u"Rejected",
 
174
                                     self.rejected,
 
175
                                     client_interface,
 
176
                                     byte_arrays=True)
186
177
    
187
178
    def property_changed(self, property=None, value=None):
188
179
        super(self, MandosClientWidget).property_changed(property,
189
180
                                                         value)
190
 
        if property == "ApprovalPending":
 
181
        if property == u"ApprovalPending":
191
182
            using_timer(bool(value))
192
183
        
193
184
    def using_timer(self, flag):
212
203
            if self.last_checker_failed:
213
204
                self.last_checker_failed = False
214
205
                self.using_timer(False)
215
 
            #self.logger('Checker for client %s (command "%s")'
216
 
            #            ' was successful'
217
 
            #            % (self.properties["Name"], command))
 
206
            #self.logger(u'Checker for client %s (command "%s")'
 
207
            #            u' was successful'
 
208
            #            % (self.properties[u"Name"], command))
218
209
            self.update()
219
210
            return
220
211
        # Checker failed
222
213
            self.last_checker_failed = True
223
214
            self.using_timer(True)
224
215
        if os.WIFEXITED(condition):
225
 
            self.logger('Checker for client %s (command "%s")'
226
 
                        ' failed with exit code %s'
227
 
                        % (self.properties["Name"], command,
 
216
            self.logger(u'Checker for client %s (command "%s")'
 
217
                        u' failed with exit code %s'
 
218
                        % (self.properties[u"Name"], command,
228
219
                           os.WEXITSTATUS(condition)))
229
220
        elif os.WIFSIGNALED(condition):
230
 
            self.logger('Checker for client %s (command "%s")'
231
 
                        ' was killed by signal %s'
232
 
                        % (self.properties["Name"], command,
 
221
            self.logger(u'Checker for client %s (command "%s")'
 
222
                        u' was killed by signal %s'
 
223
                        % (self.properties[u"Name"], command,
233
224
                           os.WTERMSIG(condition)))
234
225
        elif os.WCOREDUMP(condition):
235
 
            self.logger('Checker for client %s (command "%s")'
236
 
                        ' dumped core'
237
 
                        % (self.properties["Name"], command))
 
226
            self.logger(u'Checker for client %s (command "%s")'
 
227
                        u' dumped core'
 
228
                        % (self.properties[u"Name"], command))
238
229
        else:
239
 
            self.logger('Checker for client %s completed'
240
 
                        ' mysteriously')
 
230
            self.logger(u'Checker for client %s completed'
 
231
                        u' mysteriously')
241
232
        self.update()
242
233
    
243
234
    def checker_started(self, command):
244
 
        #self.logger('Client %s started checker "%s"'
245
 
        #            % (self.properties["Name"], unicode(command)))
 
235
        #self.logger(u'Client %s started checker "%s"'
 
236
        #            % (self.properties[u"Name"], unicode(command)))
246
237
        pass
247
238
    
248
239
    def got_secret(self):
249
240
        self.last_checker_failed = False
250
 
        self.logger('Client %s received its secret'
251
 
                    % self.properties["Name"])
 
241
        self.logger(u'Client %s received its secret'
 
242
                    % self.properties[u"Name"])
252
243
    
253
244
    def need_approval(self, timeout, default):
254
245
        if not default:
255
 
            message = 'Client %s needs approval within %s seconds'
 
246
            message = u'Client %s needs approval within %s seconds'
256
247
        else:
257
 
            message = 'Client %s will get its secret in %s seconds'
 
248
            message = u'Client %s will get its secret in %s seconds'
258
249
        self.logger(message
259
 
                    % (self.properties["Name"], timeout/1000))
 
250
                    % (self.properties[u"Name"], timeout/1000))
260
251
        self.using_timer(True)
261
252
    
262
253
    def rejected(self, reason):
263
 
        self.logger('Client %s was rejected; reason: %s'
264
 
                    % (self.properties["Name"], reason))
 
254
        self.logger(u'Client %s was rejected; reason: %s'
 
255
                    % (self.properties[u"Name"], reason))
265
256
    
266
257
    def selectable(self):
267
258
        """Make this a "selectable" widget.
268
259
        This overrides the method from urwid.FlowWidget."""
269
260
        return True
270
261
    
271
 
    def rows(self, maxcolrow, focus=False):
 
262
    def rows(self, (maxcol,), focus=False):
272
263
        """How many rows this widget will occupy might depend on
273
264
        whether we have focus or not.
274
265
        This overrides the method from urwid.FlowWidget"""
275
 
        return self.current_widget(focus).rows(maxcolrow, focus=focus)
 
266
        return self.current_widget(focus).rows((maxcol,), focus=focus)
276
267
    
277
268
    def current_widget(self, focus=False):
278
269
        if focus or self.opened:
282
273
    def update(self):
283
274
        "Called when what is visible on the screen should be updated."
284
275
        # How to add standout mode to a style
285
 
        with_standout = { "normal": "standout",
286
 
                          "bold": "bold-standout",
287
 
                          "underline-blink":
288
 
                              "underline-blink-standout",
289
 
                          "bold-underline-blink":
290
 
                              "bold-underline-blink-standout",
 
276
        with_standout = { u"normal": u"standout",
 
277
                          u"bold": u"bold-standout",
 
278
                          u"underline-blink":
 
279
                              u"underline-blink-standout",
 
280
                          u"bold-underline-blink":
 
281
                              u"bold-underline-blink-standout",
291
282
                          }
292
283
 
293
284
        # Rebuild focus and non-focus widgets using current properties
294
285
 
295
286
        # Base part of a client. Name!
296
 
        base = ('%(name)s: '
297
 
                      % {"name": self.properties["Name"]})
298
 
        if not self.properties["Enabled"]:
299
 
            message = "DISABLED"
300
 
        elif self.properties["ApprovalPending"]:
 
287
        base = (u'%(name)s: '
 
288
                      % {u"name": self.properties[u"Name"]})
 
289
        if not self.properties[u"Enabled"]:
 
290
            message = u"DISABLED"
 
291
        elif self.properties[u"ApprovalPending"]:
301
292
            timeout = datetime.timedelta(milliseconds
302
293
                                         = self.properties
303
 
                                         ["ApprovalDelay"])
 
294
                                         [u"ApprovalDelay"])
304
295
            last_approval_request = isoformat_to_datetime(
305
 
                self.properties["LastApprovalRequest"])
 
296
                self.properties[u"LastApprovalRequest"])
306
297
            if last_approval_request is not None:
307
298
                timer = timeout - (datetime.datetime.utcnow()
308
299
                                   - last_approval_request)
309
300
            else:
310
301
                timer = datetime.timedelta()
311
 
            if self.properties["ApprovedByDefault"]:
312
 
                message = "Approval in %s. (d)eny?"
 
302
            if self.properties[u"ApprovedByDefault"]:
 
303
                message = u"Approval in %s. (d)eny?"
313
304
            else:
314
 
                message = "Denial in %s. (a)pprove?"
 
305
                message = u"Denial in %s. (a)pprove?"
315
306
            message = message % unicode(timer).rsplit(".", 1)[0]
316
307
        elif self.last_checker_failed:
317
308
            timeout = datetime.timedelta(milliseconds
318
309
                                         = self.properties
319
 
                                         ["Timeout"])
 
310
                                         [u"Timeout"])
320
311
            last_ok = isoformat_to_datetime(
321
 
                max((self.properties["LastCheckedOK"]
322
 
                     or self.properties["Created"]),
323
 
                    self.properties["LastEnabled"]))
 
312
                max((self.properties[u"LastCheckedOK"]
 
313
                     or self.properties[u"Created"]),
 
314
                    self.properties[u"LastEnabled"]))
324
315
            timer = timeout - (datetime.datetime.utcnow() - last_ok)
325
 
            message = ('A checker has failed! Time until client'
326
 
                       ' gets disabled: %s'
 
316
            message = (u'A checker has failed! Time until client'
 
317
                       u' gets disabled: %s'
327
318
                           % unicode(timer).rsplit(".", 1)[0])
328
319
        else:
329
 
            message = "enabled"
 
320
            message = u"enabled"
330
321
        self._text = "%s%s" % (base, message)
331
322
            
332
323
        if not urwid.supports_unicode():
333
324
            self._text = self._text.encode("ascii", "replace")
334
 
        textlist = [("normal", self._text)]
 
325
        textlist = [(u"normal", self._text)]
335
326
        self._text_widget.set_text(textlist)
336
327
        self._focus_text_widget.set_text([(with_standout[text[0]],
337
328
                                           text[1])
350
341
        self.update()
351
342
        return True             # Keep calling this
352
343
    
353
 
    def delete(self, *args, **kwargs):
 
344
    def delete(self):
354
345
        if self._update_timer_callback_tag is not None:
355
346
            gobject.source_remove(self._update_timer_callback_tag)
356
347
            self._update_timer_callback_tag = None
357
 
        for match in self.match_objects:
358
 
            match.remove()
359
 
        self.match_objects = ()
360
348
        if self.delete_hook is not None:
361
349
            self.delete_hook(self)
362
 
        return super(MandosClientWidget, self).delete(*args, **kwargs)
363
350
    
364
 
    def render(self, maxcolrow, focus=False):
 
351
    def render(self, (maxcol,), focus=False):
365
352
        """Render differently if we have focus.
366
353
        This overrides the method from urwid.FlowWidget"""
367
 
        return self.current_widget(focus).render(maxcolrow,
 
354
        return self.current_widget(focus).render((maxcol,),
368
355
                                                 focus=focus)
369
356
    
370
 
    def keypress(self, maxcolrow, key):
 
357
    def keypress(self, (maxcol,), key):
371
358
        """Handle keys.
372
359
        This overrides the method from urwid.FlowWidget"""
373
 
        if key == "+":
374
 
            self.proxy.Enable(dbus_interface = client_interface,
375
 
                              ignore_reply=True)
376
 
        elif key == "-":
377
 
            self.proxy.Disable(dbus_interface = client_interface,
378
 
                               ignore_reply=True)
379
 
        elif key == "a":
 
360
        if key == u"+":
 
361
            self.proxy.Enable(dbus_interface = client_interface)
 
362
        elif key == u"-":
 
363
            self.proxy.Disable(dbus_interface = client_interface)
 
364
        elif key == u"a":
380
365
            self.proxy.Approve(dbus.Boolean(True, variant_level=1),
381
 
                               dbus_interface = client_interface,
382
 
                               ignore_reply=True)
383
 
        elif key == "d":
 
366
                               dbus_interface = client_interface)
 
367
        elif key == u"d":
384
368
            self.proxy.Approve(dbus.Boolean(False, variant_level=1),
385
 
                                  dbus_interface = client_interface,
386
 
                               ignore_reply=True)
387
 
        elif key == "R" or key == "_" or key == "ctrl k":
 
369
                                  dbus_interface = client_interface)
 
370
        elif key == u"R" or key == u"_" or key == u"ctrl k":
388
371
            self.server_proxy_object.RemoveClient(self.proxy
389
 
                                                  .object_path,
390
 
                                                  ignore_reply=True)
391
 
        elif key == "s":
392
 
            self.proxy.StartChecker(dbus_interface = client_interface,
393
 
                                    ignore_reply=True)
394
 
        elif key == "S":
395
 
            self.proxy.StopChecker(dbus_interface = client_interface,
396
 
                                   ignore_reply=True)
397
 
        elif key == "C":
398
 
            self.proxy.CheckedOK(dbus_interface = client_interface,
399
 
                                 ignore_reply=True)
 
372
                                                  .object_path)
 
373
        elif key == u"s":
 
374
            self.proxy.StartChecker(dbus_interface = client_interface)
 
375
        elif key == u"S":
 
376
            self.proxy.StopChecker(dbus_interface = client_interface)
 
377
        elif key == u"C":
 
378
            self.proxy.CheckedOK(dbus_interface = client_interface)
400
379
        # xxx
401
 
#         elif key == "p" or key == "=":
 
380
#         elif key == u"p" or key == "=":
402
381
#             self.proxy.pause()
403
 
#         elif key == "u" or key == ":":
 
382
#         elif key == u"u" or key == ":":
404
383
#             self.proxy.unpause()
405
 
#         elif key == "RET":
 
384
#         elif key == u"RET":
406
385
#             self.open()
407
386
        else:
408
387
            return key
424
403
    "down" key presses, thus not allowing any containing widgets to
425
404
    use them as an excuse to shift focus away from this widget.
426
405
    """
427
 
    def keypress(self, maxcolrow, key):
428
 
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
429
 
        if ret in ("up", "down"):
 
406
    def keypress(self, (maxcol, maxrow), key):
 
407
        ret = super(ConstrainedListBox, self).keypress((maxcol,
 
408
                                                        maxrow), key)
 
409
        if ret in (u"up", u"down"):
430
410
            return
431
411
        return ret
432
412
 
441
421
        self.screen = urwid.curses_display.Screen()
442
422
        
443
423
        self.screen.register_palette((
444
 
                ("normal",
445
 
                 "default", "default", None),
446
 
                ("bold",
447
 
                 "default", "default", "bold"),
448
 
                ("underline-blink",
449
 
                 "default", "default", "underline"),
450
 
                ("standout",
451
 
                 "default", "default", "standout"),
452
 
                ("bold-underline-blink",
453
 
                 "default", "default", ("bold", "underline")),
454
 
                ("bold-standout",
455
 
                 "default", "default", ("bold", "standout")),
456
 
                ("underline-blink-standout",
457
 
                 "default", "default", ("underline", "standout")),
458
 
                ("bold-underline-blink-standout",
459
 
                 "default", "default", ("bold", "underline",
460
 
                                          "standout")),
 
424
                (u"normal",
 
425
                 u"default", u"default", None),
 
426
                (u"bold",
 
427
                 u"default", u"default", u"bold"),
 
428
                (u"underline-blink",
 
429
                 u"default", u"default", u"underline"),
 
430
                (u"standout",
 
431
                 u"default", u"default", u"standout"),
 
432
                (u"bold-underline-blink",
 
433
                 u"default", u"default", (u"bold", u"underline")),
 
434
                (u"bold-standout",
 
435
                 u"default", u"default", (u"bold", u"standout")),
 
436
                (u"underline-blink-standout",
 
437
                 u"default", u"default", (u"underline", u"standout")),
 
438
                (u"bold-underline-blink-standout",
 
439
                 u"default", u"default", (u"bold", u"underline",
 
440
                                          u"standout")),
461
441
                ))
462
442
        
463
443
        if urwid.supports_unicode():
464
 
            self.divider = "─" # \u2500
465
 
            #self.divider = "━" # \u2501
 
444
            self.divider = u"─" # \u2500
 
445
            #self.divider = u"━" # \u2501
466
446
        else:
467
 
            #self.divider = "-" # \u002d
468
 
            self.divider = "_" # \u005f
 
447
            #self.divider = u"-" # \u002d
 
448
            self.divider = u"_" # \u005f
469
449
        
470
450
        self.screen.start()
471
451
        
485
465
        # This keeps track of whether self.uilist currently has
486
466
        # self.logbox in it or not
487
467
        self.log_visible = True
488
 
        self.log_wrap = "any"
 
468
        self.log_wrap = u"any"
489
469
        
490
470
        self.rebuild()
491
 
        self.log_message_raw(("bold",
492
 
                              "Mandos Monitor version " + version))
493
 
        self.log_message_raw(("bold",
494
 
                              "q: Quit  ?: Help"))
 
471
        self.log_message_raw((u"bold",
 
472
                              u"Mandos Monitor version " + version))
 
473
        self.log_message_raw((u"bold",
 
474
                              u"q: Quit  ?: Help"))
495
475
        
496
476
        self.busname = domain + '.Mandos'
497
477
        self.main_loop = gobject.MainLoop()
498
478
        self.bus = dbus.SystemBus()
499
479
        mandos_dbus_objc = self.bus.get_object(
500
 
            self.busname, "/", follow_name_owner_changes=True)
 
480
            self.busname, u"/", follow_name_owner_changes=True)
501
481
        self.mandos_serv = dbus.Interface(mandos_dbus_objc,
502
482
                                          dbus_interface
503
483
                                          = server_interface)
508
488
            mandos_clients = dbus.Dictionary()
509
489
        
510
490
        (self.mandos_serv
511
 
         .connect_to_signal("ClientRemoved",
 
491
         .connect_to_signal(u"ClientRemoved",
512
492
                            self.find_and_remove_client,
513
493
                            dbus_interface=server_interface,
514
494
                            byte_arrays=True))
515
495
        (self.mandos_serv
516
 
         .connect_to_signal("ClientAdded",
 
496
         .connect_to_signal(u"ClientAdded",
517
497
                            self.add_new_client,
518
498
                            dbus_interface=server_interface,
519
499
                            byte_arrays=True))
520
500
        (self.mandos_serv
521
 
         .connect_to_signal("ClientNotFound",
 
501
         .connect_to_signal(u"ClientNotFound",
522
502
                            self.client_not_found,
523
503
                            dbus_interface=server_interface,
524
504
                            byte_arrays=True))
539
519
                            path=path)
540
520
    
541
521
    def client_not_found(self, fingerprint, address):
542
 
        self.log_message(("Client with address %s and fingerprint %s"
543
 
                          " could not be found" % (address,
 
522
        self.log_message((u"Client with address %s and fingerprint %s"
 
523
                          u" could not be found" % (address,
544
524
                                                    fingerprint)))
545
525
    
546
526
    def rebuild(self):
562
542
    
563
543
    def log_message(self, message):
564
544
        timestamp = datetime.datetime.now().isoformat()
565
 
        self.log_message_raw(timestamp + ": " + message)
 
545
        self.log_message_raw(timestamp + u": " + message)
566
546
    
567
547
    def log_message_raw(self, markup):
568
548
        """Add a log message to the log buffer."""
571
551
            and len(self.log) > self.max_log_length):
572
552
            del self.log[0:len(self.log)-self.max_log_length-1]
573
553
        self.logbox.set_focus(len(self.logbox.body.contents),
574
 
                              coming_from="above")
 
554
                              coming_from=u"above")
575
555
        self.refresh()
576
556
    
577
557
    def toggle_log_display(self):
578
558
        """Toggle visibility of the log buffer."""
579
559
        self.log_visible = not self.log_visible
580
560
        self.rebuild()
581
 
        #self.log_message("Log visibility changed to: "
 
561
        #self.log_message(u"Log visibility changed to: "
582
562
        #                 + unicode(self.log_visible))
583
563
    
584
564
    def change_log_display(self):
585
565
        """Change type of log display.
586
566
        Currently, this toggles wrapping of text lines."""
587
 
        if self.log_wrap == "clip":
588
 
            self.log_wrap = "any"
 
567
        if self.log_wrap == u"clip":
 
568
            self.log_wrap = u"any"
589
569
        else:
590
 
            self.log_wrap = "clip"
 
570
            self.log_wrap = u"clip"
591
571
        for textwidget in self.log:
592
572
            textwidget.set_wrap_mode(self.log_wrap)
593
 
        #self.log_message("Wrap mode: " + self.log_wrap)
 
573
        #self.log_message(u"Wrap mode: " + self.log_wrap)
594
574
    
595
575
    def find_and_remove_client(self, path, name):
596
 
        """Find a client by its object path and remove it.
 
576
        """Find an client from its object path and remove it.
597
577
        
598
578
        This is connected to the ClientRemoved signal from the
599
579
        Mandos server object."""
601
581
            client = self.clients_dict[path]
602
582
        except KeyError:
603
583
            # not found?
604
 
            self.log_message("Unknown client %r (%r) removed", name,
605
 
                             path)
606
584
            return
607
 
        client.delete()
 
585
        self.remove_client(client, path)
608
586
    
609
587
    def add_new_client(self, path):
610
588
        client_proxy_object = self.bus.get_object(self.busname, path)
625
603
        if path is None:
626
604
            path = client.proxy.object_path
627
605
        self.clients_dict[path] = client
628
 
        self.clients.sort(None, lambda c: c.properties["Name"])
 
606
        self.clients.sort(None, lambda c: c.properties[u"Name"])
629
607
        self.refresh()
630
608
    
631
609
    def remove_client(self, client, path=None):
662
640
    
663
641
    def process_input(self, source, condition):
664
642
        keys = self.screen.get_input()
665
 
        translations = { "ctrl n": "down",      # Emacs
666
 
                         "ctrl p": "up",        # Emacs
667
 
                         "ctrl v": "page down", # Emacs
668
 
                         "meta v": "page up",   # Emacs
669
 
                         " ": "page down",      # less
670
 
                         "f": "page down",      # less
671
 
                         "b": "page up",        # less
672
 
                         "j": "down",           # vi
673
 
                         "k": "up",             # vi
 
643
        translations = { u"ctrl n": u"down",      # Emacs
 
644
                         u"ctrl p": u"up",        # Emacs
 
645
                         u"ctrl v": u"page down", # Emacs
 
646
                         u"meta v": u"page up",   # Emacs
 
647
                         u" ": u"page down",      # less
 
648
                         u"f": u"page down",      # less
 
649
                         u"b": u"page up",        # less
 
650
                         u"j": u"down",           # vi
 
651
                         u"k": u"up",             # vi
674
652
                         }
675
653
        for key in keys:
676
654
            try:
678
656
            except KeyError:    # :-)
679
657
                pass
680
658
            
681
 
            if key == "q" or key == "Q":
 
659
            if key == u"q" or key == u"Q":
682
660
                self.stop()
683
661
                break
684
 
            elif key == "window resize":
 
662
            elif key == u"window resize":
685
663
                self.size = self.screen.get_cols_rows()
686
664
                self.refresh()
687
 
            elif key == "\f":  # Ctrl-L
 
665
            elif key == u"\f":  # Ctrl-L
688
666
                self.refresh()
689
 
            elif key == "l" or key == "D":
 
667
            elif key == u"l" or key == u"D":
690
668
                self.toggle_log_display()
691
669
                self.refresh()
692
 
            elif key == "w" or key == "i":
 
670
            elif key == u"w" or key == u"i":
693
671
                self.change_log_display()
694
672
                self.refresh()
695
 
            elif key == "?" or key == "f1" or key == "esc":
 
673
            elif key == u"?" or key == u"f1" or key == u"esc":
696
674
                if not self.log_visible:
697
675
                    self.log_visible = True
698
676
                    self.rebuild()
699
 
                self.log_message_raw(("bold",
700
 
                                      "  ".
701
 
                                      join(("q: Quit",
702
 
                                            "?: Help",
703
 
                                            "l: Log window toggle",
704
 
                                            "TAB: Switch window",
705
 
                                            "w: Wrap (log)"))))
706
 
                self.log_message_raw(("bold",
707
 
                                      "  "
708
 
                                      .join(("Clients:",
709
 
                                             "+: Enable",
710
 
                                             "-: Disable",
711
 
                                             "R: Remove",
712
 
                                             "s: Start new checker",
713
 
                                             "S: Stop checker",
714
 
                                             "C: Checker OK",
715
 
                                             "a: Approve",
716
 
                                             "d: Deny"))))
 
677
                self.log_message_raw((u"bold",
 
678
                                      u"  ".
 
679
                                      join((u"q: Quit",
 
680
                                            u"?: Help",
 
681
                                            u"l: Log window toggle",
 
682
                                            u"TAB: Switch window",
 
683
                                            u"w: Wrap (log)"))))
 
684
                self.log_message_raw((u"bold",
 
685
                                      u"  "
 
686
                                      .join((u"Clients:",
 
687
                                             u"+: Enable",
 
688
                                             u"-: Disable",
 
689
                                             u"R: Remove",
 
690
                                             u"s: Start new checker",
 
691
                                             u"S: Stop checker",
 
692
                                             u"C: Checker OK",
 
693
                                             u"a: Approve",
 
694
                                             u"d: Deny"))))
717
695
                self.refresh()
718
 
            elif key == "tab":
 
696
            elif key == u"tab":
719
697
                if self.topwidget.get_focus() is self.logbox:
720
698
                    self.topwidget.set_focus(0)
721
699
                else:
722
700
                    self.topwidget.set_focus(self.logbox)
723
701
                self.refresh()
724
 
            #elif (key == "end" or key == "meta >" or key == "G"
725
 
            #      or key == ">"):
 
702
            #elif (key == u"end" or key == u"meta >" or key == u"G"
 
703
            #      or key == u">"):
726
704
            #    pass            # xxx end-of-buffer
727
 
            #elif (key == "home" or key == "meta <" or key == "g"
728
 
            #      or key == "<"):
 
705
            #elif (key == u"home" or key == u"meta <" or key == u"g"
 
706
            #      or key == u"<"):
729
707
            #    pass            # xxx beginning-of-buffer
730
 
            #elif key == "ctrl e" or key == "$":
 
708
            #elif key == u"ctrl e" or key == u"$":
731
709
            #    pass            # xxx move-end-of-line
732
 
            #elif key == "ctrl a" or key == "^":
 
710
            #elif key == u"ctrl a" or key == u"^":
733
711
            #    pass            # xxx move-beginning-of-line
734
 
            #elif key == "ctrl b" or key == "meta (" or key == "h":
 
712
            #elif key == u"ctrl b" or key == u"meta (" or key == u"h":
735
713
            #    pass            # xxx left
736
 
            #elif key == "ctrl f" or key == "meta )" or key == "l":
 
714
            #elif key == u"ctrl f" or key == u"meta )" or key == u"l":
737
715
            #    pass            # xxx right
738
 
            #elif key == "a":
 
716
            #elif key == u"a":
739
717
            #    pass            # scroll up log
740
 
            #elif key == "z":
 
718
            #elif key == u"z":
741
719
            #    pass            # scroll down log
742
720
            elif self.topwidget.selectable():
743
721
                self.topwidget.keypress(self.size, key)