/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: Björn Påhlsson
  • Date: 2011-07-25 18:47:45 UTC
  • mto: This revision was merged to the branch mainline in revision 489.
  • Revision ID: belorn@fukt.bsnet.se-20110725184745-leavsoyu1hll3mdp
free dirents in password-prompt

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,2010 Teddy Hogeborn
7
 
# Copyright © 2009,2010 Björn Påhlsson
 
6
# Copyright © 2009-2011 Teddy Hogeborn
 
7
# Copyright © 2009-2011 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, with_statement
 
25
from __future__ import division, absolute_import, print_function, unicode_literals
26
26
 
27
27
import sys
28
28
import os
42
42
 
43
43
import locale
44
44
 
45
 
locale.setlocale(locale.LC_ALL, u'')
 
45
locale.setlocale(locale.LC_ALL, '')
46
46
 
47
47
import logging
48
 
logging.getLogger(u'dbus.proxies').setLevel(logging.CRITICAL)
 
48
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
49
49
 
50
50
# Some useful constants
51
 
domain = u'se.bsnet.fukt'
52
 
server_interface = domain + u'.Mandos'
53
 
client_interface = domain + u'.Mandos.Client'
54
 
version = u"1.2.3"
 
51
domain = 'se.bsnet.fukt'
 
52
server_interface = domain + '.Mandos'
 
53
client_interface = domain + '.Mandos.Client'
 
54
version = "1.3.0"
55
55
 
56
56
# Always run in monochrome mode
57
57
urwid.curses_display.curses.has_colors = lambda : False
65
65
    "Parse an ISO 8601 date string to a datetime.datetime()"
66
66
    if not iso:
67
67
        return None
68
 
    d, t = iso.split(u"T", 1)
69
 
    year, month, day = d.split(u"-", 2)
70
 
    hour, minute, second = t.split(u":", 2)
 
68
    d, t = iso.split("T", 1)
 
69
    year, month, day = d.split("-", 2)
 
70
    hour, minute, second = t.split(":", 2)
71
71
    second, fraction = divmod(float(second), 1)
72
72
    return datetime.datetime(int(year),
73
73
                             int(month),
86
86
        self.proxy = proxy_object # Mandos Client proxy object
87
87
        
88
88
        self.properties = dict()
89
 
        self.proxy.connect_to_signal(u"PropertyChanged",
 
89
        self.proxy.connect_to_signal("PropertyChanged",
90
90
                                     self.property_changed,
91
91
                                     client_interface,
92
92
                                     byte_arrays=True)
127
127
        self.last_checker_failed = False
128
128
        
129
129
        # The widget shown normally
130
 
        self._text_widget = urwid.Text(u"")
 
130
        self._text_widget = urwid.Text("")
131
131
        # The widget shown when we have focus
132
 
        self._focus_text_widget = urwid.Text(u"")
 
132
        self._focus_text_widget = urwid.Text("")
133
133
        super(MandosClientWidget, self).__init__(
134
134
            update_hook=update_hook, delete_hook=delete_hook,
135
135
            *args, **kwargs)
137
137
        self.opened = False
138
138
        
139
139
        last_checked_ok = isoformat_to_datetime(self.properties
140
 
                                                [u"LastCheckedOK"])
 
140
                                                ["LastCheckedOK"])
141
141
        if last_checked_ok is None:
142
142
            self.last_checker_failed = True
143
143
        else:
146
146
                                        > datetime.timedelta
147
147
                                        (milliseconds=
148
148
                                         self.properties
149
 
                                         [u"Interval"]))
 
149
                                         ["Interval"]))
150
150
        
151
151
        if self.last_checker_failed:
152
152
            self.using_timer(True)
154
154
        if self.need_approval:
155
155
            self.using_timer(True)
156
156
        
157
 
        self.proxy.connect_to_signal(u"CheckerCompleted",
 
157
        self.proxy.connect_to_signal("CheckerCompleted",
158
158
                                     self.checker_completed,
159
159
                                     client_interface,
160
160
                                     byte_arrays=True)
161
 
        self.proxy.connect_to_signal(u"CheckerStarted",
 
161
        self.proxy.connect_to_signal("CheckerStarted",
162
162
                                     self.checker_started,
163
163
                                     client_interface,
164
164
                                     byte_arrays=True)
165
 
        self.proxy.connect_to_signal(u"GotSecret",
 
165
        self.proxy.connect_to_signal("GotSecret",
166
166
                                     self.got_secret,
167
167
                                     client_interface,
168
168
                                     byte_arrays=True)
169
 
        self.proxy.connect_to_signal(u"NeedApproval",
 
169
        self.proxy.connect_to_signal("NeedApproval",
170
170
                                     self.need_approval,
171
171
                                     client_interface,
172
172
                                     byte_arrays=True)
173
 
        self.proxy.connect_to_signal(u"Rejected",
 
173
        self.proxy.connect_to_signal("Rejected",
174
174
                                     self.rejected,
175
175
                                     client_interface,
176
176
                                     byte_arrays=True)
178
178
    def property_changed(self, property=None, value=None):
179
179
        super(self, MandosClientWidget).property_changed(property,
180
180
                                                         value)
181
 
        if property == u"ApprovalPending":
 
181
        if property == "ApprovalPending":
182
182
            using_timer(bool(value))
183
183
        
184
184
    def using_timer(self, flag):
203
203
            if self.last_checker_failed:
204
204
                self.last_checker_failed = False
205
205
                self.using_timer(False)
206
 
            #self.logger(u'Checker for client %s (command "%s")'
207
 
            #            u' was successful'
208
 
            #            % (self.properties[u"Name"], command))
 
206
            #self.logger('Checker for client %s (command "%s")'
 
207
            #            ' was successful'
 
208
            #            % (self.properties["Name"], command))
209
209
            self.update()
210
210
            return
211
211
        # Checker failed
213
213
            self.last_checker_failed = True
214
214
            self.using_timer(True)
215
215
        if os.WIFEXITED(condition):
216
 
            self.logger(u'Checker for client %s (command "%s")'
217
 
                        u' failed with exit code %s'
218
 
                        % (self.properties[u"Name"], command,
 
216
            self.logger('Checker for client %s (command "%s")'
 
217
                        ' failed with exit code %s'
 
218
                        % (self.properties["Name"], command,
219
219
                           os.WEXITSTATUS(condition)))
220
220
        elif os.WIFSIGNALED(condition):
221
 
            self.logger(u'Checker for client %s (command "%s")'
222
 
                        u' was killed by signal %s'
223
 
                        % (self.properties[u"Name"], command,
 
221
            self.logger('Checker for client %s (command "%s")'
 
222
                        ' was killed by signal %s'
 
223
                        % (self.properties["Name"], command,
224
224
                           os.WTERMSIG(condition)))
225
225
        elif os.WCOREDUMP(condition):
226
 
            self.logger(u'Checker for client %s (command "%s")'
227
 
                        u' dumped core'
228
 
                        % (self.properties[u"Name"], command))
 
226
            self.logger('Checker for client %s (command "%s")'
 
227
                        ' dumped core'
 
228
                        % (self.properties["Name"], command))
229
229
        else:
230
 
            self.logger(u'Checker for client %s completed'
231
 
                        u' mysteriously')
 
230
            self.logger('Checker for client %s completed'
 
231
                        ' mysteriously')
232
232
        self.update()
233
233
    
234
234
    def checker_started(self, command):
235
 
        #self.logger(u'Client %s started checker "%s"'
236
 
        #            % (self.properties[u"Name"], unicode(command)))
 
235
        #self.logger('Client %s started checker "%s"'
 
236
        #            % (self.properties["Name"], unicode(command)))
237
237
        pass
238
238
    
239
239
    def got_secret(self):
240
240
        self.last_checker_failed = False
241
 
        self.logger(u'Client %s received its secret'
242
 
                    % self.properties[u"Name"])
 
241
        self.logger('Client %s received its secret'
 
242
                    % self.properties["Name"])
243
243
    
244
244
    def need_approval(self, timeout, default):
245
245
        if not default:
246
 
            message = u'Client %s needs approval within %s seconds'
 
246
            message = 'Client %s needs approval within %s seconds'
247
247
        else:
248
 
            message = u'Client %s will get its secret in %s seconds'
 
248
            message = 'Client %s will get its secret in %s seconds'
249
249
        self.logger(message
250
 
                    % (self.properties[u"Name"], timeout/1000))
 
250
                    % (self.properties["Name"], timeout/1000))
251
251
        self.using_timer(True)
252
252
    
253
253
    def rejected(self, reason):
254
 
        self.logger(u'Client %s was rejected; reason: %s'
255
 
                    % (self.properties[u"Name"], reason))
 
254
        self.logger('Client %s was rejected; reason: %s'
 
255
                    % (self.properties["Name"], reason))
256
256
    
257
257
    def selectable(self):
258
258
        """Make this a "selectable" widget.
273
273
    def update(self):
274
274
        "Called when what is visible on the screen should be updated."
275
275
        # How to add standout mode to a style
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",
 
276
        with_standout = { "normal": "standout",
 
277
                          "bold": "bold-standout",
 
278
                          "underline-blink":
 
279
                              "underline-blink-standout",
 
280
                          "bold-underline-blink":
 
281
                              "bold-underline-blink-standout",
282
282
                          }
283
283
 
284
284
        # Rebuild focus and non-focus widgets using current properties
285
285
 
286
286
        # Base part of a client. Name!
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"]:
 
287
        base = ('%(name)s: '
 
288
                      % {"name": self.properties["Name"]})
 
289
        if not self.properties["Enabled"]:
 
290
            message = "DISABLED"
 
291
        elif self.properties["ApprovalPending"]:
292
292
            timeout = datetime.timedelta(milliseconds
293
293
                                         = self.properties
294
 
                                         [u"ApprovalDelay"])
 
294
                                         ["ApprovalDelay"])
295
295
            last_approval_request = isoformat_to_datetime(
296
 
                self.properties[u"LastApprovalRequest"])
 
296
                self.properties["LastApprovalRequest"])
297
297
            if last_approval_request is not None:
298
298
                timer = timeout - (datetime.datetime.utcnow()
299
299
                                   - last_approval_request)
300
300
            else:
301
301
                timer = datetime.timedelta()
302
 
            if self.properties[u"ApprovedByDefault"]:
303
 
                message = u"Approval in %s. (d)eny?"
 
302
            if self.properties["ApprovedByDefault"]:
 
303
                message = "Approval in %s. (d)eny?"
304
304
            else:
305
 
                message = u"Denial in %s. (a)pprove?"
 
305
                message = "Denial in %s. (a)pprove?"
306
306
            message = message % unicode(timer).rsplit(".", 1)[0]
307
307
        elif self.last_checker_failed:
308
308
            timeout = datetime.timedelta(milliseconds
309
309
                                         = self.properties
310
 
                                         [u"Timeout"])
 
310
                                         ["Timeout"])
311
311
            last_ok = isoformat_to_datetime(
312
 
                max((self.properties[u"LastCheckedOK"]
313
 
                     or self.properties[u"Created"]),
314
 
                    self.properties[u"LastEnabled"]))
 
312
                max((self.properties["LastCheckedOK"]
 
313
                     or self.properties["Created"]),
 
314
                    self.properties["LastEnabled"]))
315
315
            timer = timeout - (datetime.datetime.utcnow() - last_ok)
316
 
            message = (u'A checker has failed! Time until client'
317
 
                       u' gets disabled: %s'
 
316
            message = ('A checker has failed! Time until client'
 
317
                       ' gets disabled: %s'
318
318
                           % unicode(timer).rsplit(".", 1)[0])
319
319
        else:
320
 
            message = u"enabled"
321
 
        self._text = u"%s%s" % (base, message)
 
320
            message = "enabled"
 
321
        self._text = "%s%s" % (base, message)
322
322
            
323
323
        if not urwid.supports_unicode():
324
 
            self._text = self._text.encode(u"ascii", u"replace")
325
 
        textlist = [(u"normal", self._text)]
 
324
            self._text = self._text.encode("ascii", "replace")
 
325
        textlist = [("normal", self._text)]
326
326
        self._text_widget.set_text(textlist)
327
327
        self._focus_text_widget.set_text([(with_standout[text[0]],
328
328
                                           text[1])
331
331
                                          for text in textlist])
332
332
        self._widget = self._text_widget
333
333
        self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
334
 
                                            u"standout")
 
334
                                            "standout")
335
335
        # Run update hook, if any
336
336
        if self.update_hook is not None:
337
337
            self.update_hook()
357
357
    def keypress(self, maxcolrow, key):
358
358
        """Handle keys.
359
359
        This overrides the method from urwid.FlowWidget"""
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":
 
360
        if key == "+":
 
361
            self.proxy.Enable(dbus_interface = client_interface,
 
362
                              ignore_reply=True)
 
363
        elif key == "-":
 
364
            self.proxy.Disable(dbus_interface = client_interface,
 
365
                               ignore_reply=True)
 
366
        elif key == "a":
365
367
            self.proxy.Approve(dbus.Boolean(True, variant_level=1),
366
 
                               dbus_interface = client_interface)
367
 
        elif key == u"d":
 
368
                               dbus_interface = client_interface,
 
369
                               ignore_reply=True)
 
370
        elif key == "d":
368
371
            self.proxy.Approve(dbus.Boolean(False, variant_level=1),
369
 
                                  dbus_interface = client_interface)
370
 
        elif key == u"R" or key == u"_" or key == u"ctrl k":
 
372
                                  dbus_interface = client_interface,
 
373
                               ignore_reply=True)
 
374
        elif key == "R" or key == "_" or key == "ctrl k":
371
375
            self.server_proxy_object.RemoveClient(self.proxy
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)
 
376
                                                  .object_path,
 
377
                                                  ignore_reply=True)
 
378
        elif key == "s":
 
379
            self.proxy.StartChecker(dbus_interface = client_interface,
 
380
                                    ignore_reply=True)
 
381
        elif key == "S":
 
382
            self.proxy.StopChecker(dbus_interface = client_interface,
 
383
                                   ignore_reply=True)
 
384
        elif key == "C":
 
385
            self.proxy.CheckedOK(dbus_interface = client_interface,
 
386
                                 ignore_reply=True)
379
387
        # xxx
380
 
#         elif key == u"p" or key == "=":
 
388
#         elif key == "p" or key == "=":
381
389
#             self.proxy.pause()
382
 
#         elif key == u"u" or key == ":":
 
390
#         elif key == "u" or key == ":":
383
391
#             self.proxy.unpause()
384
 
#         elif key == u"RET":
 
392
#         elif key == "RET":
385
393
#             self.open()
386
394
        else:
387
395
            return key
405
413
    """
406
414
    def keypress(self, maxcolrow, key):
407
415
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
408
 
        if ret in (u"up", u"down"):
 
416
        if ret in ("up", "down"):
409
417
            return
410
418
        return ret
411
419
 
420
428
        self.screen = urwid.curses_display.Screen()
421
429
        
422
430
        self.screen.register_palette((
423
 
                (u"normal",
424
 
                 u"default", u"default", None),
425
 
                (u"bold",
426
 
                 u"default", u"default", u"bold"),
427
 
                (u"underline-blink",
428
 
                 u"default", u"default", u"underline"),
429
 
                (u"standout",
430
 
                 u"default", u"default", u"standout"),
431
 
                (u"bold-underline-blink",
432
 
                 u"default", u"default", (u"bold", u"underline")),
433
 
                (u"bold-standout",
434
 
                 u"default", u"default", (u"bold", u"standout")),
435
 
                (u"underline-blink-standout",
436
 
                 u"default", u"default", (u"underline", u"standout")),
437
 
                (u"bold-underline-blink-standout",
438
 
                 u"default", u"default", (u"bold", u"underline",
439
 
                                          u"standout")),
 
431
                ("normal",
 
432
                 "default", "default", None),
 
433
                ("bold",
 
434
                 "default", "default", "bold"),
 
435
                ("underline-blink",
 
436
                 "default", "default", "underline"),
 
437
                ("standout",
 
438
                 "default", "default", "standout"),
 
439
                ("bold-underline-blink",
 
440
                 "default", "default", ("bold", "underline")),
 
441
                ("bold-standout",
 
442
                 "default", "default", ("bold", "standout")),
 
443
                ("underline-blink-standout",
 
444
                 "default", "default", ("underline", "standout")),
 
445
                ("bold-underline-blink-standout",
 
446
                 "default", "default", ("bold", "underline",
 
447
                                          "standout")),
440
448
                ))
441
449
        
442
450
        if urwid.supports_unicode():
443
 
            self.divider = u"─" # \u2500
444
 
            #self.divider = u"━" # \u2501
 
451
            self.divider = "─" # \u2500
 
452
            #self.divider = "━" # \u2501
445
453
        else:
446
 
            #self.divider = u"-" # \u002d
447
 
            self.divider = u"_" # \u005f
 
454
            #self.divider = "-" # \u002d
 
455
            self.divider = "_" # \u005f
448
456
        
449
457
        self.screen.start()
450
458
        
464
472
        # This keeps track of whether self.uilist currently has
465
473
        # self.logbox in it or not
466
474
        self.log_visible = True
467
 
        self.log_wrap = u"any"
 
475
        self.log_wrap = "any"
468
476
        
469
477
        self.rebuild()
470
 
        self.log_message_raw((u"bold",
471
 
                              u"Mandos Monitor version " + version))
472
 
        self.log_message_raw((u"bold",
473
 
                              u"q: Quit  ?: Help"))
 
478
        self.log_message_raw(("bold",
 
479
                              "Mandos Monitor version " + version))
 
480
        self.log_message_raw(("bold",
 
481
                              "q: Quit  ?: Help"))
474
482
        
475
483
        self.busname = domain + '.Mandos'
476
484
        self.main_loop = gobject.MainLoop()
477
485
        self.bus = dbus.SystemBus()
478
486
        mandos_dbus_objc = self.bus.get_object(
479
 
            self.busname, u"/", follow_name_owner_changes=True)
 
487
            self.busname, "/", follow_name_owner_changes=True)
480
488
        self.mandos_serv = dbus.Interface(mandos_dbus_objc,
481
489
                                          dbus_interface
482
490
                                          = server_interface)
487
495
            mandos_clients = dbus.Dictionary()
488
496
        
489
497
        (self.mandos_serv
490
 
         .connect_to_signal(u"ClientRemoved",
 
498
         .connect_to_signal("ClientRemoved",
491
499
                            self.find_and_remove_client,
492
500
                            dbus_interface=server_interface,
493
501
                            byte_arrays=True))
494
502
        (self.mandos_serv
495
 
         .connect_to_signal(u"ClientAdded",
 
503
         .connect_to_signal("ClientAdded",
496
504
                            self.add_new_client,
497
505
                            dbus_interface=server_interface,
498
506
                            byte_arrays=True))
499
507
        (self.mandos_serv
500
 
         .connect_to_signal(u"ClientNotFound",
 
508
         .connect_to_signal("ClientNotFound",
501
509
                            self.client_not_found,
502
510
                            dbus_interface=server_interface,
503
511
                            byte_arrays=True))
518
526
                            path=path)
519
527
    
520
528
    def client_not_found(self, fingerprint, address):
521
 
        self.log_message((u"Client with address %s and fingerprint %s"
522
 
                          u" could not be found" % (address,
 
529
        self.log_message(("Client with address %s and fingerprint %s"
 
530
                          " could not be found" % (address,
523
531
                                                    fingerprint)))
524
532
    
525
533
    def rebuild(self):
541
549
    
542
550
    def log_message(self, message):
543
551
        timestamp = datetime.datetime.now().isoformat()
544
 
        self.log_message_raw(timestamp + u": " + message)
 
552
        self.log_message_raw(timestamp + ": " + message)
545
553
    
546
554
    def log_message_raw(self, markup):
547
555
        """Add a log message to the log buffer."""
550
558
            and len(self.log) > self.max_log_length):
551
559
            del self.log[0:len(self.log)-self.max_log_length-1]
552
560
        self.logbox.set_focus(len(self.logbox.body.contents),
553
 
                              coming_from=u"above")
 
561
                              coming_from="above")
554
562
        self.refresh()
555
563
    
556
564
    def toggle_log_display(self):
557
565
        """Toggle visibility of the log buffer."""
558
566
        self.log_visible = not self.log_visible
559
567
        self.rebuild()
560
 
        #self.log_message(u"Log visibility changed to: "
 
568
        #self.log_message("Log visibility changed to: "
561
569
        #                 + unicode(self.log_visible))
562
570
    
563
571
    def change_log_display(self):
564
572
        """Change type of log display.
565
573
        Currently, this toggles wrapping of text lines."""
566
 
        if self.log_wrap == u"clip":
567
 
            self.log_wrap = u"any"
 
574
        if self.log_wrap == "clip":
 
575
            self.log_wrap = "any"
568
576
        else:
569
 
            self.log_wrap = u"clip"
 
577
            self.log_wrap = "clip"
570
578
        for textwidget in self.log:
571
579
            textwidget.set_wrap_mode(self.log_wrap)
572
 
        #self.log_message(u"Wrap mode: " + self.log_wrap)
 
580
        #self.log_message("Wrap mode: " + self.log_wrap)
573
581
    
574
582
    def find_and_remove_client(self, path, name):
575
583
        """Find an client from its object path and remove it.
602
610
        if path is None:
603
611
            path = client.proxy.object_path
604
612
        self.clients_dict[path] = client
605
 
        self.clients.sort(None, lambda c: c.properties[u"Name"])
 
613
        self.clients.sort(None, lambda c: c.properties["Name"])
606
614
        self.refresh()
607
615
    
608
616
    def remove_client(self, client, path=None):
639
647
    
640
648
    def process_input(self, source, condition):
641
649
        keys = self.screen.get_input()
642
 
        translations = { u"ctrl n": u"down",      # Emacs
643
 
                         u"ctrl p": u"up",        # Emacs
644
 
                         u"ctrl v": u"page down", # Emacs
645
 
                         u"meta v": u"page up",   # Emacs
646
 
                         u" ": u"page down",      # less
647
 
                         u"f": u"page down",      # less
648
 
                         u"b": u"page up",        # less
649
 
                         u"j": u"down",           # vi
650
 
                         u"k": u"up",             # vi
 
650
        translations = { "ctrl n": "down",      # Emacs
 
651
                         "ctrl p": "up",        # Emacs
 
652
                         "ctrl v": "page down", # Emacs
 
653
                         "meta v": "page up",   # Emacs
 
654
                         " ": "page down",      # less
 
655
                         "f": "page down",      # less
 
656
                         "b": "page up",        # less
 
657
                         "j": "down",           # vi
 
658
                         "k": "up",             # vi
651
659
                         }
652
660
        for key in keys:
653
661
            try:
655
663
            except KeyError:    # :-)
656
664
                pass
657
665
            
658
 
            if key == u"q" or key == u"Q":
 
666
            if key == "q" or key == "Q":
659
667
                self.stop()
660
668
                break
661
 
            elif key == u"window resize":
 
669
            elif key == "window resize":
662
670
                self.size = self.screen.get_cols_rows()
663
671
                self.refresh()
664
 
            elif key == u"\f":  # Ctrl-L
 
672
            elif key == "\f":  # Ctrl-L
665
673
                self.refresh()
666
 
            elif key == u"l" or key == u"D":
 
674
            elif key == "l" or key == "D":
667
675
                self.toggle_log_display()
668
676
                self.refresh()
669
 
            elif key == u"w" or key == u"i":
 
677
            elif key == "w" or key == "i":
670
678
                self.change_log_display()
671
679
                self.refresh()
672
 
            elif key == u"?" or key == u"f1" or key == u"esc":
 
680
            elif key == "?" or key == "f1" or key == "esc":
673
681
                if not self.log_visible:
674
682
                    self.log_visible = True
675
683
                    self.rebuild()
676
 
                self.log_message_raw((u"bold",
677
 
                                      u"  ".
678
 
                                      join((u"q: Quit",
679
 
                                            u"?: Help",
680
 
                                            u"l: Log window toggle",
681
 
                                            u"TAB: Switch window",
682
 
                                            u"w: Wrap (log)"))))
683
 
                self.log_message_raw((u"bold",
684
 
                                      u"  "
685
 
                                      .join((u"Clients:",
686
 
                                             u"+: Enable",
687
 
                                             u"-: Disable",
688
 
                                             u"R: Remove",
689
 
                                             u"s: Start new checker",
690
 
                                             u"S: Stop checker",
691
 
                                             u"C: Checker OK",
692
 
                                             u"a: Approve",
693
 
                                             u"d: Deny"))))
 
684
                self.log_message_raw(("bold",
 
685
                                      "  ".
 
686
                                      join(("q: Quit",
 
687
                                            "?: Help",
 
688
                                            "l: Log window toggle",
 
689
                                            "TAB: Switch window",
 
690
                                            "w: Wrap (log)"))))
 
691
                self.log_message_raw(("bold",
 
692
                                      "  "
 
693
                                      .join(("Clients:",
 
694
                                             "+: Enable",
 
695
                                             "-: Disable",
 
696
                                             "R: Remove",
 
697
                                             "s: Start new checker",
 
698
                                             "S: Stop checker",
 
699
                                             "C: Checker OK",
 
700
                                             "a: Approve",
 
701
                                             "d: Deny"))))
694
702
                self.refresh()
695
 
            elif key == u"tab":
 
703
            elif key == "tab":
696
704
                if self.topwidget.get_focus() is self.logbox:
697
705
                    self.topwidget.set_focus(0)
698
706
                else:
699
707
                    self.topwidget.set_focus(self.logbox)
700
708
                self.refresh()
701
 
            #elif (key == u"end" or key == u"meta >" or key == u"G"
702
 
            #      or key == u">"):
 
709
            #elif (key == "end" or key == "meta >" or key == "G"
 
710
            #      or key == ">"):
703
711
            #    pass            # xxx end-of-buffer
704
 
            #elif (key == u"home" or key == u"meta <" or key == u"g"
705
 
            #      or key == u"<"):
 
712
            #elif (key == "home" or key == "meta <" or key == "g"
 
713
            #      or key == "<"):
706
714
            #    pass            # xxx beginning-of-buffer
707
 
            #elif key == u"ctrl e" or key == u"$":
 
715
            #elif key == "ctrl e" or key == "$":
708
716
            #    pass            # xxx move-end-of-line
709
 
            #elif key == u"ctrl a" or key == u"^":
 
717
            #elif key == "ctrl a" or key == "^":
710
718
            #    pass            # xxx move-beginning-of-line
711
 
            #elif key == u"ctrl b" or key == u"meta (" or key == u"h":
 
719
            #elif key == "ctrl b" or key == "meta (" or key == "h":
712
720
            #    pass            # xxx left
713
 
            #elif key == u"ctrl f" or key == u"meta )" or key == u"l":
 
721
            #elif key == "ctrl f" or key == "meta )" or key == "l":
714
722
            #    pass            # xxx right
715
 
            #elif key == u"a":
 
723
            #elif key == "a":
716
724
            #    pass            # scroll up log
717
 
            #elif key == u"z":
 
725
            #elif key == "z":
718
726
            #    pass            # scroll down log
719
727
            elif self.topwidget.selectable():
720
728
                self.topwidget.keypress(self.size, key)