remove sys append by default, add gpl
[samba-gtk.git] / sambagtk / registry.py
1 # Samba GTK+ frontends
2 #
3 # Copyright (C) 2010 Sergio Martins <sergio97@gmail.com>
4 # Copyright (C) 2011 Jelmer Vernooij <jelmer@samba.org>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 """Registry-related dialogs."""
21
22 import gtk
23 import gobject
24 import pango
25
26 import os
27 import string
28 import sys
29
30 from samba.dcerpc import misc
31
32 class RegistryValue(object):
33
34     def __init__(self, name, type, data, parent):
35         self.name = name
36         self.type = type
37         self.data = data
38         self.parent = parent
39
40     def get_absolute_path(self):
41         if self.parent is None:
42             return self.name
43         else:
44             return self.parent.get_absolute_path() + "\\" + self.name
45
46     def get_data_string(self):
47         interpreted_data = self.get_interpreted_data()
48
49         if interpreted_data is None or len(self.data) == 0:
50             return "(value not set)"
51         elif self.type in (misc.REG_SZ, misc.REG_EXPAND_SZ):
52             return interpreted_data
53         elif self.type == misc.REG_BINARY:
54             return "".join(["%02X" % byte for byte in interpreted_data])
55         elif self.type == misc.REG_DWORD:
56             return "0x%08X" % (interpreted_data)
57         elif self.type == misc.REG_DWORD_BIG_ENDIAN:
58             return "0x%08X" % (interpreted_data)
59         elif self.type == misc.REG_MULTI_SZ:
60             return " ".join(interpreted_data)
61         elif self.type == misc.REG_QWORD:
62             return "0x%016X" % (interpreted_data)
63         else:
64             return str(interpreted_data)
65
66     def get_interpreted_data(self):
67         if self.data is None:
68             return None
69
70         if self.type in (misc.REG_SZ, misc.REG_EXPAND_SZ):
71             result = ""
72
73             index = 0
74             while (index + 1 < len(self.data)): #The +1 ensures that the whole char is valid. Corrupt keys can otherwise cause exceptions
75                 word = ((self.data[index + 1] << 8) + self.data[index])
76                 if word != 0:
77                     result += unichr(word)
78                 index += 2
79
80             return result
81         elif self.type == misc.REG_BINARY:
82             return self.data
83         elif self.type == misc.REG_DWORD:
84             result = 0L
85
86             if len(self.data) < 4:
87                 return 0L
88
89             for i in xrange(4):
90                 result = (result << 8) + self.data[3 - i]
91
92             return result
93         elif self.type == misc.REG_DWORD_BIG_ENDIAN:
94             result = 0L
95
96             if len(self.data) < 4:
97                 return 0L
98
99             for i in xrange(4):
100                 result = (result << 8) + self.data[i]
101
102             return result
103         elif self.type == misc.REG_MULTI_SZ:
104             result = []
105             string = ""
106
107             if len(self.data) == 0:
108                 return []
109
110             index = 0
111             while (index < len(self.data)):
112                 word = ((self.data[index + 1] << 8) + self.data[index])
113                 if word == 0:
114                     result.append(string)
115                     string = ""
116                 else:
117                     string += unichr(word)
118
119                 index += 2
120
121             result.pop() # remove last systematic empty string
122
123             return result
124         elif self.type == misc.REG_QWORD:
125             result = 0L
126
127             if len(self.data) < 8:
128                 return 0L
129
130             for i in xrange(8):
131                 result = (result << 8) + self.data[7 - i]
132
133             return result
134         else:
135             return self.data
136
137     def set_interpreted_data(self, data):
138         del self.data[:]
139
140         if data is None:
141             self.data = None
142         elif self.type in (misc.REG_SZ, misc.REG_EXPAND_SZ):
143             for uch in data:
144                 word = ord(uch)
145                 self.data.append(int(word & 0x00FF))
146                 self.data.append(int((word >> 8) & 0x00FF))
147         elif self.type == misc.REG_BINARY:
148             self.data = []
149             for elem in data:
150                 self.data.append(int(elem))
151         elif self.type == misc.REG_DWORD:
152             for i in xrange(4):
153                 self.data.append(int(data >> (8 * i) & 0xFF))
154         elif self.type == misc.REG_DWORD_BIG_ENDIAN:
155             for i in xrange(3, -1, -1):
156                 self.data.append(int(data >> (8 * i) & 0xFF))
157         elif self.type == misc.REG_MULTI_SZ:
158             index = 0
159
160             for string in data:
161                 for uch in string:
162                     word = ord(uch)
163                     self.data.append(int(word & 0x00FF))
164                     self.data.append(int((word >> 8) & 0x00FF))
165
166                 self.data.append(0)
167                 self.data.append(0)
168
169             self.data.append(0)
170             self.data.append(0)
171         elif self.type == misc.REG_QWORD:
172             for i in xrange(8):
173                 self.data.append(int(data >> (8 * i) & 0xFF))
174         else:
175             self.data = data
176
177     def list_view_representation(self):
178         return [self.name, RegistryValue.get_type_string(self.type),
179                 self.get_data_string(), self]
180
181     @staticmethod
182     def get_type_string(type):
183         type_strings = {
184             misc.REG_SZ:"String",
185             misc.REG_BINARY:"Binary Data",
186             misc.REG_EXPAND_SZ:"Expandable String",
187             misc.REG_DWORD:"32-bit Number (little endian)",
188             misc.REG_DWORD_BIG_ENDIAN:"32-bit Number (big endian)",
189             misc.REG_MULTI_SZ:"Multi-String",
190             misc.REG_QWORD:"64-bit Number (little endian)"
191             }
192
193         return type_strings[type]
194
195
196 class RegistryKey(object):
197
198     def __init__(self, name, parent):
199         self.name = name
200         self.parent = parent
201         self.handle = None
202
203     def get_absolute_path(self):
204         if self.parent is None:
205             return self.name
206         else:
207             return self.parent.get_absolute_path() + "\\" + self.name
208
209     def get_root_key(self):
210         if self.parent is None:
211             return self
212         else:
213             return self.parent.get_root_key()
214
215     def list_view_representation(self):
216         return [self.name, self]
217
218
219 class RegValueEditDialog(gtk.Dialog):
220
221     def __init__(self, reg_value, type):
222         super(RegValueEditDialog, self).__init__()
223
224         if reg_value is None:
225             self.brand_new = True
226             self.reg_value = RegistryValue("", type, [], None)
227         else:
228             self.brand_new = False
229             self.reg_value = reg_value
230
231         self.disable_signals = False
232         self.ascii_cursor_shift = 0 # because moving the cursor in some functions has no effect, we need to keep this value and apply it at the right time
233         self.hex_cursor_shift = 0
234
235         self.create()
236         self.reg_value_to_values()
237
238     def create(self):
239         self.set_title(["Edit registry value", "New registry value"][self.brand_new])
240         self.set_border_width(5)
241
242         self.icon_registry_number_filename = os.path.join(sys.path[0],
243                 "images", "registry-number.png")
244         self.icon_registry_string_filename = os.path.join(sys.path[0],
245                 "images", "registry-string.png")
246         self.icon_registry_binary_filename = os.path.join(sys.path[0],
247                 "images", "registry-binary.png")
248
249         self.set_resizable(True)
250
251         # value name
252         hbox = gtk.HBox()
253         self.vbox.pack_start(hbox, False, False, 10)
254
255         label = gtk.Label("Value name:")
256         hbox.pack_start(label, False, True, 10)
257
258         self.name_entry = gtk.Entry()
259         self.name_entry.set_activates_default(True)
260         self.name_entry.set_sensitive(self.brand_new)
261         hbox.pack_start(self.name_entry, True, True, 10)
262
263         separator = gtk.HSeparator()
264         self.vbox.pack_start(separator, False, True, 5)
265
266         # data
267         frame = gtk.Frame(" Value data: ")
268         self.vbox.pack_start(frame, True, True, 10)
269
270         self.type_notebook = gtk.Notebook()
271         self.type_notebook.set_border_width(5)
272         self.type_notebook.set_show_tabs(False)
273         self.type_notebook.set_show_border(False)
274         frame.add(self.type_notebook)
275
276         # string type page
277         self.string_data_entry = gtk.Entry()
278         self.string_data_entry.set_activates_default(True)
279         self.type_notebook.append_page(self.string_data_entry)
280
281
282         # binary type page
283         scrolledwindow = gtk.ScrolledWindow(None, None)
284         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
285         scrolledwindow.set_shadow_type(gtk.SHADOW_NONE)
286         self.type_notebook.append_page(scrolledwindow)
287
288         hbox = gtk.HBox()
289         scrolledwindow.add_with_viewport(hbox)
290
291         self.binary_data_addr_text_view = gtk.TextView()
292         self.binary_data_addr_text_view.set_wrap_mode(gtk.WRAP_WORD)
293         self.binary_data_addr_text_view.set_editable(False)
294         self.binary_data_addr_text_view.modify_font(pango.FontDescription("mono 10"))
295         self.binary_data_addr_text_view.set_size_request(60, -1)
296         hbox.pack_start(self.binary_data_addr_text_view, False, False, 0)
297
298         self.binary_data_hex_text_view = gtk.TextView()
299         self.binary_data_hex_text_view.set_wrap_mode(gtk.WRAP_WORD)
300         self.binary_data_hex_text_view.set_accepts_tab(False)
301         self.binary_data_hex_text_view.modify_font(pango.FontDescription("mono bold 10"))
302         self.binary_data_hex_text_view.set_size_request(275, -1)
303         hbox.pack_start(self.binary_data_hex_text_view, False, False, 0)
304
305         self.binary_data_ascii_text_view = gtk.TextView()
306         self.binary_data_ascii_text_view.set_wrap_mode(gtk.WRAP_CHAR)
307         #self.binary_data_ascii_text_view.set_editable(False)
308         self.binary_data_ascii_text_view.modify_font(pango.FontDescription("mono 10"))
309         self.binary_data_ascii_text_view.set_accepts_tab(False)
310         self.binary_data_ascii_text_view.set_size_request(100, -1)
311         hbox.pack_start(self.binary_data_ascii_text_view, False, False, 0)
312
313
314         # number type page
315         hbox = gtk.HBox()
316         self.type_notebook.append_page(hbox)
317
318         self.number_data_entry = gtk.Entry()
319         self.number_data_entry.set_activates_default(True)
320         hbox.pack_start(self.number_data_entry, True, True, 5)
321
322         self.number_data_dec_radio = gtk.RadioButton(None, "Decimal")
323         hbox.pack_start(self.number_data_dec_radio, False, True, 5)
324
325         self.number_data_hex_radio = gtk.RadioButton(self.number_data_dec_radio, "Hexadecimal")
326         hbox.pack_start(self.number_data_hex_radio, False, True, 5)
327
328         self.number_data_hex_radio.set_active(True)
329
330         # multi-string type page
331         scrolledwindow = gtk.ScrolledWindow(None, None)
332         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
333         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
334         self.type_notebook.append_page(scrolledwindow)
335
336         self.multi_string_data_text_view = gtk.TextView()
337         self.multi_string_data_text_view.set_wrap_mode(gtk.WRAP_NONE)
338         scrolledwindow.add(self.multi_string_data_text_view)
339
340         # dialog buttons
341         self.action_area.set_layout(gtk.BUTTONBOX_END)
342
343         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
344         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
345         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
346
347         self.apply_button = gtk.Button("Apply", gtk.STOCK_APPLY)
348         self.apply_button.set_flags(gtk.CAN_DEFAULT)
349         self.apply_button.set_sensitive(not self.brand_new) # disabled for new task
350         self.add_action_widget(self.apply_button, gtk.RESPONSE_APPLY)
351
352         self.ok_button = gtk.Button("OK", gtk.STOCK_OK)
353         self.ok_button.set_flags(gtk.CAN_DEFAULT)
354         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
355
356         self.set_default_response(gtk.RESPONSE_OK)
357
358         # signals/events
359         self.binary_data_hex_text_view.get_buffer().connect("changed", self.on_binary_data_hex_text_view_buffer_changed)
360         self.binary_data_hex_text_view.get_buffer().connect("insert-text", self.on_binary_data_hex_text_view_buffer_insert_text)
361         self.binary_data_hex_text_view.get_buffer().connect("delete-range", self.on_binary_data_hex_text_view_buffer_delete_range)
362
363         # Ascii text view callbacks. This view requires special attention to
364         # facilitate the crazy editing it needs to do
365         self.binary_data_ascii_text_view.get_buffer().connect("insert-text", self.on_binary_data_ascii_text_view_buffer_insert_text) #manually handles inserting text
366         self.binary_data_ascii_text_view.get_buffer().connect("delete-range", self.on_binary_data_ascii_text_view_buffer_delete_range) #manually handles deleting text
367         self.binary_data_ascii_text_view.get_buffer().connect("changed", self.on_binary_data_ascii_text_view_buffer_changed)
368         self.binary_data_ascii_text_view.connect("move-cursor", self.on_binary_data_ascii_text_view_move_cursor)
369
370         self.number_data_dec_radio.connect("toggled", self.on_number_data_dec_radio_toggled)
371         self.number_data_hex_radio.connect("toggled", self.on_number_data_hex_radio_toggled)
372         self.number_data_entry.connect("changed", self.on_number_data_entry_changed)
373
374     def check_for_problems(self):
375         if len(self.name_entry.get_text().strip()) == 0:
376             return "Please specify a name."
377
378         if self.reg_value.type in [misc.REG_DWORD, misc.REG_DWORD_BIG_ENDIAN, misc.REG_QWORD]:
379             number_str = self.number_data_entry.get_text()
380             if len(number_str) == 0:
381                 return "Please enter a number."
382
383             if self.number_data_dec_radio.get_active():
384                 try:
385                     number = string.atoi(number_str, 10)
386                 except Exception:
387                     return "Please enter a valid decimal number."
388                 else:
389                     number_str_hex = "%X" % number
390
391                     if self.reg_value.type in [misc.REG_DWORD, misc.REG_DWORD_BIG_ENDIAN]:
392                         max_hex_len = 8
393                     else:
394                         max_hex_len = 16
395
396                     if len(number_str_hex) > max_hex_len:
397                         return "Please enter a smaller decimal number."
398         return None
399
400     def reg_value_to_values(self):
401         if self.reg_value is None:
402             raise Exception("registry value not set")
403
404         self.name_entry.set_text(self.reg_value.name)
405
406         if self.reg_value.type in [misc.REG_SZ, misc.REG_EXPAND_SZ]:
407             self.set_icon_from_file(self.icon_registry_string_filename)
408             self.set_size_request(430, 200)
409
410             self.string_data_entry.set_text(self.reg_value.get_interpreted_data())
411         elif self.reg_value.type == misc.REG_BINARY:
412             self.set_icon_from_file(self.icon_registry_binary_filename)
413             self.set_size_request(483, 400) #extra few pixels for the scroll bar
414
415             self.binary_data_hex_text_view.get_buffer().set_text(RegValueEditDialog.byte_array_to_hex(self.reg_value.get_interpreted_data(), 8))
416             #self.on_binary_data_hex_text_view_buffer_changed(None) #this is already called with the statement above
417
418         elif self.reg_value.type in [misc.REG_DWORD, misc.REG_DWORD_BIG_ENDIAN, misc.REG_QWORD]:
419             self.set_icon_from_file(self.icon_registry_number_filename)
420             self.set_size_request(430, 200)
421
422             if self.reg_value.type == misc.REG_QWORD:
423                 self.number_data_entry.set_text("%016X" % self.reg_value.get_interpreted_data())
424             else:
425                 self.number_data_entry.set_text("%08X" % self.reg_value.get_interpreted_data())
426
427         elif self.reg_value.type == misc.REG_MULTI_SZ:
428             self.set_icon_from_file(self.icon_registry_string_filename)
429             self.set_size_request(430, 400)
430
431             text = ""
432             for line in self.reg_value.get_interpreted_data():
433                 text += line + "\n"
434
435             self.multi_string_data_text_view.get_buffer().set_text(text)
436
437     def values_to_reg_value(self):
438         if self.reg_value is None:
439             raise Exception("registry value not set")
440
441         self.reg_value.name = self.name_entry.get_text()
442
443         if self.reg_value.type in [misc.REG_SZ, misc.REG_EXPAND_SZ]:
444             self.reg_value.set_interpreted_data(self.string_data_entry.get_text())
445         elif self.reg_value.type == misc.REG_BINARY:
446             buffer = self.binary_data_hex_text_view.get_buffer()
447             text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
448             self.reg_value.set_interpreted_data(RegValueEditDialog.hex_to_byte_array(text))
449         elif self.reg_value.type in [misc.REG_DWORD, misc.REG_DWORD_BIG_ENDIAN, misc.REG_QWORD]:
450             if self.number_data_dec_radio.get_active():
451                 self.reg_value.set_interpreted_data(string.atoi(self.number_data_entry.get_text(), 10))
452             else:
453                 self.reg_value.set_interpreted_data(string.atoi(self.number_data_entry.get_text(), 0x10))
454
455         elif self.reg_value.type == misc.REG_MULTI_SZ:
456             lines = []
457             line = ""
458
459             buffer = self.multi_string_data_text_view.get_buffer()
460             for ch in buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()):
461                 if ch != "\n":
462                     line += ch
463                 else:
464                     lines.append(line)
465                     line = ""
466
467             if len(line) > 0:
468                 lines.append(line)
469
470             self.reg_value.set_interpreted_data(lines)
471
472     def update_type_page_after_show(self):
473         if self.reg_value.type == misc.REG_SZ:
474             self.type_notebook.set_current_page(0)
475             self.string_data_entry.grab_focus()
476         if self.reg_value.type == misc.REG_EXPAND_SZ:
477             self.type_notebook.set_current_page(0)
478             self.string_data_entry.grab_focus()
479         if self.reg_value.type == misc.REG_BINARY:
480             self.type_notebook.set_current_page(1)
481             self.binary_data_hex_text_view.grab_focus()
482         if self.reg_value.type == misc.REG_DWORD:
483             self.type_notebook.set_current_page(2)
484             self.number_data_entry.grab_focus()
485         if self.reg_value.type == misc.REG_DWORD_BIG_ENDIAN:
486             self.type_notebook.set_current_page(2)
487             self.number_data_entry.grab_focus()
488         if self.reg_value.type == misc.REG_MULTI_SZ:
489             self.type_notebook.set_current_page(3)
490             self.multi_string_data_text_view.grab_focus()
491         if self.reg_value.type == misc.REG_QWORD:
492             self.type_notebook.set_current_page(2)
493             self.number_data_entry.grab_focus()
494         if self.brand_new:
495             self.name_entry.grab_focus()
496
497     def on_binary_data_hex_text_view_buffer_changed(self, widget):
498         if self.disable_signals:
499             return
500         self.disable_signals = True
501
502         hex_buffer = self.binary_data_hex_text_view.get_buffer() #this is the same as 'widget'
503         ascii_buffer = self.binary_data_ascii_text_view.get_buffer()
504         addr_buffer = self.binary_data_addr_text_view.get_buffer()
505
506         insert_iter = hex_buffer.get_iter_at_mark(hex_buffer.get_insert())
507         insert_char_offs = insert_iter.get_offset()
508         #print "cursor at:", insert_char_offs
509
510         text = hex_buffer.get_text(hex_buffer.get_start_iter(), hex_buffer.get_end_iter())
511         before_len = len(text)
512         text = RegValueEditDialog.check_hex_string(text).strip()
513         after_len = len(text)
514
515         hex_buffer.set_text(text)
516         ascii_buffer.set_text(RegValueEditDialog.hex_to_ascii(text))
517         addr_buffer.set_text(RegValueEditDialog.hex_to_addr(text))
518
519         #print "cursor now at:", insert_char_offs + (after_len - before_len)
520         hex_buffer.place_cursor(hex_buffer.get_iter_at_offset(insert_char_offs + self.hex_cursor_shift))
521         self.hex_cursor_shift = 0
522         self.disable_signals = False
523
524     def on_binary_data_hex_text_view_buffer_insert_text(self, widget, iter, text, length):
525         """callback for text inserted into the hex field. \nThe purpose of this function is only to update the cursor"""
526         if self.disable_signals:
527             return
528         self.disable_signals = True
529
530         offset = iter.get_offset()
531         whole_text = widget.get_text(widget.get_start_iter(), widget.get_end_iter())
532
533         #construct the final text
534         final_text = ""
535         for i in range(offset):
536             final_text += whole_text[i]
537         for ch in text:
538             final_text += ch
539         for i in range(offset, len(whole_text)):
540             final_text += whole_text[i]
541         final_text = self.check_hex_string(final_text)
542
543         #here we properly adjust the cursor
544         count = 0
545         limit = len(final_text) #it could be that the user typed an invalid character, so we'll play it safe
546         for i in range(offset, offset + length + count + 1): #go through the inserted characters and see if any have been replaced by white space
547             if (i < limit) and ((final_text[i] == ' ') or (final_text[i] == '\n')):
548                 count += 1
549         self.hex_cursor_shift = count
550
551         self.disable_signals = False
552
553     def on_binary_data_hex_text_view_buffer_delete_range(self, widget, start, end):
554         """callback for text inserted into the hex field. \nThe purpose of this function is only to update the cursor"""
555         if (self.disable_signals):
556             return
557         self.disable_signals = True
558
559         text = widget.get_text(start, end)
560         if (text == ' ') or (text == '\n'):
561             #if the user deleted whitespace, they probably wanted to delete whatever was before it
562             new_start = widget.get_iter_at_offset(start.get_offset() - 1)
563             #widget.delete(new_start, start) #if this worked as expected, programming would be too easy :P
564
565         self.disable_signals = False
566
567     def on_binary_data_ascii_text_view_buffer_changed(self, widget):
568         """this function formats the text in the ascii field whenever it's changed"""
569         if (self.disable_signals):
570             return
571
572         self.disable_signals = True
573         if widget is None:
574             widget = self.binary_data_ascii_text_view.get_buffer()
575
576         #stuff we need to move the cursor properly later
577         cursor_iter = widget.get_iter_at_mark(widget.get_insert()) #insert means cursor, or "the insertion point" as gtk calls it
578         cursor_offset = cursor_iter.get_offset()
579
580         text = widget.get_text(widget.get_start_iter(), widget.get_end_iter())
581         text = self.check_ascii_string(text)
582         widget.set_text(text)
583
584         #Calling this function below will translate the hex back into our ascii box, making errors easier to spot
585         self.disable_signals = False
586         self.on_binary_data_hex_text_view_buffer_changed(None)
587         self.disable_signals = True
588
589         #now that we've overwritten everything in the textbuffer, we have to put the cursor back in the same spot
590         widget.place_cursor(widget.get_iter_at_offset(cursor_offset + self.ascii_cursor_shift))
591         self.ascii_cursor_shift = 0
592
593         self.disable_signals = False
594
595     def on_binary_data_ascii_text_view_buffer_insert_text(self, widget, iter, text, length):
596         if (self.disable_signals):
597             return
598         self.disable_signals = True
599         if widget is None:
600             widget = self.binary_data_ascii_text_view.get_buffer()
601
602         #get stuff that we need
603         offset = iter.get_offset()
604         inclusive_text = widget.get_text(widget.get_start_iter(), iter)
605         hex_pos = int(iter.get_offset() * 3) #because each ascii character is 2 hex characters, plus a space
606         hex_pos -= inclusive_text.count('\n') * 2 #because '\n' counts as a character, but it doesn't take up 3 spaces in the hex string.
607         hex_buffer = self.binary_data_hex_text_view.get_buffer()
608         addr_buffer = self.binary_data_addr_text_view.get_buffer()
609         hex_text = hex_buffer.get_text(hex_buffer.get_start_iter(), hex_buffer.get_end_iter())
610
611         #insert into hex_text up to the point where the new character was inserted
612         new_hex = ""
613         for ch in hex_text: #this works best because the hex_pos can be greater than len(hex_text) when inserting at the end
614             if len(new_hex) >= hex_pos:
615                 break
616             new_hex += ch
617         #insert the new character(s)
618         for i in range(length):
619             new_hex += "%X" % ((ord(text[i]) >> 4) & 0x0F) #handle the upper 4 bits of the char
620             new_hex += "%X " % (ord(text[i]) & 0x0F)       #handle the lower 4 bits of the char
621         #insert the rest of the old characters into new_hex
622         while hex_pos < len(hex_text):
623             new_hex += hex_text[hex_pos]
624             hex_pos += 1
625         new_hex = self.check_hex_string(new_hex)
626
627         #here we properly adjust the cursor
628         final_text = self.hex_to_ascii(new_hex)
629         count = 0
630         for i in range(offset, offset + length + count): #go through the inserted characters and see if any have been replaced by '\n's
631             if (final_text[i] == '\n'):
632                 count += 1
633         hex_buffer.set_text(new_hex) #set the text
634         self.ascii_cursor_shift = count #tell the on_changed() function to shift the cursor, since it has no effect if we call place_cursor() from here
635         addr_buffer.set_text(self.hex_to_addr(new_hex)) #can't forget to update the address text!
636         self.disable_signals = False
637
638     def on_binary_data_ascii_text_view_buffer_delete_range(self, widget, start, end):
639         if (self.disable_signals):
640             return
641         self.disable_signals = True
642
643         #get stuff that we need
644         text = widget.get_text(start, end)
645         beginning_text = widget.get_text(widget.get_start_iter(), start)
646         inclusive_text = widget.get_text(widget.get_start_iter(), end)
647         hex_buffer = self.binary_data_hex_text_view.get_buffer()
648         addr_buffer = self.binary_data_addr_text_view.get_buffer()
649         hex_text = hex_buffer.get_text(hex_buffer.get_start_iter(), hex_buffer.get_end_iter())
650         new_end_iter = None #this will tell us if any extra characters need to be deleted later
651
652         if text == '\n': #we assume that the user pressed backspace and NOT delete. We don't get any indicator of which key was pressed so without adding another complex function, this is the best we can do
653             new_end_iter = start #so later we can delete from a new start to the current start
654             start = widget.get_iter_at_offset(start.get_offset() - 1) #also delete the character before the '\n'
655
656         #Adjust the values for use in the hex field. this is basically the same as count('\n') + 1
657         hex_start = int(start.get_offset() * 3) #because each ascii character is 2 hex characters, plus a space
658         hex_start -= beginning_text.count('\n') * 2 #because '\n' counts as a character, but it doesn't take up 3 spaces in the hex string.
659         hex_end = int(end.get_offset() * 3)
660         hex_end -= inclusive_text.count('\n') * 2
661
662         new_hex = ""
663         #insert into hex_text up to the point where characters were deleted
664         for i in range(hex_start):
665             new_hex += hex_text[i]
666         #insert the characters after the deleted characters. We simply ignore the deleted characters
667         for i in range(hex_end, len(hex_text)):
668             new_hex += hex_text[i]
669
670         hex_buffer.set_text(RegValueEditDialog.check_hex_string(new_hex)) #set the text
671         addr_buffer.set_text(RegValueEditDialog.hex_to_addr(new_hex)) #can't forget to update the address text!
672
673         if (new_end_iter is not None):
674             widget.delete(start, new_end_iter) #this causes a warning because of bad iterators! Makes no sense
675
676         self.disable_signals = False
677
678     def on_binary_data_ascii_text_view_move_cursor(self, textview, step_size, count, extend_selection):
679         """This function handles cursor movement. For now it only responds to text selection"""
680         print "ext_sel", extend_selection
681         #The following doesn't work... even if extend_selection is true, get_selection_bounds() still returns nothing
682 #        if (not extend_selection) or (self.disable_signals):
683 #            return
684 #        self.disable_signals = True
685 #
686 #        #get stuff we need
687 #        ascii_buffer = textview.get_buffer()
688 #        (start, end) = ascii_buffer.get_selection_bounds() #This function returns 2 iterators
689 #        hex_buffer = self.binary_data_hex_text_view.get_buffer()
690 #
691 #        hex_start = int(start.get_offset() * 3) #because each ascii character is 2 hex characters, plus a space
692 #        hex_start -= (hex_start/25) * 2 #because '\n' counts as a character, but it doesn't take up 3 spaces in the hex string.
693 #        hex_end = int(end.get_offset() * 3)
694 #        hex_end -= (hex_end/25) * 2
695 #        hex_buffer.select_range(hex_buffer.get_iter_at_offset(hex_start), hex_buffer.get_iter_at_offset(hex_end))
696 #
697 #        self.disable_signals = False
698
699     def on_number_data_hex_radio_toggled(self, widget):
700         if (not widget.get_active()):
701             return
702
703         if (self.reg_value.type == misc.REG_QWORD):
704             digits = 16
705         else:
706             digits = 8
707
708         number_str = self.number_data_entry.get_text()
709         if (len(number_str) == 0):
710             number_str = "0"
711
712         number = string.atoi(number_str, 10)
713
714         format = "%0" + str(digits) + "X"
715
716         self.number_data_entry.set_text(format % number)
717
718     def on_number_data_dec_radio_toggled(self, widget):
719         if (not widget.get_active()):
720             return
721
722         if (self.reg_value.type == misc.REG_QWORD):
723             digits = 16
724         else:
725             digits = 8
726
727         number_str = self.number_data_entry.get_text()
728         if (len(number_str) == 0):
729             number_str = "0"
730
731         number = string.atoi(number_str, 0x10)
732
733         format = "%0" + str(digits) + "d"
734
735         self.number_data_entry.set_text(format % number)
736
737     def on_number_data_entry_changed(self, widget):
738         old_text = self.number_data_entry.get_text()
739
740         if (self.reg_value.type in [misc.REG_DWORD, misc.REG_DWORD_BIG_ENDIAN]):
741             max_len = 8
742         else:
743             max_len = 16
744
745         new_text = ""
746         if (self.number_data_hex_radio.get_active()):
747             for ch in old_text:
748                 if (ch in string.hexdigits):
749                     new_text += ch
750             if (len(new_text) > max_len):
751                 new_text = new_text[:max_len]
752
753         else:
754             for ch in old_text:
755                 if (ch in string.digits):
756                     new_text += ch
757
758         self.number_data_entry.set_text(new_text)
759
760
761     @staticmethod
762     def remove_string_white_space(str):
763         return string.join(str.split(), "")
764
765     @staticmethod
766     def check_hex_string(old_string, line_length=8, remove_orphaned = False):
767         new_string = ""
768         length = 0
769         insert_space = False
770         for ch in old_string:
771             if (ch in string.hexdigits):
772                 new_string += string.upper(ch)
773                 if (insert_space):
774                     new_string += " "
775                     length += 1
776                 insert_space = not insert_space
777
778             if (length >= line_length):
779                 new_string += "\n"
780                 length = 0
781
782         if (insert_space and remove_orphaned):
783             new_string = new_string.strip()[:len(new_string) - 1]
784
785         return new_string
786
787     @staticmethod
788     def check_ascii_string(string, line_length=8):
789         new_string = ""
790         digits = ""
791         length = 0
792         #insert a '\n' every line_length characters.
793         for ch in string:
794             if ch != '\n': #ignore carrage returns alreadys present
795                 new_string += ch
796                 length += 1
797                 if (length >= line_length):
798                     new_string += "\n"
799                     length = 0
800
801         return new_string.strip()
802
803     @staticmethod
804     def hex_to_ascii(hex_string, line_length=8):
805         ascii_string = ""
806
807         digits = ""
808         length = 0
809         for ch in hex_string:
810             if (ch in string.hexdigits):
811                 digits += ch
812
813             if (len(digits) >= 2):
814                 new_chr = chr(string.atol(digits, 0x10))
815                 if (new_chr in (string.punctuation + string.digits + string.ascii_letters + ' ')): #We don't just use string.printables because that inclues '\n' and '\r' which we don't want to put into the ascii box
816                     ascii_string += new_chr
817                 else:
818                     ascii_string += "."
819                 length += 1
820                 digits = ""
821
822             if (length >= line_length):
823                 ascii_string += "\n"
824                 length = 0
825
826         return ascii_string
827
828     @staticmethod
829     def hex_to_addr(old_string, line_length=8):
830         new_string = ""
831
832         digits = ""
833         length = 0
834         addr = 0
835         for ch in old_string:
836             if (ch in string.hexdigits):
837                 digits += ch
838
839             if (len(digits) >= 2):
840
841                 if (length % line_length) == 0:
842                     new_string += "%04X\n" % addr
843                     addr += line_length
844
845                 length += 1
846                 digits = ""
847
848         return new_string
849
850     @staticmethod
851     def byte_array_to_hex(array, line_length=8):
852         new_string = ""
853
854         for byte in array:
855             new_string += "%02x" % byte
856
857         return RegValueEditDialog.check_hex_string(new_string, line_length, False)
858
859     @staticmethod
860     def hex_to_byte_array(hex_string):
861         array = []
862
863         digits = ""
864         for ch in hex_string:
865             if (ch in string.hexdigits):
866                 digits += ch
867
868             if (len(digits) >= 2):
869                 byte = string.atol(digits, 0x10)
870                 array.append(byte)
871                 digits = ""
872
873         return array
874
875
876 class RegKeyEditDialog(gtk.Dialog):
877
878     def __init__(self, reg_key):
879         super(RegKeyEditDialog, self).__init__()
880
881         if (reg_key is None):
882             self.brand_new = True
883             self.reg_key = RegistryKey("", None)
884
885         else:
886             self.brand_new = False
887             self.reg_key = reg_key
888
889         self.create()
890         self.reg_key_to_values()
891
892     def create(self):
893         self.set_title(["Edit registry key", "New registry key"][self.brand_new])
894         self.set_border_width(5)
895
896         self.icon_registry_filename = os.path.join(sys.path[0], "images", "registry.png")
897         self.set_icon_from_file(self.icon_registry_filename)
898
899         self.set_resizable(False)
900
901
902         # value name
903
904         hbox = gtk.HBox()
905         self.vbox.pack_start(hbox, False, False, 10)
906
907         label = gtk.Label("Key name:")
908         hbox.pack_start(label, False, True, 10)
909
910         self.name_entry = gtk.Entry()
911         self.name_entry.set_activates_default(True)
912         hbox.pack_start(self.name_entry, True, True, 10)
913
914
915         # dialog buttons
916
917         self.action_area.set_layout(gtk.BUTTONBOX_END)
918
919         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
920         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
921         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
922
923         self.apply_button = gtk.Button("Apply", gtk.STOCK_APPLY)
924         self.apply_button.set_flags(gtk.CAN_DEFAULT)
925         self.apply_button.set_sensitive(not self.brand_new) # disabled for new task
926         self.add_action_widget(self.apply_button, gtk.RESPONSE_APPLY)
927
928         self.ok_button = gtk.Button("OK", gtk.STOCK_OK)
929         self.ok_button.set_flags(gtk.CAN_DEFAULT)
930         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
931
932         self.set_default_response(gtk.RESPONSE_OK)
933
934
935         # signals/events
936
937     def check_for_problems(self):
938         if (len(self.name_entry.get_text().strip()) == 0):
939             return "Please specify a name."
940
941         return None
942
943     def reg_key_to_values(self):
944         if (self.reg_key is None):
945             raise Exception("registry key not set")
946
947         self.name_entry.set_text(self.reg_key.name)
948
949     def values_to_reg_key(self):
950         if (self.reg_key is None):
951             raise Exception("registry key not set")
952
953         self.reg_key.name = self.name_entry.get_text()
954
955
956 class RegRenameDialog(gtk.Dialog):
957
958     def __init__(self, reg_key, reg_value):
959         super(RegRenameDialog, self).__init__()
960
961         self.reg_key = reg_key
962         self.reg_value = reg_value
963
964         self.create()
965         self.reg_to_values()
966
967     def create(self):
968         self.set_title(["Rename registry key", "Rename registry value"][self.reg_value is not None])
969         self.set_border_width(5)
970
971         self.icon_registry_filename = os.path.join(sys.path[0], "images", "registry.png")
972         self.set_icon_from_file(self.icon_registry_filename)
973
974         self.set_resizable(False)
975
976
977         # name
978
979         hbox = gtk.HBox()
980         self.vbox.pack_start(hbox, False, False, 10)
981
982         label = gtk.Label("Name:")
983         hbox.pack_start(label, False, True, 10)
984
985         self.name_entry = gtk.Entry()
986         self.name_entry.set_activates_default(True)
987         hbox.pack_start(self.name_entry, True, True, 10)
988
989
990         # dialog buttons
991
992         self.action_area.set_layout(gtk.BUTTONBOX_END)
993
994         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
995         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
996         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
997
998         self.apply_button = gtk.Button("Apply", gtk.STOCK_APPLY)
999         self.apply_button.set_flags(gtk.CAN_DEFAULT)
1000         self.add_action_widget(self.apply_button, gtk.RESPONSE_APPLY)
1001
1002         self.ok_button = gtk.Button("OK", gtk.STOCK_OK)
1003         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1004         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
1005
1006         self.set_default_response(gtk.RESPONSE_OK)
1007
1008
1009         # signals/events
1010
1011     def check_for_problems(self):
1012         if (len(self.name_entry.get_text().strip()) == 0):
1013             return "Please specify a name."
1014         return None
1015
1016     def reg_to_values(self):
1017         if (self.reg_key is None):
1018             self.name_entry.set_text(self.reg_value.name)
1019         else:
1020             self.name_entry.set_text(self.reg_key.name)
1021
1022     def values_to_reg(self):
1023         if (self.reg_key is None):
1024             self.reg_value.name = self.name_entry.get_text()
1025         else:
1026             self.reg_key.name = self.name_entry.get_text()
1027
1028 class RegSearchDialog(gtk.Dialog):
1029
1030     def __init__(self):
1031         super(RegSearchDialog, self).__init__()
1032
1033         self.warned = False
1034
1035         self.create()
1036
1037     def create(self):
1038         self.set_title("Search the registry")
1039         self.set_border_width(5)
1040
1041         self.icon_registry_filename = os.path.join(sys.path[0], "images", "registry.png")
1042         self.set_icon_from_file(self.icon_registry_filename)
1043
1044         self.set_resizable(False)
1045
1046
1047         # name
1048
1049         hbox = gtk.HBox()
1050         self.vbox.pack_start(hbox, False, False, 10)
1051
1052         label = gtk.Label("Search for: ")
1053         hbox.pack_start(label, False, True, 10)
1054
1055         self.search_entry = gtk.Entry()
1056         self.search_entry.set_activates_default(True)
1057         hbox.pack_start(self.search_entry, True, True, 10)
1058
1059
1060         # options
1061
1062         frame = gtk.Frame("Match:")
1063         self.vbox.pack_start(frame, False, True, 0)
1064
1065         vbox = gtk.VBox()
1066         vbox.set_border_width(4)
1067         frame.add(vbox)
1068
1069         self.check_match_keys = gtk.CheckButton("Keys")
1070         self.check_match_keys.set_active(True)
1071         vbox.pack_start(self.check_match_keys, False, False, 0)
1072         self.check_match_values = gtk.CheckButton("Values")
1073         self.check_match_values.set_active(True)
1074         vbox.pack_start(self.check_match_values, False, False, 0)
1075         self.check_match_data = gtk.CheckButton("Data")
1076         self.check_match_data.set_active(True)
1077         vbox.pack_start(self.check_match_data, False, False, 0)
1078
1079         self.check_match_whole_string = gtk.CheckButton("Match whole string only")
1080         self.vbox.pack_start(self.check_match_whole_string, False, False, 5)
1081
1082
1083         # dialog buttons
1084
1085         self.action_area.set_layout(gtk.BUTTONBOX_END)
1086
1087         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
1088         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
1089         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
1090
1091         self.ok_button = gtk.Button("Search", gtk.STOCK_FIND)
1092         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1093         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
1094
1095         self.set_default_response(gtk.RESPONSE_OK)
1096
1097
1098         # signals/events
1099
1100     def check_for_problems(self):
1101         if self.search_entry.get_text() == "":
1102             return ("You must enter text to search for!", gtk.MESSAGE_ERROR)
1103         elif not self.check_match_data.get_active() and not self.check_match_keys.get_active() and not self.check_match_values.get_active():
1104             return ("You much select at least one of: keys, values, or data to search", gtk.MESSAGE_ERROR)
1105         elif not self.check_match_whole_string.get_active() and not self.warned:
1106             for ch in self.search_entry.get_text():
1107                 if ch in string.punctuation:
1108                     self.warned = True
1109                     return ("Search items should be separated by a space. Punctuation (such as commas) will be considered part of the search string.\n\nPress find again to continue anyways.", gtk.MESSAGE_INFO)
1110
1111         return None
1112
1113 class RegPermissionsDialog(gtk.Dialog):
1114
1115     def __init__(self, users, permissions):
1116         super(RegPermissionsDialog, self).__init__()
1117
1118         self.users = users
1119         self.permissions = permissions
1120
1121         self.create()
1122
1123         if users is not None:
1124             for user in users:
1125                 self.user_store.append((user.username,
1126                                         user,))
1127
1128     def create(self):
1129         self.set_title("Permissions")
1130         self.set_border_width(5)
1131         self.set_resizable(True)
1132         self.set_default_size(380, 480)
1133
1134         self.icon_registry_filename = os.path.join(sys.path[0], "images", "registry.png")
1135         self.set_icon_from_file(self.icon_registry_filename)
1136
1137
1138
1139         # Groups/Users area
1140
1141         vbox = gtk.VBox()
1142         self.vbox.pack_start(vbox, True, True, 10)
1143
1144         label = gtk.Label("Users:")
1145         label.set_alignment(0, 1)
1146         vbox.pack_start(label, False, False, 0)
1147
1148         hpaned = gtk.HPaned()
1149         vbox.pack_start(hpaned, True, True, 0)
1150
1151         scrolledwindow = gtk.ScrolledWindow(None, None)
1152         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1153         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1154         hpaned.add1(scrolledwindow)
1155
1156         self.user_tree_view = gtk.TreeView()
1157         self.user_tree_view.set_headers_visible(False)
1158         scrolledwindow.add(self.user_tree_view)
1159
1160         column = gtk.TreeViewColumn()
1161         column.set_title("User")
1162         column.set_resizable(True)
1163         column.set_fixed_width(200)
1164         column.set_sort_column_id(0)
1165         renderer = gtk.CellRendererText()
1166         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1167         column.pack_start(renderer, True)
1168         self.user_tree_view.append_column(column)
1169         column.add_attribute(renderer, "text", 0)
1170
1171         self.user_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
1172         self.user_tree_view.set_model(self.user_store)
1173
1174         hbox = gtk.HBox()
1175         vbox.pack_start(hbox, False, False, 0)
1176
1177         padding = gtk.HBox()
1178         hbox.pack_start(padding, True, True, 0)
1179
1180         self.add_button = gtk.Button("Add", gtk.STOCK_ADD)
1181         hbox.pack_start(self.add_button, False, False, 2)
1182
1183         self.remove_button = gtk.Button("Remove", gtk.STOCK_REMOVE)
1184         hbox.pack_start(self.remove_button, False, False, 2)
1185
1186
1187
1188         #Permissions area
1189
1190         vbox = gtk.VBox()
1191         self.vbox.pack_start(vbox, True, True, 10)
1192
1193         self.permissions_label = gtk.Label("Permissions for UNKNOWN USER/GROUP:")
1194         self.permissions_label.set_alignment(0, 1)
1195         vbox.pack_start(self.permissions_label, False, False, 0)
1196
1197         hpaned = gtk.HPaned()
1198         vbox.pack_start(hpaned, True, True, 0)
1199
1200         scrolledwindow = gtk.ScrolledWindow(None, None)
1201         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1202         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1203         hpaned.add1(scrolledwindow)
1204
1205         self.permissions_tree_view = gtk.TreeView()
1206         scrolledwindow.add(self.permissions_tree_view)
1207
1208         column = gtk.TreeViewColumn()
1209         column.set_title("Permission")
1210         column.set_resizable(True)
1211         column.set_min_width(160)
1212         column.set_sort_column_id(0)
1213         renderer = gtk.CellRendererText()
1214         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1215         column.pack_start(renderer, True)
1216         self.permissions_tree_view.append_column(column)
1217         column.add_attribute(renderer, "text", 0)
1218
1219         column = gtk.TreeViewColumn()
1220         column.set_title("Allow")
1221         column.set_resizable(False)
1222         column.set_fixed_width(30)
1223         column.set_sort_column_id(1)
1224         renderer = gtk.CellRendererToggle()
1225         column.pack_start(renderer, True)
1226         self.permissions_tree_view.append_column(column)
1227
1228         column = gtk.TreeViewColumn()
1229         column.set_title("Deny")
1230         column.set_resizable(False)
1231         column.set_fixed_width(30)
1232         column.set_sort_column_id(2)
1233         renderer = gtk.CellRendererToggle()
1234         column.pack_start(renderer, True)
1235         self.permissions_tree_view.append_column(column)
1236
1237         self.permissions_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT)
1238         self.permissions_tree_view.set_model(self.permissions_store)
1239
1240         hbox = gtk.HBox()
1241         vbox.pack_start(hbox, False, False, 0)
1242
1243         padding = gtk.HBox()
1244         hbox.pack_start(padding, True, True, 0)
1245
1246         self.advanced_button = gtk.Button("Advanced")
1247         hbox.pack_start(self.advanced_button, False, False, 2)
1248
1249
1250
1251         # dialog buttons
1252
1253         self.action_area.set_layout(gtk.BUTTONBOX_END)
1254
1255         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
1256         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
1257         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
1258
1259         self.ok_button = gtk.Button("Ok", gtk.STOCK_OK)
1260         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1261         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
1262
1263         self.ok_button = gtk.Button("Apply", gtk.STOCK_APPLY)
1264         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1265         self.add_action_widget(self.ok_button, gtk.RESPONSE_APPLY)
1266
1267         self.set_default_response(gtk.RESPONSE_APPLY)
1268
1269
1270         # signals/events
1271
1272         self.user_tree_view.get_selection().connect("changed", self.on_user_tree_view_selection_changed)
1273         self.add_button.connect("clicked", self.on_add_item_activate)
1274         self.remove_button.connect("clicked", self.on_remove_item_activate)
1275
1276         #TODO: permission view data editing updates the store?
1277         self.advanced_button.connect("clicked", self.on_advanced_item_activate)
1278
1279     def check_for_problems(self):
1280         #TODO: find problems?
1281         return None
1282
1283     def on_user_tree_view_selection_changed(self, widget):
1284         self.permissions_store.clear()
1285
1286         (iter, user) = self.get_selected_user()
1287
1288         if (iter is not None):
1289             self.permissions_label.set_text("Permissions for " + user.username + ":")
1290             #TODO: update permissions view on selection changed
1291         else:
1292             self.permissions_label.set_text("")
1293
1294     def on_add_item_activate(self, widget):
1295         #TODO: implement add user for permissions
1296         pass
1297
1298     def on_remove_item_activate(self, widget):
1299         (iter, user) = self.get_selected_user()
1300
1301         if (iter is not None):
1302             self.users.remove(user)
1303             self.user_store.remove(iter)
1304             #TODO: remove user permissions?
1305
1306     def on_advanced_item_activate(self, widget):
1307         dialog = RegAdvancedPermissionsDialog(None, None)
1308         dialog.show_all()
1309         #TODO: handle advanced dialog
1310         dialog.run()
1311         dialog.hide_all()
1312
1313
1314     def get_selected_user(self):
1315         (model, iter) = self.user_tree_view.get_selection().get_selected()
1316         if (iter is None): # no selection
1317             return (None, None)
1318         else:
1319             return (iter, model.get_value(iter, 1))
1320
1321 class RegAdvancedPermissionsDialog(gtk.Dialog):
1322     def __init__(self, users, permissions):
1323         super(RegAdvancedPermissionsDialog, self).__init__()
1324
1325         self.users = users
1326         self.permissions = permissions
1327
1328         self.create()
1329
1330         self.insert_test_values() #TODO: remove
1331
1332         #update sensitivity
1333         self.on_auditing_tree_view_selection_changed(None)
1334         self.on_permissions_tree_view_selection_changed(None)
1335
1336     def create(self):
1337         self.set_title("Permissions")
1338         self.set_border_width(5)
1339         self.set_resizable(True)
1340         self.set_default_size(630, 490)
1341
1342         self.icon_registry_filename = os.path.join(sys.path[0], "images", "registry.png")
1343         self.set_icon_from_file(self.icon_registry_filename)
1344
1345         self.notebook = gtk.Notebook()
1346         self.vbox.pack_start(self.notebook, True, True, 0)
1347
1348
1349
1350         # Permissions tab
1351
1352         hbox = gtk.HBox() #hbox is for the padding on the left & right.
1353         self.notebook.append_page(hbox, gtk.Label("Permissions"))
1354
1355         vbox = gtk.VBox()
1356         hbox.pack_start(vbox, True, True, 10)
1357
1358         label = gtk.Label("To view the details of special permissions entries, select it and then click Edit.\n")
1359         label.set_alignment(0, 0)
1360         vbox.pack_start(label, False, False, 15)
1361
1362         label = gtk.Label("Permission entries:")
1363         label.set_alignment(0, 1)
1364         vbox.pack_start(label, False, False, 0)
1365
1366         hpaned = gtk.HPaned()
1367         vbox.pack_start(hpaned, True, True, 0)
1368
1369         scrolledwindow = gtk.ScrolledWindow(None, None)
1370         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1371         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1372         hpaned.add1(scrolledwindow)
1373
1374         self.permissions_tree_view = gtk.TreeView()
1375         scrolledwindow.add(self.permissions_tree_view)
1376
1377         column = gtk.TreeViewColumn()
1378         column.set_title("Type")
1379         column.set_resizable(True)
1380         column.set_sort_column_id(0)
1381         renderer = gtk.CellRendererText()
1382         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1383         column.pack_start(renderer, True)
1384         self.permissions_tree_view.append_column(column)
1385         column.add_attribute(renderer, "text", 0)
1386
1387         column = gtk.TreeViewColumn()
1388         column.set_title("Name")
1389         column.set_resizable(True)
1390         column.set_expand(True)
1391         column.set_sort_column_id(1)
1392         renderer = gtk.CellRendererText()
1393         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1394         column.pack_start(renderer, True)
1395         self.permissions_tree_view.append_column(column)
1396         column.add_attribute(renderer, "text", 1)
1397
1398         column = gtk.TreeViewColumn()
1399         column.set_title("Permission")
1400         column.set_resizable(True)
1401         column.set_expand(True)
1402         column.set_sort_column_id(2)
1403         renderer = gtk.CellRendererText()
1404         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1405         column.pack_start(renderer, True)
1406         self.permissions_tree_view.append_column(column)
1407         column.add_attribute(renderer, "text", 2)
1408
1409         column = gtk.TreeViewColumn()
1410         column.set_title("Inherited from")
1411         column.set_resizable(True)
1412         column.set_expand(True)
1413         column.set_sort_column_id(3)
1414         renderer = gtk.CellRendererText()
1415         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1416         column.pack_start(renderer, True)
1417         self.permissions_tree_view.append_column(column)
1418         column.add_attribute(renderer, "text", 3)
1419
1420         column = gtk.TreeViewColumn()
1421         column.set_title("Applies to")
1422         column.set_resizable(True)
1423         column.set_expand(True)
1424         column.set_sort_column_id(4)
1425         renderer = gtk.CellRendererText()
1426         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1427         column.pack_start(renderer, True)
1428         self.permissions_tree_view.append_column(column)
1429         column.add_attribute(renderer, "text", 4)
1430
1431         #Store contains: type (string), name (string), permission (string), inherited from (string), apply to (string, permissions (object)
1432         self.permissions_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
1433         self.permissions_tree_view.set_model(self.permissions_store)
1434
1435         hbox = gtk.HBox()
1436         vbox.pack_start(hbox, False, False, 0)
1437
1438         padding = gtk.HBox()
1439         hbox.pack_start(padding, True, True, 0)
1440
1441         self.add_button_permissions = gtk.Button("Add", gtk.STOCK_ADD)
1442         hbox.pack_start(self.add_button_permissions, False, False, 2)
1443
1444         self.edit_button_permissions = gtk.Button("Edit", gtk.STOCK_EDIT)
1445         hbox.pack_start(self.edit_button_permissions, False, False, 2)
1446
1447         self.remove_button_permissions = gtk.Button("Remove", gtk.STOCK_REMOVE)
1448         hbox.pack_start(self.remove_button_permissions, False, False, 2)
1449
1450         check_area = gtk.VBox()
1451         vbox.pack_start(check_area, False, False, 10)
1452
1453         self.check_inherit_permissions = gtk.CheckButton("Inherit permissions from parents that apply to child objects.")
1454         check_area.pack_start(self.check_inherit_permissions, False, False, 0)
1455
1456         hbox = gtk.HBox()
1457         check_area.pack_start(hbox, False, False, 0)
1458
1459         self.replace_child_permissions_button = gtk.Button("Replace child permissions")
1460         hbox.pack_start(self.replace_child_permissions_button, False, False, 0)
1461
1462
1463
1464         # Auditing tab
1465
1466         hbox = gtk.HBox() #hbox is for the padding on the left & right.
1467         self.notebook.append_page(hbox, gtk.Label("Auditing"))
1468
1469         vbox = gtk.VBox()
1470         hbox.pack_start(vbox, True, True, 10)
1471
1472         label = gtk.Label("To view the details of special auditing entries, select it and then click Edit.\n")
1473         label.set_alignment(0, 0)
1474         vbox.pack_start(label, False, False, 15)
1475
1476         label = gtk.Label("Auditing entries:")
1477         label.set_alignment(0, 1)
1478         vbox.pack_start(label, False, False, 0)
1479
1480         hpaned = gtk.HPaned()
1481         vbox.pack_start(hpaned, True, True, 0)
1482
1483         scrolledwindow = gtk.ScrolledWindow(None, None)
1484         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1485         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1486         hpaned.add1(scrolledwindow)
1487
1488         self.auditing_tree_view = gtk.TreeView()
1489         scrolledwindow.add(self.auditing_tree_view)
1490
1491         column = gtk.TreeViewColumn()
1492         column.set_title("Type")
1493         column.set_resizable(True)
1494         column.set_sort_column_id(0)
1495         renderer = gtk.CellRendererText()
1496         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1497         column.pack_start(renderer, True)
1498         self.auditing_tree_view.append_column(column)
1499         column.add_attribute(renderer, "text", 0)
1500
1501         column = gtk.TreeViewColumn()
1502         column.set_title("Name")
1503         column.set_resizable(True)
1504         column.set_expand(True)
1505         column.set_sort_column_id(1)
1506         renderer = gtk.CellRendererText()
1507         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1508         column.pack_start(renderer, True)
1509         self.auditing_tree_view.append_column(column)
1510         column.add_attribute(renderer, "text", 1)
1511
1512         column = gtk.TreeViewColumn()
1513         column.set_title("Permission")
1514         column.set_resizable(True)
1515         column.set_expand(True)
1516         column.set_sort_column_id(2)
1517         renderer = gtk.CellRendererText()
1518         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1519         column.pack_start(renderer, True)
1520         self.auditing_tree_view.append_column(column)
1521         column.add_attribute(renderer, "text", 2)
1522
1523         column = gtk.TreeViewColumn()
1524         column.set_title("Inherited from")
1525         column.set_resizable(True)
1526         column.set_expand(True)
1527         column.set_sort_column_id(3)
1528         renderer = gtk.CellRendererText()
1529         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1530         column.pack_start(renderer, True)
1531         self.auditing_tree_view.append_column(column)
1532         column.add_attribute(renderer, "text", 3)
1533
1534         column = gtk.TreeViewColumn()
1535         column.set_title("Applies to")
1536         column.set_resizable(True)
1537         column.set_expand(True)
1538         column.set_sort_column_id(4)
1539         renderer = gtk.CellRendererText()
1540         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1541         column.pack_start(renderer, True)
1542         self.auditing_tree_view.append_column(column)
1543         column.add_attribute(renderer, "text", 4)
1544
1545         self.auditing_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
1546         self.auditing_tree_view.set_model(self.auditing_store)
1547
1548         hbox = gtk.HBox()
1549         vbox.pack_start(hbox, False, False, 0)
1550
1551         padding = gtk.HBox()
1552         hbox.pack_start(padding, True, True, 0)
1553
1554         self.add_button_auditing = gtk.Button("Add", gtk.STOCK_ADD)
1555         hbox.pack_start(self.add_button_auditing, False, False, 2)
1556
1557         self.edit_button_auditing = gtk.Button("Edit", gtk.STOCK_EDIT)
1558         hbox.pack_start(self.edit_button_auditing, False, False, 2)
1559
1560         self.remove_button_auditing = gtk.Button("Remove", gtk.STOCK_REMOVE)
1561         hbox.pack_start(self.remove_button_auditing, False, False, 2)
1562
1563         check_area = gtk.VBox()
1564         vbox.pack_start(check_area, False, False, 10)
1565
1566         self.check_inherit_auditing = gtk.CheckButton("Inherit auditing options from parents that apply to child objects.")
1567         check_area.pack_start(self.check_inherit_auditing, False, False, 0)
1568
1569         hbox = gtk.HBox()
1570         check_area.pack_start(hbox, False, False, 0)
1571
1572         self.replace_child_auditing_button = gtk.Button("Replace child auditing options")
1573         hbox.pack_start(self.replace_child_auditing_button, False, False, 0)
1574
1575
1576
1577         # Ownership tab
1578
1579         hbox = gtk.HBox() #hbox is for the padding on the left & right.
1580         self.notebook.append_page(hbox, gtk.Label("Ownership"))
1581
1582         vbox = gtk.VBox()
1583         hbox.pack_start(vbox, True, True, 10)
1584
1585
1586         label = gtk.Label("You may take ownership of an object if you have the appropriate permissions.\n")
1587         label.set_alignment(0, 0)
1588         vbox.pack_start(label, False, False, 15)
1589
1590         label = gtk.Label("Current owner of this item:")
1591         label.set_alignment(0, 1)
1592         vbox.pack_start(label, False, False, 0)
1593
1594         textview = gtk.Entry()
1595         textview.set_editable(False)
1596         vbox.pack_start(textview, False, False, 0)
1597
1598         label = gtk.Label("Change owner to:")
1599         label.set_alignment(0, 1)
1600         vbox.pack_start(label, False, False, 0)
1601
1602         hpaned = gtk.HPaned()
1603         vbox.pack_start(hpaned, True, True, 0)
1604
1605         scrolledwindow = gtk.ScrolledWindow(None, None)
1606         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1607         scrolledwindow.set_shadow_type(gtk.SHADOW_IN)
1608         hpaned.add1(scrolledwindow)
1609
1610         self.owner_tree_view = gtk.TreeView()
1611         self.owner_tree_view.set_headers_visible(False)
1612         scrolledwindow.add(self.owner_tree_view)
1613
1614         column = gtk.TreeViewColumn()
1615         column.set_title("Name")
1616         column.set_resizable(True)
1617         column.set_fixed_width(200)
1618         column.set_sort_column_id(0)
1619         renderer = gtk.CellRendererText()
1620         renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
1621         column.pack_start(renderer, True)
1622         self.owner_tree_view.append_column(column)
1623         column.add_attribute(renderer, "text", 0)
1624
1625         self.owner_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
1626         self.owner_tree_view.set_model(self.owner_store)
1627
1628         self.check_replace_owner_child_objects = gtk.CheckButton("Replace ownership of child objects")
1629         vbox.pack_start(self.check_replace_owner_child_objects, False, False, 10)
1630
1631
1632
1633         # dialog buttons
1634
1635         self.action_area.set_layout(gtk.BUTTONBOX_END)
1636
1637         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
1638         self.cancel_button.set_flags(gtk.CAN_DEFAULT)
1639         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
1640
1641         self.ok_button = gtk.Button("Ok", gtk.STOCK_OK)
1642         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1643         self.add_action_widget(self.ok_button, gtk.RESPONSE_OK)
1644
1645         self.ok_button = gtk.Button("Apply", gtk.STOCK_APPLY)
1646         self.ok_button.set_flags(gtk.CAN_DEFAULT)
1647         self.add_action_widget(self.ok_button, gtk.RESPONSE_APPLY)
1648
1649         self.set_default_response(gtk.RESPONSE_APPLY)
1650
1651         # TODO: Effective permissions
1652
1653         # signals/events
1654         self.permissions_tree_view.get_selection().connect("changed", self.on_permissions_tree_view_selection_changed)
1655         self.auditing_tree_view.get_selection().connect("changed", self.on_auditing_tree_view_selection_changed)
1656
1657         self.add_button_permissions.connect("clicked", self.on_add_permissions_button_clicked)
1658         self.edit_button_permissions.connect("clicked", self.on_edit_permissions_button_clicked)
1659         self.remove_button_permissions.connect("clicked", self.on_remove_permissions_button_clicked)
1660         self.replace_child_permissions_button.connect("clicked", self.on_replace_permissions_button_clicked)
1661         self.add_button_auditing.connect("clicked", self.on_add_auditing_button_clicked)
1662         self.edit_button_auditing.connect("clicked", self.on_edit_auditing_button_clicked)
1663         self.remove_button_auditing.connect("clicked", self.on_remove_auditing_button_clicked)
1664         self.replace_child_auditing_button.connect("clicked", self.on_replace_auditing_button_clicked)
1665
1666         self.check_inherit_permissions.connect("clicked", self.on_check_inherit_permissions_changed)
1667         self.check_inherit_auditing.connect("clicked", self.on_check_inherit_auditing_changed)
1668
1669
1670
1671     def insert_test_values(self):
1672         #TODO: remove this function when no longer needed
1673         self.check_inherit_permissions.set_active(True)
1674         self.check_inherit_auditing.set_active(True)
1675
1676         user = User("Foo Bar", "", "", 0)
1677         self.permissions_store.append(("Allow", user.username, "Special Permissions", "Unicorns", "This key only", user))
1678         self.permissions_store.append(("Deny", "Pib", "Access to Playdoe", "HKEY_USERS", "This key and subkeys", user))
1679
1680         self.auditing_store.append(("Deny", "Homer Simpson", "Double Rainbow", "HKEY_LOCAL_MACHINE\\made up key\\temp\\new", "This key and subkeys", user))
1681         self.auditing_store.append(("Allow", "Administrator", "Your Right to Party", "Earthworm Jim", "This key only", user))
1682
1683     def get_selected_permission(self):
1684         (model, iter) = self.permissions_tree_view.get_selection().get_selected()
1685         if (iter is None): # no selection
1686             return (None, None)
1687         else:
1688             return (iter, model.get_value(iter, 1))
1689
1690     def get_selected_audit(self):
1691         (model, iter) = self.auditing_tree_view.get_selection().get_selected()
1692         if iter is None: # no selection
1693             return (None, None)
1694         else:
1695             return (iter, model.get_value(iter, 1))
1696
1697     def on_permissions_tree_view_selection_changed(self, widget):
1698         (iter, permission) = self.get_selected_permission()
1699         self.edit_button_permissions.set_sensitive(permission is not None)
1700         self.remove_button_permissions.set_sensitive(permission is not None)
1701
1702     def on_auditing_tree_view_selection_changed(self, widget):
1703         (iter, audit) = self.get_selected_audit()
1704         self.edit_button_auditing.set_sensitive(audit is not None)
1705         self.remove_button_auditing.set_sensitive(audit is not None)
1706
1707     def on_add_permissions_button_clicked(self, widget):
1708         #TODO: this
1709         pass
1710
1711     def on_edit_permissions_button_clicked(self, widget):
1712         #TODO: this
1713         pass
1714
1715     def on_remove_permissions_button_clicked(self, widget):
1716         (iter, permission) = self.get_selected_permission()
1717         if (iter is not None):
1718             self.permissions_store.remove(iter)
1719
1720     def on_replace_permissions_button_clicked(self, widget):
1721         #TODO: this
1722         pass
1723
1724     def on_add_auditing_button_clicked(self, widget):
1725         #TODO: this
1726         pass
1727
1728     def on_edit_auditing_button_clicked(self, widget):
1729         #TODO: this
1730         pass
1731
1732     def on_remove_auditing_button_clicked(self, widget):
1733         (iter, audit) = self.get_selected_audit()
1734         if (iter is not None):
1735             self.auditing_store.remove(iter)
1736
1737     def on_replace_auditing_button_clicked(self, widget):
1738         #TODO: this
1739         pass
1740
1741     def on_check_inherit_permissions_changed(self, widget):
1742         if widget.get_active():
1743             return
1744         #TODO: if no permissions are inherited
1745
1746         message_box = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "Unchecking this option means permissions inherited from the parent object will be lost.\n\nDo you want to copy the inherited permissions for this object?")
1747         response = message_box.run()
1748         message_box.hide()
1749
1750         if (response == gtk.RESPONSE_YES):
1751             #TODO: copy permissions from the parent object
1752             pass
1753         elif (response == gtk.RESPONSE_NO):
1754             #TODO: delete all inherited permissions from the permissions store
1755             pass
1756         else:#probably gtk.RESPONSE_DELETE_EVENT (from pressing escape)
1757             widget.set_active(True)
1758
1759     def on_check_inherit_auditing_changed(self, widget):
1760         if widget.get_active():
1761             return
1762         #TODO: if no permissions are inherited
1763
1764         message_box = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "Unchecking this option means auditing options inherited from the parent object will be lost.\n\nDo you want to copy the inherited auditing options for this object?")
1765         response = message_box.run()
1766         message_box.hide()
1767
1768         if response == gtk.RESPONSE_YES:
1769             #TODO: copy auditing from the parent object
1770             pass
1771         elif response == gtk.RESPONSE_NO:
1772             #TODO: delete all inherited auditing from the permissions store
1773             pass
1774         else:#probably gtk.RESPONSE_DELETE_EVENT (from pressing escape)
1775             widget.set_active(True)
1776
1777
1778 class WinRegConnectDialog(gtk.Dialog):
1779
1780     def __init__(self, server, transport_type, username, password=""):
1781         super(WinRegConnectDialog, self).__init__()
1782
1783         self.server_address = server
1784         self.transport_type = transport_type
1785         self.username = username
1786         self.password = password
1787
1788         self.create()
1789
1790         self.update_sensitivity()
1791
1792     def create(self):
1793         self.set_title("Connect to a server")
1794         self.set_border_width(5)
1795         self.set_icon_name(gtk.STOCK_CONNECT)
1796         self.set_resizable(False)
1797
1798
1799         # server frame
1800
1801         self.vbox.set_spacing(5)
1802
1803         self.server_frame = gtk.Frame("Server")
1804         self.vbox.pack_start(self.server_frame, False, True, 0)
1805
1806         table = gtk.Table(3, 2)
1807         table.set_border_width(5)
1808         self.server_frame.add(table)
1809
1810         label = gtk.Label(" Server address: ")
1811         label.set_alignment(0, 0.5)
1812         table.attach(label, 0, 1, 0, 1, gtk.FILL, gtk.FILL | gtk.EXPAND, 0, 0)
1813
1814         self.server_address_entry = gtk.Entry()
1815         self.server_address_entry.set_text(self.server_address)
1816         self.server_address_entry.set_activates_default(True)
1817         table.attach(self.server_address_entry, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 1, 1)
1818
1819         label = gtk.Label(" Username: ")
1820         label.set_alignment(0, 0.5)
1821         table.attach(label, 0, 1, 1, 2, gtk.FILL, gtk.FILL | gtk.EXPAND, 0, 0)
1822
1823         self.username_entry = gtk.Entry()
1824         self.username_entry.set_text(self.username)
1825         self.username_entry.set_activates_default(True)
1826         table.attach(self.username_entry, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 1, 1)
1827
1828         label = gtk.Label(" Password: ")
1829         label.set_alignment(0, 0.5)
1830         table.attach(label, 0, 1, 2, 3, gtk.FILL, gtk.FILL | gtk.EXPAND, 0, 0)
1831
1832         self.password_entry = gtk.Entry()
1833         self.password_entry.set_text(self.password)
1834         self.password_entry.set_visibility(False)
1835         self.password_entry.set_activates_default(True)
1836         table.attach(self.password_entry, 1, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL | gtk.EXPAND, 1, 1)
1837
1838
1839         # transport frame
1840
1841         self.transport_frame = gtk.Frame(" Transport type ")
1842         self.vbox.pack_start(self.transport_frame, False, True, 0)
1843
1844         vbox = gtk.VBox()
1845         vbox.set_border_width(5)
1846         self.transport_frame.add(vbox)
1847
1848         self.rpc_smb_tcpip_radio_button = gtk.RadioButton(None, "RPC over SMB over TCP/IP")
1849         self.rpc_smb_tcpip_radio_button.set_active(self.transport_type == 0)
1850         vbox.pack_start(self.rpc_smb_tcpip_radio_button)
1851
1852         self.rpc_tcpip_radio_button = gtk.RadioButton(self.rpc_smb_tcpip_radio_button, "RPC over TCP/IP")
1853         self.rpc_tcpip_radio_button.set_active(self.transport_type == 1)
1854         vbox.pack_start(self.rpc_tcpip_radio_button)
1855
1856         self.localhost_radio_button = gtk.RadioButton(self.rpc_tcpip_radio_button, "Localhost")
1857         self.localhost_radio_button.set_active(self.transport_type == 2)
1858         vbox.pack_start(self.localhost_radio_button)
1859
1860
1861         # dialog buttons
1862
1863         self.action_area.set_layout(gtk.BUTTONBOX_END)
1864
1865         self.cancel_button = gtk.Button("Cancel", gtk.STOCK_CANCEL)
1866         self.add_action_widget(self.cancel_button, gtk.RESPONSE_CANCEL)
1867
1868         self.connect_button = gtk.Button("Connect", gtk.STOCK_CONNECT)
1869         self.connect_button.set_flags(gtk.CAN_DEFAULT)
1870         self.add_action_widget(self.connect_button, gtk.RESPONSE_OK)
1871
1872         self.set_default_response(gtk.RESPONSE_OK)
1873
1874
1875         # signals/events
1876
1877         self.rpc_smb_tcpip_radio_button.connect("toggled", self.on_radio_button_toggled)
1878         self.rpc_tcpip_radio_button.connect("toggled", self.on_radio_button_toggled)
1879         self.localhost_radio_button.connect("toggled", self.on_radio_button_toggled)
1880
1881     def update_sensitivity(self):
1882         server_required = not self.localhost_radio_button.get_active()
1883
1884         self.server_address_entry.set_sensitive(server_required)
1885
1886     def get_server_address(self):
1887         return self.server_address_entry.get_text().strip()
1888
1889     def get_transport_type(self):
1890         if self.rpc_smb_tcpip_radio_button.get_active():
1891             return 0
1892         elif self.rpc_tcpip_radio_button.get_active():
1893             return 1
1894         elif self.localhost_radio_button.get_active():
1895             return 2
1896         else:
1897             return -1
1898
1899     def get_username(self):
1900         return self.username_entry.get_text().strip()
1901
1902     def get_password(self):
1903         return self.password_entry.get_text()
1904
1905     def on_radio_button_toggled(self, widget):
1906         self.update_sensitivity()