130
86
self.logger = logger
132
self._update_timer_callback_tag = None
133
self._update_timer_callback_lock = 0
134
self.last_checker_failed = False
136
88
# The widget shown normally
137
self._text_widget = urwid.Text("")
89
self._text_widget = urwid.Text(u"")
138
90
# The widget shown when we have focus
139
self._focus_text_widget = urwid.Text("")
91
self._focus_text_widget = urwid.Text(u"")
140
92
super(MandosClientWidget, self).__init__(
141
93
update_hook=update_hook, delete_hook=delete_hook,
144
96
self.opened = False
146
last_checked_ok = isoformat_to_datetime(self.properties
148
if last_checked_ok is None:
149
self.last_checker_failed = True
151
self.last_checker_failed = ((datetime.datetime.utcnow()
158
if self.last_checker_failed:
159
self.using_timer(True)
161
if self.need_approval:
162
self.using_timer(True)
164
self.match_objects = (
165
self.proxy.connect_to_signal("CheckerCompleted",
166
self.checker_completed,
169
self.proxy.connect_to_signal("CheckerStarted",
170
self.checker_started,
173
self.proxy.connect_to_signal("GotSecret",
177
self.proxy.connect_to_signal("NeedApproval",
181
self.proxy.connect_to_signal("Rejected",
185
#self.logger('Created client %s' % (self.properties["Name"]))
187
def property_changed(self, property=None, value=None):
188
super(self, MandosClientWidget).property_changed(property,
190
if property == "ApprovalPending":
191
using_timer(bool(value))
193
def using_timer(self, flag):
194
"""Call this method with True or False when timer should be
195
activated or deactivated.
197
old = self._update_timer_callback_lock
199
self._update_timer_callback_lock += 1
201
self._update_timer_callback_lock -= 1
202
if old == 0 and self._update_timer_callback_lock:
203
self._update_timer_callback_tag = (gobject.timeout_add
206
elif old and self._update_timer_callback_lock == 0:
207
gobject.source_remove(self._update_timer_callback_tag)
208
self._update_timer_callback_tag = None
97
self.proxy.connect_to_signal(u"CheckerCompleted",
98
self.checker_completed,
101
self.proxy.connect_to_signal(u"CheckerStarted",
102
self.checker_started,
105
self.proxy.connect_to_signal(u"GotSecret",
109
self.proxy.connect_to_signal(u"NeedApproval",
113
self.proxy.connect_to_signal(u"Rejected",
210
118
def checker_completed(self, exitstatus, condition, command):
211
119
if exitstatus == 0:
212
if self.last_checker_failed:
213
self.last_checker_failed = False
214
self.using_timer(False)
215
#self.logger('Checker for client %s (command "%s")'
217
# % (self.properties["Name"], command))
120
#self.logger(u'Checker for client %s (command "%s")'
122
# % (self.properties[u"name"], command))
221
if not self.last_checker_failed:
222
self.last_checker_failed = True
223
self.using_timer(True)
224
124
if os.WIFEXITED(condition):
225
self.logger('Checker for client %s (command "%s")'
226
' failed with exit code %s'
227
% (self.properties["Name"], command,
125
self.logger(u'Checker for client %s (command "%s")'
126
u' failed with exit code %s'
127
% (self.properties[u"name"], command,
228
128
os.WEXITSTATUS(condition)))
229
elif os.WIFSIGNALED(condition):
230
self.logger('Checker for client %s (command "%s")'
231
' was killed by signal %s'
232
% (self.properties["Name"], command,
130
if os.WIFSIGNALED(condition):
131
self.logger(u'Checker for client %s (command "%s")'
132
u' was killed by signal %s'
133
% (self.properties[u"name"], command,
233
134
os.WTERMSIG(condition)))
234
elif os.WCOREDUMP(condition):
235
self.logger('Checker for client %s (command "%s")'
237
% (self.properties["Name"], command))
239
self.logger('Checker for client %s completed'
136
if os.WCOREDUMP(condition):
137
self.logger(u'Checker for client %s (command "%s")'
139
% (self.properties[u"name"], command))
140
self.logger(u'Checker for client %s completed mysteriously')
243
142
def checker_started(self, command):
244
#self.logger('Client %s started checker "%s"'
245
# % (self.properties["Name"], unicode(command)))
143
#self.logger(u'Client %s started checker "%s"'
144
# % (self.properties[u"name"], unicode(command)))
248
147
def got_secret(self):
249
self.last_checker_failed = False
250
self.logger('Client %s received its secret'
251
% self.properties["Name"])
148
self.logger(u'Client %s received its secret'
149
% self.properties[u"name"])
253
151
def need_approval(self, timeout, default):
255
message = 'Client %s needs approval within %s seconds'
153
message = u'Client %s needs approval within %s seconds'
257
message = 'Client %s will get its secret in %s seconds'
155
message = u'Client %s will get its secret in %s seconds'
258
156
self.logger(message
259
% (self.properties["Name"], timeout/1000))
260
self.using_timer(True)
157
% (self.properties[u"name"], timeout/1000))
262
159
def rejected(self, reason):
263
self.logger('Client %s was rejected; reason: %s'
264
% (self.properties["Name"], reason))
160
self.logger(u'Client %s was rejected; reason: %s'
161
% (self.properties[u"name"], reason))
266
163
def selectable(self):
267
164
"""Make this a "selectable" widget.
268
165
This overrides the method from urwid.FlowWidget."""
271
def rows(self, maxcolrow, focus=False):
168
def rows(self, (maxcol,), focus=False):
272
169
"""How many rows this widget will occupy might depend on
273
170
whether we have focus or not.
274
171
This overrides the method from urwid.FlowWidget"""
275
return self.current_widget(focus).rows(maxcolrow, focus=focus)
172
return self.current_widget(focus).rows((maxcol,), focus=focus)
277
174
def current_widget(self, focus=False):
278
175
if focus or self.opened:
282
179
def update(self):
283
180
"Called when what is visible on the screen should be updated."
284
181
# How to add standout mode to a style
285
with_standout = { "normal": "standout",
286
"bold": "bold-standout",
288
"underline-blink-standout",
289
"bold-underline-blink":
290
"bold-underline-blink-standout",
182
with_standout = { u"normal": u"standout",
183
u"bold": u"bold-standout",
185
u"underline-blink-standout",
186
u"bold-underline-blink":
187
u"bold-underline-blink-standout",
293
190
# Rebuild focus and non-focus widgets using current properties
295
192
# Base part of a client. Name!
297
% {"name": self.properties["Name"]})
298
if not self.properties["Enabled"]:
300
elif self.properties["ApprovalPending"]:
301
timeout = datetime.timedelta(milliseconds
304
last_approval_request = isoformat_to_datetime(
305
self.properties["LastApprovalRequest"])
306
if last_approval_request is not None:
307
timer = timeout - (datetime.datetime.utcnow()
308
- last_approval_request)
310
timer = datetime.timedelta()
311
if self.properties["ApprovedByDefault"]:
312
message = "Approval in %s. (d)eny?"
314
message = "Denial in %s. (a)pprove?"
315
message = message % unicode(timer).rsplit(".", 1)[0]
316
elif self.last_checker_failed:
317
timeout = datetime.timedelta(milliseconds
320
last_ok = isoformat_to_datetime(
321
max((self.properties["LastCheckedOK"]
322
or self.properties["Created"]),
323
self.properties["LastEnabled"]))
324
timer = timeout - (datetime.datetime.utcnow() - last_ok)
325
message = ('A checker has failed! Time until client'
327
% unicode(timer).rsplit(".", 1)[0])
193
self._text = (u'%(name)s: '
194
% {u"name": self.properties[u"name"]})
196
if self.properties[u"approved_pending"]:
197
if self.properties[u"approved_by_default"]:
198
self._text += u"Connection established to client. (d)eny?"
200
self._text += u"Seeks approval to send secret. (a)pprove?"
330
self._text = "%s%s" % (base, message)
202
self._text += (u'%(enabled)s'
205
if self.properties[u"enabled"]
332
207
if not urwid.supports_unicode():
333
208
self._text = self._text.encode("ascii", "replace")
334
textlist = [("normal", self._text)]
209
textlist = [(u"normal", self._text)]
335
210
self._text_widget.set_text(textlist)
336
211
self._focus_text_widget.set_text([(with_standout[text[0]],
345
220
if self.update_hook is not None:
346
221
self.update_hook()
348
def update_timer(self):
351
return True # Keep calling this
353
def delete(self, *args, **kwargs):
354
if self._update_timer_callback_tag is not None:
355
gobject.source_remove(self._update_timer_callback_tag)
356
self._update_timer_callback_tag = None
357
for match in self.match_objects:
359
self.match_objects = ()
360
224
if self.delete_hook is not None:
361
225
self.delete_hook(self)
362
return super(MandosClientWidget, self).delete(*args, **kwargs)
364
def render(self, maxcolrow, focus=False):
227
def render(self, (maxcol,), focus=False):
365
228
"""Render differently if we have focus.
366
229
This overrides the method from urwid.FlowWidget"""
367
return self.current_widget(focus).render(maxcolrow,
230
return self.current_widget(focus).render((maxcol,),
370
def keypress(self, maxcolrow, key):
233
def keypress(self, (maxcol,), key):
372
235
This overrides the method from urwid.FlowWidget"""
374
self.proxy.Enable(dbus_interface = client_interface,
377
self.proxy.Disable(dbus_interface = client_interface,
237
self.proxy.Enable(dbus_interface = client_interface)
239
self.proxy.Disable(dbus_interface = client_interface)
380
241
self.proxy.Approve(dbus.Boolean(True, variant_level=1),
381
dbus_interface = client_interface,
242
dbus_interface = client_interface)
384
244
self.proxy.Approve(dbus.Boolean(False, variant_level=1),
385
dbus_interface = client_interface,
387
elif key == "R" or key == "_" or key == "ctrl k":
245
dbus_interface = client_interface)
246
elif key == u"r" or key == u"_" or key == u"ctrl k":
388
247
self.server_proxy_object.RemoveClient(self.proxy
392
self.proxy.StartChecker(dbus_interface = client_interface,
395
self.proxy.StopChecker(dbus_interface = client_interface,
398
self.proxy.CheckedOK(dbus_interface = client_interface,
250
self.proxy.StartChecker(dbus_interface = client_interface)
252
self.proxy.StopChecker(dbus_interface = client_interface)
254
self.proxy.CheckedOK(dbus_interface = client_interface)
401
# elif key == "p" or key == "=":
256
# elif key == u"p" or key == "=":
402
257
# self.proxy.pause()
403
# elif key == "u" or key == ":":
258
# elif key == u"u" or key == ":":
404
259
# self.proxy.unpause()
260
# elif key == u"RET":
263
# self.proxy.Approve(True)
265
# self.proxy.Approve(False)
441
300
self.screen = urwid.curses_display.Screen()
443
302
self.screen.register_palette((
445
"default", "default", None),
447
"default", "default", "bold"),
449
"default", "default", "underline"),
451
"default", "default", "standout"),
452
("bold-underline-blink",
453
"default", "default", ("bold", "underline")),
455
"default", "default", ("bold", "standout")),
456
("underline-blink-standout",
457
"default", "default", ("underline", "standout")),
458
("bold-underline-blink-standout",
459
"default", "default", ("bold", "underline",
304
u"default", u"default", None),
306
u"default", u"default", u"bold"),
308
u"default", u"default", u"underline"),
310
u"default", u"default", u"standout"),
311
(u"bold-underline-blink",
312
u"default", u"default", (u"bold", u"underline")),
314
u"default", u"default", (u"bold", u"standout")),
315
(u"underline-blink-standout",
316
u"default", u"default", (u"underline", u"standout")),
317
(u"bold-underline-blink-standout",
318
u"default", u"default", (u"bold", u"underline",
463
322
if urwid.supports_unicode():
464
self.divider = "─" # \u2500
465
#self.divider = "━" # \u2501
323
self.divider = u"─" # \u2500
324
#self.divider = u"━" # \u2501
467
#self.divider = "-" # \u002d
468
self.divider = "_" # \u005f
326
#self.divider = u"-" # \u002d
327
self.divider = u"_" # \u005f
470
329
self.screen.start()
571
427
and len(self.log) > self.max_log_length):
572
428
del self.log[0:len(self.log)-self.max_log_length-1]
573
429
self.logbox.set_focus(len(self.logbox.body.contents),
430
coming_from=u"above")
577
433
def toggle_log_display(self):
578
434
"""Toggle visibility of the log buffer."""
579
435
self.log_visible = not self.log_visible
581
#self.log_message("Log visibility changed to: "
582
# + unicode(self.log_visible))
437
self.log_message(u"Log visibility changed to: "
438
+ unicode(self.log_visible))
584
440
def change_log_display(self):
585
441
"""Change type of log display.
586
442
Currently, this toggles wrapping of text lines."""
587
if self.log_wrap == "clip":
588
self.log_wrap = "any"
443
if self.log_wrap == u"clip":
444
self.log_wrap = u"any"
590
self.log_wrap = "clip"
446
self.log_wrap = u"clip"
591
447
for textwidget in self.log:
592
448
textwidget.set_wrap_mode(self.log_wrap)
593
#self.log_message("Wrap mode: " + self.log_wrap)
449
self.log_message(u"Wrap mode: " + self.log_wrap)
595
451
def find_and_remove_client(self, path, name):
596
"""Find a client by its object path and remove it.
452
"""Find an client from its object path and remove it.
598
454
This is connected to the ClientRemoved signal from the
599
455
Mandos server object."""
678
532
except KeyError: # :-)
681
if key == "q" or key == "Q":
535
if key == u"q" or key == u"Q":
684
elif key == "window resize":
538
elif key == u"window resize":
685
539
self.size = self.screen.get_cols_rows()
687
elif key == "\f": # Ctrl-L
541
elif key == u"\f": # Ctrl-L
689
elif key == "l" or key == "D":
543
elif key == u"l" or key == u"D":
690
544
self.toggle_log_display()
692
elif key == "w" or key == "i":
546
elif key == u"w" or key == u"i":
693
547
self.change_log_display()
695
elif key == "?" or key == "f1" or key == "esc":
549
elif key == u"?" or key == u"f1" or key == u"esc":
696
550
if not self.log_visible:
697
551
self.log_visible = True
699
self.log_message_raw(("bold",
703
"l: Log window toggle",
704
"TAB: Switch window",
706
self.log_message_raw(("bold",
712
"s: Start new checker",
553
self.log_message_raw((u"bold",
557
u"l: Log window toggle",
558
u"TAB: Switch window",
560
self.log_message_raw((u"bold",
566
u"s: Start new checker",
719
573
if self.topwidget.get_focus() is self.logbox:
720
574
self.topwidget.set_focus(0)
722
576
self.topwidget.set_focus(self.logbox)
724
#elif (key == "end" or key == "meta >" or key == "G"
578
#elif (key == u"end" or key == u"meta >" or key == u"G"
726
580
# pass # xxx end-of-buffer
727
#elif (key == "home" or key == "meta <" or key == "g"
581
#elif (key == u"home" or key == u"meta <" or key == u"g"
729
583
# pass # xxx beginning-of-buffer
730
#elif key == "ctrl e" or key == "$":
584
#elif key == u"ctrl e" or key == u"$":
731
585
# pass # xxx move-end-of-line
732
#elif key == "ctrl a" or key == "^":
586
#elif key == u"ctrl a" or key == u"^":
733
587
# pass # xxx move-beginning-of-line
734
#elif key == "ctrl b" or key == "meta (" or key == "h":
588
#elif key == u"ctrl b" or key == u"meta (" or key == u"h":
735
589
# pass # xxx left
736
#elif key == "ctrl f" or key == "meta )" or key == "l":
590
#elif key == u"ctrl f" or key == u"meta )" or key == u"l":
737
591
# pass # xxx right
739
593
# pass # scroll up log
741
595
# pass # scroll down log
742
596
elif self.topwidget.selectable():
743
597
self.topwidget.keypress(self.size, key)