/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos-monitor

  • Committer: teddy at bsnet
  • Date: 2011-02-11 18:54:14 UTC
  • mto: (237.7.13 mandos)
  • mto: This revision was merged to the branch mainline in revision 282.
  • Revision ID: teddy@fukt.bsnet.se-20110211185414-cjmw3hppv9i3h9wh
* mandos-monitor: Use only unicode string literals.
  (MandosClientWidget.rows, MandosClientWidget.render,
  MandosClientWidget.keypress, ConstrainedListBox.keypress) Don't use
                                                            argument
                                                            tuple
                                                            unpacking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
# -*- mode: python; coding: utf-8 -*-
 
3
 
4
# Mandos Monitor - Control and monitor the Mandos server
 
5
 
6
# Copyright © 2009,2010 Teddy Hogeborn
 
7
# Copyright © 2009,2010 Björn Påhlsson
 
8
 
9
# This program is free software: you can redistribute it and/or modify
 
10
# it under the terms of the GNU General Public License as published by
 
11
# the Free Software Foundation, either version 3 of the License, or
 
12
# (at your option) any later version.
 
13
#
 
14
#     This program is distributed in the hope that it will be useful,
 
15
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
#     GNU General Public License for more details.
 
18
 
19
# You should have received a copy of the GNU General Public License
 
20
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 
22
# Contact the authors at <mandos@fukt.bsnet.se>.
 
23
3
24
 
4
25
from __future__ import division, absolute_import, with_statement
5
26
 
24
45
locale.setlocale(locale.LC_ALL, u'')
25
46
 
26
47
import logging
27
 
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
 
48
logging.getLogger(u'dbus.proxies').setLevel(logging.CRITICAL)
28
49
 
29
50
# Some useful constants
30
 
domain = 'se.bsnet.fukt'
31
 
server_interface = domain + '.Mandos'
32
 
client_interface = domain + '.Mandos.Client'
33
 
version = "1.0.15"
 
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"
34
55
 
35
56
# Always run in monochrome mode
36
57
urwid.curses_display.curses.has_colors = lambda : False
102
123
        self.logger = logger
103
124
        
104
125
        self._update_timer_callback_tag = None
 
126
        self._update_timer_callback_lock = 0
105
127
        self.last_checker_failed = False
106
128
        
107
129
        # The widget shown normally
113
135
            *args, **kwargs)
114
136
        self.update()
115
137
        self.opened = False
 
138
        
 
139
        last_checked_ok = isoformat_to_datetime(self.properties
 
140
                                                [u"LastCheckedOK"])
 
141
        if last_checked_ok is None:
 
142
            self.last_checker_failed = True
 
143
        else:
 
144
            self.last_checker_failed = ((datetime.datetime.utcnow()
 
145
                                         - last_checked_ok)
 
146
                                        > datetime.timedelta
 
147
                                        (milliseconds=
 
148
                                         self.properties
 
149
                                         [u"Interval"]))
 
150
        
 
151
        if self.last_checker_failed:
 
152
            self.using_timer(True)
 
153
        
 
154
        if self.need_approval:
 
155
            self.using_timer(True)
 
156
        
116
157
        self.proxy.connect_to_signal(u"CheckerCompleted",
117
158
                                     self.checker_completed,
118
159
                                     client_interface,
133
174
                                     self.rejected,
134
175
                                     client_interface,
135
176
                                     byte_arrays=True)
136
 
        last_checked_ok = isoformat_to_datetime(self.properties
137
 
                                                [u"LastCheckedOK"])
138
 
        if last_checked_ok is None:
139
 
            self.last_checker_failed = True
 
177
    
 
178
    def property_changed(self, property=None, value=None):
 
179
        super(self, MandosClientWidget).property_changed(property,
 
180
                                                         value)
 
181
        if property == u"ApprovalPending":
 
182
            using_timer(bool(value))
 
183
        
 
184
    def using_timer(self, flag):
 
185
        """Call this method with True or False when timer should be
 
186
        activated or deactivated.
 
187
        """
 
188
        old = self._update_timer_callback_lock
 
189
        if flag:
 
190
            self._update_timer_callback_lock += 1
140
191
        else:
141
 
            self.last_checker_failed = ((datetime.datetime.utcnow()
142
 
                                         - last_checked_ok)
143
 
                                        > datetime.timedelta
144
 
                                        (milliseconds=
145
 
                                         self.properties
146
 
                                         [u"Interval"]))
147
 
        if self.last_checker_failed:
 
192
            self._update_timer_callback_lock -= 1
 
193
        if old == 0 and self._update_timer_callback_lock:
148
194
            self._update_timer_callback_tag = (gobject.timeout_add
149
195
                                               (1000,
150
196
                                                self.update_timer))
 
197
        elif old and self._update_timer_callback_lock == 0:
 
198
            gobject.source_remove(self._update_timer_callback_tag)
 
199
            self._update_timer_callback_tag = None
151
200
    
152
201
    def checker_completed(self, exitstatus, condition, command):
153
202
        if exitstatus == 0:
154
203
            if self.last_checker_failed:
155
204
                self.last_checker_failed = False
156
 
                gobject.source_remove(self._update_timer_callback_tag)
157
 
                self._update_timer_callback_tag = None
 
205
                self.using_timer(False)
158
206
            #self.logger(u'Checker for client %s (command "%s")'
159
207
            #            u' was successful'
160
208
            #            % (self.properties[u"Name"], command))
163
211
        # Checker failed
164
212
        if not self.last_checker_failed:
165
213
            self.last_checker_failed = True
166
 
            self._update_timer_callback_tag = (gobject.timeout_add
167
 
                                               (1000,
168
 
                                                self.update_timer))
 
214
            self.using_timer(True)
169
215
        if os.WIFEXITED(condition):
170
216
            self.logger(u'Checker for client %s (command "%s")'
171
217
                        u' failed with exit code %s'
202
248
            message = u'Client %s will get its secret in %s seconds'
203
249
        self.logger(message
204
250
                    % (self.properties[u"Name"], timeout/1000))
 
251
        self.using_timer(True)
205
252
    
206
253
    def rejected(self, reason):
207
254
        self.logger(u'Client %s was rejected; reason: %s'
212
259
        This overrides the method from urwid.FlowWidget."""
213
260
        return True
214
261
    
215
 
    def rows(self, (maxcol,), focus=False):
 
262
    def rows(self, maxcolrow, focus=False):
216
263
        """How many rows this widget will occupy might depend on
217
264
        whether we have focus or not.
218
265
        This overrides the method from urwid.FlowWidget"""
219
 
        return self.current_widget(focus).rows((maxcol,), focus=focus)
 
266
        return self.current_widget(focus).rows(maxcolrow, focus=focus)
220
267
    
221
268
    def current_widget(self, focus=False):
222
269
        if focus or self.opened:
242
289
        if not self.properties[u"Enabled"]:
243
290
            message = u"DISABLED"
244
291
        elif self.properties[u"ApprovalPending"]:
 
292
            timeout = datetime.timedelta(milliseconds
 
293
                                         = self.properties
 
294
                                         [u"ApprovalDelay"])
 
295
            last_approval_request = isoformat_to_datetime(
 
296
                self.properties[u"LastApprovalRequest"])
 
297
            if last_approval_request is not None:
 
298
                timer = timeout - (datetime.datetime.utcnow()
 
299
                                   - last_approval_request)
 
300
            else:
 
301
                timer = datetime.timedelta()
245
302
            if self.properties[u"ApprovedByDefault"]:
246
 
                message = u"Connection established to client. (d)eny?"
 
303
                message = u"Approval in %s. (d)eny?"
247
304
            else:
248
 
                message = u"Seeks approval to send secret. (a)pprove?"
 
305
                message = u"Denial in %s. (a)pprove?"
 
306
            message = message % unicode(timer).rsplit(".", 1)[0]
249
307
        elif self.last_checker_failed:
250
308
            timeout = datetime.timedelta(milliseconds
251
309
                                         = self.properties
256
314
                    self.properties[u"LastEnabled"]))
257
315
            timer = timeout - (datetime.datetime.utcnow() - last_ok)
258
316
            message = (u'A checker has failed! Time until client'
259
 
                       u' gets diabled: %s'
 
317
                       u' gets disabled: %s'
260
318
                           % unicode(timer).rsplit(".", 1)[0])
261
319
        else:
262
320
            message = u"enabled"
263
 
        self._text = "%s%s" % (base, message)
 
321
        self._text = u"%s%s" % (base, message)
264
322
            
265
323
        if not urwid.supports_unicode():
266
 
            self._text = self._text.encode("ascii", "replace")
 
324
            self._text = self._text.encode(u"ascii", u"replace")
267
325
        textlist = [(u"normal", self._text)]
268
326
        self._text_widget.set_text(textlist)
269
327
        self._focus_text_widget.set_text([(with_standout[text[0]],
273
331
                                          for text in textlist])
274
332
        self._widget = self._text_widget
275
333
        self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
276
 
                                            "standout")
 
334
                                            u"standout")
277
335
        # Run update hook, if any
278
336
        if self.update_hook is not None:
279
337
            self.update_hook()
290
348
        if self.delete_hook is not None:
291
349
            self.delete_hook(self)
292
350
    
293
 
    def render(self, (maxcol,), focus=False):
 
351
    def render(self, maxcolrow, focus=False):
294
352
        """Render differently if we have focus.
295
353
        This overrides the method from urwid.FlowWidget"""
296
 
        return self.current_widget(focus).render((maxcol,),
 
354
        return self.current_widget(focus).render(maxcolrow,
297
355
                                                 focus=focus)
298
356
    
299
 
    def keypress(self, (maxcol,), key):
 
357
    def keypress(self, maxcolrow, key):
300
358
        """Handle keys.
301
359
        This overrides the method from urwid.FlowWidget"""
302
360
        if key == u"+":
309
367
        elif key == u"d":
310
368
            self.proxy.Approve(dbus.Boolean(False, variant_level=1),
311
369
                                  dbus_interface = client_interface)
312
 
        elif key == u"r" or key == u"_" or key == u"ctrl k":
 
370
        elif key == u"R" or key == u"_" or key == u"ctrl k":
313
371
            self.server_proxy_object.RemoveClient(self.proxy
314
372
                                                  .object_path)
315
373
        elif key == u"s":
345
403
    "down" key presses, thus not allowing any containing widgets to
346
404
    use them as an excuse to shift focus away from this widget.
347
405
    """
348
 
    def keypress(self, (maxcol, maxrow), key):
349
 
        ret = super(ConstrainedListBox, self).keypress((maxcol,
350
 
                                                        maxrow), key)
 
406
    def keypress(self, maxcolrow, key):
 
407
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
351
408
        if ret in (u"up", u"down"):
352
409
            return
353
410
        return ret
628
685
                                      .join((u"Clients:",
629
686
                                             u"+: Enable",
630
687
                                             u"-: Disable",
631
 
                                             u"r: Remove",
 
688
                                             u"R: Remove",
632
689
                                             u"s: Start new checker",
633
690
                                             u"S: Stop checker",
634
691
                                             u"C: Checker OK",