From 96b21bbc6f6e5072e1b0fc20bb957532140bba7a Mon Sep 17 00:00:00 2001 From: Yann Leboulanger Date: Mon, 3 Jul 2006 20:49:20 +0000 Subject: [PATCH] [roidelapluie & asterix] Privacy lists. Fixes #253 --- data/glade/advanced_menuitem_menu.glade | 7 + data/glade/privacy_list_edit_window.glade | 779 ++++++++++++++++++++ data/glade/privacy_lists_first_window.glade | 255 +++++++ src/common/connection.py | 65 ++ src/common/xmpp/features.py | 3 + src/common/xmpp/features_nb.py | 80 +- src/dialogs.py | 393 +++++++++- src/gajim.py | 29 + src/roster_window.py | 11 + 9 files changed, 1591 insertions(+), 31 deletions(-) create mode 100644 data/glade/privacy_list_edit_window.glade create mode 100644 data/glade/privacy_lists_first_window.glade diff --git a/data/glade/advanced_menuitem_menu.glade b/data/glade/advanced_menuitem_menu.glade index 8ab4ac0e5..c1cd77edf 100644 --- a/data/glade/advanced_menuitem_menu.glade +++ b/data/glade/advanced_menuitem_menu.glade @@ -30,6 +30,13 @@ + + + _Privacy Lists + True + + + diff --git a/data/glade/privacy_list_edit_window.glade b/data/glade/privacy_list_edit_window.glade new file mode 100644 index 000000000..681c79625 --- /dev/null +++ b/data/glade/privacy_list_edit_window.glade @@ -0,0 +1,779 @@ + + + + + + + 6 + True + Privacy List + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + 600 + True + False + 0 + + + + True + True + 0 + + + + True + <i>Privacy List</i> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + Active + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + + True + True + Default + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + 0 + False + True + + + + + + True + + + 5 + False + False + + + + + + True + <b>List of rules</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 5 + False + False + + + + + + True + + False + True + + + + 5 + False + True + + + + + + True + True + 0 + + + + 5 + True + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + 5 + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + 6 + True + True + gtk-edit + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + False + True + + + + + + 5 + False + 0 + + + + True + + + 5 + True + True + + + + + + True + <b>Add / Edit a rule</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 5 + False + False + + + + + + True + False + 0 + + + + True + True + 0 + + + + True + True + Allow + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Deny + True + GTK_RELIEF_NORMAL + True + False + False + True + edit_allow_radiobutton + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + True + 0 + + + + 5 + True + False + 0 + + + + True + True + JabberID + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 5 + False + False + + + + + + True + True + True + True + 0 + + True + + False + + + 5 + True + True + + + + + 0 + True + True + + + + + + 5 + True + False + 0 + + + + True + True + all in the group + True + GTK_RELIEF_NORMAL + True + False + False + True + edit_type_jabberid_radiobutton + + + 5 + False + False + + + + + + True + + False + True + + + 5 + True + True + + + + + 0 + True + True + + + + + + 5 + True + False + 0 + + + + True + True + all by subscription + True + GTK_RELIEF_NORMAL + True + False + False + True + edit_type_jabberid_radiobutton + + + 5 + False + False + + + + + + True + none +both +from +to + False + True + + + 5 + True + True + + + + + 0 + True + True + + + + + + 10 + True + False + 0 + + + + True + True + All + True + GTK_RELIEF_NORMAL + True + False + False + True + edit_type_jabberid_radiobutton + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + True + 0 + + + + True + True + to send me messages + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + to send me queries + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + to view my status + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + to send me status + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + True + 0 + + + + True + False + 0 + + + + True + Order: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 5 + False + False + + + + + + True + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 0 100 1 10 10 + + + 0 + False + True + + + + + 0 + True + True + + + + + + 5 + True + True + gtk-save + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + + + 0 + False + True + + + + + + True + True + 0 + + + + 5 + True + True + gtk-refresh + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + 5 + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + False + True + + + + + + + diff --git a/data/glade/privacy_lists_first_window.glade b/data/glade/privacy_lists_first_window.glade new file mode 100644 index 000000000..7a7470123 --- /dev/null +++ b/data/glade/privacy_lists_first_window.glade @@ -0,0 +1,255 @@ + + + + + + + 12 + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + Server-based Privacy Lists + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 5 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 4 + True + + False + True + + + 0 + True + True + + + + + + True + True + 0 + + + + 5 + True + True + gtk-delete + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + 5 + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + + + 5 + True + True + + + + + + True + Create your own Privacy Lists + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 5 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + + False + + + 4 + False + False + + + + + + 5 + True + True + gtk-new + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + + + 5 + True + True + + + + + + True + True + 0 + + + + 5 + True + True + gtk-refresh + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + 5 + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/src/common/connection.py b/src/common/connection.py index 7a4574d11..6b90b7cb9 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -217,6 +217,34 @@ class Connection(ConnectionHandlers): else: conf = data[1].asDict() self.dispatch('REGISTER_AGENT_INFO', (data[0], conf, is_form)) + elif realm == common.xmpp.NS_PRIVACY: + if event == common.xmpp.features_nb.PRIVACY_LISTS_RECEIVED: + # data is (list) + self.dispatch('PRIVACY_LISTS_RECEIVED', (data)) + elif event == common.xmpp.features_nb.PRIVACY_LIST_RECEIVED: + # data is (resp) + if not data: + return + rules = [] + name = data.getTag('query').getTag('list').getAttr('name') + for child in data.getTag('query').getTag('list').getChildren(): + dict_item = child.getAttrs() + childs = [] + if dict_item.has_key('type'): + for scnd_child in child.getChildren(): + childs += [scnd_child.getName()] + rules.append({'action':dict_item['action'], + 'type':dict_item['type'], 'order':dict_item['order'], + 'value':dict_item['value'], 'child':childs}) + else: + for scnd_child in child.getChildren(): + childs.append(scnd_child.getName()) + rules.append({'action':dict_item['action'], + 'order':dict_item['order'], 'child':childs}) + self.dispatch('PRIVACY_LIST_RECEIVED', (name, rules)) + elif event == common.xmpp.features_nb.PRIVACY_LISTS_ACTIVE_DEFAULT: + # data is (dict) + self.dispatch('PRIVACY_LISTS_ACTIVE_DEFAULT', (data)) elif realm == '': if event == common.xmpp.transports.DATA_RECEIVED: self.dispatch('STANZA_ARRIVED', unicode(data, errors = 'ignore')) @@ -439,6 +467,41 @@ class Connection(ConnectionHandlers): if kill_core and self.connected > 1: self.disconnect(on_purpose = True) + def get_privacy_lists(self): + if not self.connection: + return + common.xmpp.features_nb.getPrivacyLists(self.connection) + + def get_active_default_lists(self): + if not self.connection: + return + common.xmpp.features_nb.getActiveAndDefaultPrivacyLists(self.connection) + + def del_privacy_list(self, privacy_list): + if not self.connection: + return + common.xmpp.features_nb.delPrivacyList(self.connection, privacy_list) + + def get_privacy_list(self, title): + if not self.connection: + return + common.xmpp.features_nb.getPrivacyList(self.connection, title) + + def set_privacy_list(self, listname, tags): + if not self.connection: + return + common.xmpp.features_nb.setPrivacyList(self.connection, listname, tags) + + def set_active_list(self, listname): + if not self.connection: + return + common.xmpp.features_nb.setActivePrivacyList(self.connection, listname, 'active') + + def set_default_list(self, listname): + if not self.connection: + return + common.xmpp.features_nb.setDefaultPrivacyList(self.connection, listname) + def build_privacy_rule(self, name, action): '''Build a Privacy rule stanza for invisibility''' iq = common.xmpp.Iq('set', common.xmpp.NS_PRIVACY, xmlns = '') @@ -448,6 +511,8 @@ class Connection(ConnectionHandlers): return iq def activate_privacy_rule(self, name): + if not self.connection: + return '''activate a privacy rule''' iq = common.xmpp.Iq('set', common.xmpp.NS_PRIVACY, xmlns = '') iq.getTag('query').setTag('active', {'name': name}) diff --git a/src/common/xmpp/features.py b/src/common/xmpp/features.py index 8fad7fc24..5b4b6fea6 100644 --- a/src/common/xmpp/features.py +++ b/src/common/xmpp/features.py @@ -27,6 +27,9 @@ All these methods takes 'disp' first argument that should be already connected from protocol import * REGISTER_DATA_RECEIVED='REGISTER DATA RECEIVED' +PRIVACY_LISTS_RECEIVED='PRIVACY LISTS RECEIVED' +PRIVACY_LIST_RECEIVED='PRIVACY LIST RECEIVED' +PRIVACY_LISTS_ACTIVE_DEFAULT='PRIVACY LISTS ACTIVE DEFAULT' ### DISCO ### http://jabber.org/protocol/disco ### JEP-0030 #################### ### Browse ### jabber:iq:browse ### JEP-0030 ################################### diff --git a/src/common/xmpp/features_nb.py b/src/common/xmpp/features_nb.py index 453f7229b..ed195ceca 100644 --- a/src/common/xmpp/features_nb.py +++ b/src/common/xmpp/features_nb.py @@ -14,7 +14,7 @@ # $Id: features.py,v 1.22 2005/09/30 20:13:04 mikealbon Exp $ -from features import REGISTER_DATA_RECEIVED +from features import REGISTER_DATA_RECEIVED, PRIVACY_LISTS_RECEIVED, PRIVACY_LIST_RECEIVED, PRIVACY_LISTS_ACTIVE_DEFAULT from protocol import * def _on_default_response(disp, iq, cb): @@ -146,9 +146,9 @@ def register(disp, host, info, cb): attributes lastErrNode, lastErr and lastErrCode. """ iq=Iq('set', NS_REGISTER, to=host) - if not isinstance(info, dict): + if not isinstance(info, dict): info=info.asDict() - for i in info.keys(): + for i in info.keys(): iq.setTag('query').setTagData(i,info[i]) disp.SendAndCallForResponse(iq, cb) @@ -172,37 +172,46 @@ def changePasswordTo(disp, newpassword, host=None, cb = None): #type=[jid|group|subscription] #action=[allow|deny] -def getPrivacyLists(disp, cb): +def getPrivacyLists(disp): """ Requests privacy lists from connected server. Returns dictionary of existing lists on success.""" iq = Iq('get', NS_PRIVACY) def _on_response(resp): dict = {'lists': []} - try: - if not isResultNode(resp): - cb(False) - return - for list in resp.getQueryPayload(): - if list.getName()=='list': - dict['lists'].append(list.getAttr('name')) - else: - dict[list.getName()]=list.getAttr('name') - cb(dict) - except: - pass - cb(False) - disp.SendAndCallForResponse(iq, _on_respons) + if not isResultNode(resp): + disp.Event(NS_PRIVACY, PRIVACY_LISTS_RECEIVED, (False)) + return + for list in resp.getQueryPayload(): + if list.getName()=='list': + dict['lists'].append(list.getAttr('name')) + else: + dict[list.getName()]=list.getAttr('name') + disp.Event(NS_PRIVACY, PRIVACY_LISTS_RECEIVED, (dict)) + disp.SendAndCallForResponse(iq, _on_response) -def getPrivacyList(disp, listname, cb): +def getActiveAndDefaultPrivacyLists(disp): + iq = Iq('get', NS_PRIVACY) + def _on_response(resp): + dict = {'active': '', 'default': ''} + if not isResultNode(resp): + disp.Event(NS_PRIVACY, PRIVACY_LISTS_ACTIVE_DEFAULT, (False)) + return + for list in resp.getQueryPayload(): + if list.getName() == 'active': + dict['active'] = list.getAttr('name') + elif list.getName() == 'default': + dict['default'] = list.getAttr('name') + disp.Event(NS_PRIVACY, PRIVACY_LISTS_ACTIVE_DEFAULT, (dict)) + disp.SendAndCallForResponse(iq, _on_response) + +def getPrivacyList(disp, listname): """ Requests specific privacy list listname. Returns list of XML nodes (rules) taken from the server responce.""" def _on_response(resp): - try: - if isResultNode(resp): - return cb(resp.getQueryPayload()[0]) - except: - pass - cb(False) + if not isResultNode(resp): + disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False)) + return + disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (resp)) iq = Iq('get', NS_PRIVACY, payload=[Node('list', {'name': listname})]) disp.SendAndCallForResponse(iq, _on_response) @@ -220,14 +229,25 @@ def setDefaultPrivacyList(disp, listname=None): """ Sets the default privacy list as 'listname'. Returns true on success.""" return setActivePrivacyList(disp, listname,'default') -def setPrivacyList(disp, list, cb): +def setPrivacyList(disp, listname, tags): """ Set the ruleset. 'list' should be the simpleXML node formatted according to RFC 3921 (XMPP-IM) (I.e. Node('list',{'name':listname},payload=[...]) ) Returns true on success.""" - iq=Iq('set',NS_PRIVACY,payload=[list]) - _on_default_response(disp, iq, cb) + iq = Iq('set', NS_PRIVACY, xmlns = '') + list_query = iq.getTag('query').setTag('list', {'name': listname}) + for item in tags: + if item.has_key('type') and item.has_key('value'): + item_tag = list_query.setTag('item', {'action': item['action'], + 'order': item['order'], 'type': item['type'], 'value': item['value']}) + else: + item_tag = list_query.setTag('item', {'action': item['action'], + 'order': item['order']}) + if item.has_key('child'): + for child_tag in item['child']: + item_tag.setTag(child_tag) + _on_default_response(disp, iq, None) -def delPrivacyList(disp,listname, cb): +def delPrivacyList(disp,listname): """ Deletes privacy list 'listname'. Returns true on success.""" iq = Iq('set',NS_PRIVACY,payload=[Node('list',{'name':listname})]) - _on_default_response(disp, iq, cb) + _on_default_response(disp, iq, None) diff --git a/src/dialogs.py b/src/dialogs.py index e61ba58bb..bdff353b1 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -1577,6 +1577,397 @@ class XMLConsoleWindow: # it's expanded!! self.input_textview.grab_focus() +class PrivacyListWindow: + def __init__(self, account, privacy_list, list_type): + '''list_type can be 0 if list is created or 1 if it id edited''' + self.account = account + self.privacy_list = privacy_list + + # Dicts and Default Values + self.active_rule = '' + self.global_rules = {} + self.list_of_groups = {} + + # Default Edit Values + self.edit_rule_type = 'jid' + self.allow_deny = 'allow' + + # Connect to glade + self.xml = gtkgui_helpers.get_glade('privacy_list_edit_window.glade') + self.window = self.xml.get_widget('privacy_list_edit_window') + + # Add Widgets + + for widget_to_add in ['title_hbox', 'privacy_lists_title_label', + 'list_of_rules_label', 'add_edit_rule_label', 'delete_open_buttons_hbox', + 'privacy_list_active_checkbutton', 'privacy_list_default_checkbutton', + 'list_of_rules_combobox', 'delete_open_buttons_hbox', + 'delete_rule_button', 'open_rule_button', 'edit_allow_radiobutton', + 'edit_deny_radiobutton', 'edit_type_jabberid_radiobutton', + 'edit_type_jabberid_entry', 'edit_type_group_radiobutton', + 'edit_type_group_combobox', 'edit_type_subscription_radiobutton', + 'edit_type_subscription_combobox', 'edit_type_select_all_radiobutton', + 'edit_queries_send_checkbutton', 'edit_send_messages_checkbutton', + 'edit_view_status_checkbutton', 'edit_order_spinbutton', + 'new_rule_button', 'save_rule_button', 'privacy_list_refresh_button', + 'privacy_list_close_button', 'edit_send_status_checkbutton', + 'add_edit_vbox']: + self.__dict__[widget_to_add] = self.xml.get_widget(widget_to_add) + + # Send translations + self.privacy_lists_title_label.set_label( + _('Privacy List %s') % \ + gtkgui_helpers.escape_for_pango_markup(self.privacy_list)) + + if len(gajim.connections) > 1: + title = _('Privacy List for %s') % self.account + else: + title = _('Privacy List') + + self.delete_rule_button.set_sensitive(False) + self.open_rule_button.set_sensitive(False) + + # Check if list is created (0) or edited (1) + if list_type == 1: + self.refresh_rules() + + count = 0 + for group in gajim.groups[self.account]: + self.list_of_groups[group] = count + count += 1 + self.edit_type_group_combobox.append_text(group) + self.edit_type_group_combobox.set_active(0) + + self.window.set_title(title) + + self.add_edit_vbox.set_no_show_all(True) + self.window.show_all() + self.add_edit_vbox.hide() + + self.xml.signal_autoconnect(self) + + def on_privacy_list_edit_window_destroy(self, widget): + '''close window''' + if gajim.interface.instances[self.account].has_key('privacy_list_%s' % \ + self.privacy_list): + del gajim.interface.instances[self.account]['privacy_list_%s' % \ + self.privacy_list] + + def check_active_default(self, a_d_dict): + if a_d_dict['active'] == self.privacy_list: + self.privacy_list_active_checkbutton.set_active(True) + else: + self.privacy_list_active_checkbutton.set_active(False) + if a_d_dict['default'] == self.privacy_list: + self.privacy_list_default_checkbutton.set_active(True) + else: + self.privacy_list_default_checkbutton.set_active(False) + + def privacy_list_received(self, rules): + self.list_of_rules_combobox.get_model().clear() + self.global_rules = {} + for rule in rules: + if rule.has_key('type'): + text_item = 'Order: %s, action: %s, type: %s, value: %s' % \ + (rule['order'], rule['action'], rule['type'], + rule['value']) + else: + text_item = 'Order: %s, action: %s' % (rule['order'], + rule['action']) + self.global_rules[text_item] = rule + self.list_of_rules_combobox.append_text(text_item) + if len(rules) == 0: + self.title_hbox.set_sensitive(False) + self.list_of_rules_combobox.set_sensitive(False) + self.delete_rule_button.set_sensitive(False) + self.open_rule_button.set_sensitive(False) + else: + self.list_of_rules_combobox.set_active(0) + self.title_hbox.set_sensitive(True) + self.list_of_rules_combobox.set_sensitive(True) + self.delete_rule_button.set_sensitive(True) + self.open_rule_button.set_sensitive(True) + self.reset_fields() + gajim.connections[self.account].get_active_default_lists() + + def refresh_rules(self): + gajim.connections[self.account].get_privacy_list(self.privacy_list) + + def on_delete_rule_button_clicked(self, widget): + tags = [] + for rule in self.global_rules: + if rule != \ + self.list_of_rules_combobox.get_active_text().decode('utf-8'): + tags.append(self.global_rules[rule]) + gajim.connections[self.account].set_privacy_list( + self.privacy_list, tags) + self.privacy_list_received(tags) + self.add_edit_vbox.hide() + + def on_open_rule_button_clicked(self, widget): + self.add_edit_rule_label.set_label( + _('Edit a rule')) + active_num = self.list_of_rules_combobox.get_active() + if active_num == -1: + self.active_rule = '' + else: + self.active_rule = \ + self.list_of_rules_combobox.get_active_text().decode('utf-8') + if self.active_rule != '': + rule_info = self.global_rules[self.active_rule] + self.edit_order_spinbutton.set_value(int(rule_info['order'])) + if rule_info.has_key('type'): + if rule_info['type'] == 'jid': + self.edit_type_jabberid_radiobutton.set_active(True) + self.edit_type_jabberid_entry.set_text(rule_info['value']) + elif rule_info['type'] == 'group': + self.edit_type_group_radiobutton.set_active(True) + if self.list_of_groups.has_key(rule_info['value']): + self.edit_type_group_combobox.set_active( + self.list_of_groups[rule_info['value']]) + else: + self.edit_type_group_combobox.set_active(0) + elif rule_info['type'] == 'subscription': + self.edit_type_subscription_radiobutton.set_active(True) + sub_value = rule_info['value'] + if sub_value == 'none': + self.edit_type_subscription_combobox.set_active(0) + elif sub_value == 'both': + self.edit_type_subscription_combobox.set_active(1) + elif sub_value == 'from': + self.edit_type_subscription_combobox.set_active(2) + elif sub_value == 'to': + self.edit_type_subscription_combobox.set_active(3) + else: + self.edit_type_select_all_radiobutton.set_active(True) + else: + self.edit_type_select_all_radiobutton.set_active(True) + self.edit_send_messages_checkbutton.set_active(False) + self.edit_queries_send_checkbutton.set_active(False) + self.edit_view_status_checkbutton.set_active(False) + self.edit_send_status_checkbutton.set_active(False) + for child in rule_info['child']: + if child == 'presence-out': + self.edit_send_status_checkbutton.set_active(True) + elif child == 'presence-in': + self.edit_view_status_checkbutton.set_active(True) + elif child == 'iq': + self.edit_queries_send_checkbutton.set_active(True) + elif child == 'message': + self.edit_send_messages_checkbutton.set_active(True) + + if rule_info['action'] == 'allow': + self.edit_allow_radiobutton.set_active(True) + else: + self.edit_deny_radiobutton.set_active(True) + self.add_edit_vbox.show() + + def on_privacy_list_active_checkbutton_toggled(self, widget): + if widget.get_active(): + gajim.connections[self.account].set_active_list(self.privacy_list) + else: + gajim.connections[self.account].set_active_list(None) + + def on_privacy_list_default_checkbutton_toggled(self, widget): + if widget.get_active(): + gajim.connections[self.account].set_default_list(self.privacy_list) + else: + gajim.connections[self.account].set_default_list(None) + + def on_new_rule_button_clicked(self, widget): + self.reset_fields() + self.add_edit_vbox.show() + + def reset_fields(self): + self.edit_type_jabberid_entry.set_text('') + self.edit_allow_radiobutton.set_active(True) + self.edit_type_jabberid_radiobutton.set_active(True) + self.active_rule = '' + self.edit_send_messages_checkbutton.set_active(False) + self.edit_queries_send_checkbutton.set_active(False) + self.edit_view_status_checkbutton.set_active(False) + self.edit_send_status_checkbutton.set_active(False) + self.edit_order_spinbutton.set_value(1) + self.edit_type_group_combobox.set_active(0) + self.edit_type_subscription_combobox.set_active(0) + self.add_edit_rule_label.set_label( + _('Add a rule')) + + def get_current_tags(self): + if self.edit_type_jabberid_radiobutton.get_active(): + edit_type = 'jid' + edit_value = \ + self.edit_type_jabberid_entry.get_text().decode('utf-8') + elif self.edit_type_group_radiobutton.get_active(): + edit_type = 'group' + edit_value = \ + self.edit_type_group_combobox.get_active_text().decode('utf-8') + elif self.edit_type_subscription_radiobutton.get_active(): + edit_type = 'subscription' + edit_value = self.edit_type_subscription_combobox.get_active_text() + elif self.edit_type_select_all_radiobutton.get_active(): + edit_type = '' + edit_value = '' + edit_order = str(self.edit_order_spinbutton.get_value_as_int()) + if self.edit_allow_radiobutton.get_active(): + edit_deny = 'allow' + else: + edit_deny = 'deny' + child = [] + if self.edit_send_messages_checkbutton.get_active(): + child.append('message') + if self.edit_queries_send_checkbutton.get_active(): + child.append('iq') + if self.edit_send_status_checkbutton.get_active(): + child.append('presence-out') + if self.edit_view_status_checkbutton.get_active(): + child.append('presence-in') + if edit_type != '': + return {'order': edit_order, 'action': edit_deny, + 'type': edit_type, 'value': edit_value, 'child': child} + return {'order': edit_order, 'action': edit_deny, 'child': child} + + def on_save_rule_button_clicked(self, widget): + tags=[] + current_tags = self.get_current_tags() + if self.active_rule == '': + tags.append(current_tags) + + for rule in self.global_rules: + if rule != self.active_rule: + tags.append(self.global_rules[rule]) + else: + tags.append(current_tags) + + gajim.connections[self.account].set_privacy_list(self.privacy_list, tags) + self.privacy_list_received(tags) + self.add_edit_vbox.hide() + + def on_list_of_rules_combobox_changed(self, widget): + self.add_edit_vbox.hide() + + def on_edit_type_radiobutton_changed(self, widget, radiobutton): + active_bool = widget.get_active() + if active_bool: + self.edit_rule_type = radiobutton + + def on_edit_allow_radiobutton_changed(self, widget, radiobutton): + active_bool = widget.get_active() + if active_bool: + self.allow_deny = radiobutton + + def on_privacy_list_close_button_clicked(self, widget): + self.window.destroy() + + def on_privacy_list_refresh_button_clicked(self, widget): + self.refresh_rules() + self.add_edit_vbox.hide() + +class PrivacyListsWindow: +# To do: UTF-8 ??????? + def __init__(self, account): + self.account = account + + self.privacy_lists = [] + + self.privacy_lists_save = [] + + self.xml = gtkgui_helpers.get_glade('privacy_lists_first_window.glade') + + self.window = self.xml.get_widget('privacy_lists_first_window') + for widget_to_add in ['list_of_privacy_lists_combobox', + 'delete_privacy_list_button', 'open_privacy_list_button', + 'new_privacy_list_button', 'new_privacy_list_entry', 'buttons_hbox', + 'privacy_lists_refresh_button', 'close_privacy_lists_window_button']: + self.__dict__[widget_to_add] = self.xml.get_widget(widget_to_add) + + self.privacy_lists_refresh() + + self.enabled = True + + if len(gajim.connections) > 1: + title = _('Privacy Lists for %s') % self.account + else: + title = _('Privacy Lists') + + self.window.set_title(title) + + self.window.show_all() + + self.xml.signal_autoconnect(self) + + def on_privacy_lists_first_window_destroy(self, widget): + '''close window''' + if gajim.interface.instances[self.account].has_key('privacy_lists'): + del gajim.interface.instances[self.account]['privacy_lists'] + + def draw_privacy_lists_in_combobox(self): + self.list_of_privacy_lists_combobox.set_active(-1) + self.list_of_privacy_lists_combobox.get_model().clear() + self.privacy_lists_save = self.privacy_lists + for add_item in self.privacy_lists: + self.list_of_privacy_lists_combobox.append_text(add_item) + if len(self.privacy_lists) == 0: + self.list_of_privacy_lists_combobox.set_sensitive(False) + self.buttons_hbox.set_sensitive(False) + elif len(self.privacy_lists) == 1: + self.list_of_privacy_lists_combobox.set_active(0) + self.list_of_privacy_lists_combobox.set_sensitive(False) + self.buttons_hbox.set_sensitive(True) + else: + self.list_of_privacy_lists_combobox.set_sensitive(True) + self.buttons_hbox.set_sensitive(True) + self.list_of_privacy_lists_combobox.set_active(0) + self.privacy_lists = [] + + def on_privacy_lists_refresh_button_clicked(self, widget): + self.privacy_lists_refresh() + + def on_close_button_clicked(self, widget): + self.window.destroy() + + def on_delete_privacy_list_button_clicked(self, widget): + active_list = self.privacy_lists_save[ + self.list_of_privacy_lists_combobox.get_active()] + gajim.connections[self.account].del_privacy_list(active_list) + self.privacy_lists_save.remove(active_list) + self.privacy_lists_received({'lists':self.privacy_lists_save}) + + def privacy_lists_received(self, lists): + if not lists: + return + for privacy_list in lists['lists']: + self.privacy_lists += [privacy_list] + self.draw_privacy_lists_in_combobox() + + def privacy_lists_refresh(self): + gajim.connections[self.account].get_privacy_lists() + + def on_new_privacy_list_button_clicked(self, widget): + name = self.new_privacy_list_entry.get_text().decode('utf-8') + if gajim.interface.instances[self.account].has_key( + 'privacy_list_%s' % name): + gajim.interface.instances[self.account]['privacy_list_%s' % name].\ + window.present() + else: + gajim.interface.instances[self.account]['privacy_list_%s' % name] = \ + PrivacyListWindow(self.account, name, 0) + self.new_privacy_list_entry.set_text('') + + def on_privacy_lists_refresh_button_clicked(self, widget): + self.privacy_lists_refresh() + + def on_open_privacy_list_button_clicked(self, widget): + name = self.privacy_lists_save[ + self.list_of_privacy_lists_combobox.get_active()] + if gajim.interface.instances[self.account].has_key( + 'privacy_list_%s' % name): + gajim.interface.instances[self.account]['privacy_list_%s' % name].\ + window.present() + else: + gajim.interface.instances[self.account]['privacy_list_%s' % name] = \ + PrivacyListWindow(self.account, name, 1) + class InvitationReceivedDialog: def __init__(self, account, room_jid, contact_jid, password = None, comment = None): @@ -1584,7 +1975,7 @@ class InvitationReceivedDialog: self.account = account xml = gtkgui_helpers.get_glade('invitation_received_dialog.glade') self.dialog = xml.get_widget('invitation_received_dialog') - + #FIXME: use nickname instead of contact_jid pritext = _('%(contact_jid)s has invited you to %(room_jid)s room') % { 'room_jid': room_jid, 'contact_jid': contact_jid } diff --git a/src/gajim.py b/src/gajim.py index a1618fdc9..35e65d7cf 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -1336,6 +1336,31 @@ class Interface: def handle_event_metacontacts(self, account, tags_list): gajim.contacts.define_metacontacts(account, tags_list) + def handle_event_privacy_lists_received(self, account, data): + # ('PRIVACY_LISTS_RECEIVED', account, list) + if not self.instances.has_key(account): + return + if self.instances[account].has_key('privacy_lists'): + self.instances[account]['privacy_lists'].privacy_lists_received(data) + + def handle_event_privacy_list_received(self, account, data): + # ('PRIVACY_LISTS_RECEIVED', account, (name, rules)) + if not self.instances.has_key(account): + return + name = data[0] + rules = data[1] + if self.instances[account].has_key('privacy_list_%s' % name): + self.instances[account]['privacy_list_%s' % name].\ + privacy_list_received(rules) + + def handle_event_privacy_lists_active_default(self, account, data): + if not data: + return + # Send to all privacy_list_* windows as we can't know which one asked + for win in self.instances[account]: + if win.startswith('privacy_list_'): + self.instances[account][win].check_active_default(data) + def read_sleepy(self): '''Check idle status and change that status if needed''' if not self.sleeper.poll(): @@ -1636,6 +1661,10 @@ class Interface: 'ASK_NEW_NICK': self.handle_event_ask_new_nick, 'SIGNED_IN': self.handle_event_signed_in, 'METACONTACTS': self.handle_event_metacontacts, + 'PRIVACY_LISTS_RECEIVED': self.handle_event_privacy_lists_received, + 'PRIVACY_LIST_RECEIVED': self.handle_event_privacy_list_received, + 'PRIVACY_LISTS_ACTIVE_DEFAULT': \ + self.handle_event_privacy_lists_active_default, } gajim.handlers = self.handlers diff --git a/src/roster_window.py b/src/roster_window.py index 9f5d46b0e..c6f18670e 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -584,6 +584,13 @@ class RosterWindow: gajim.interface.instances[account]['xml_console'] = \ dialogs.XMLConsoleWindow(account) + def on_privacy_lists_menuitem_activate(self, widget, account): + if gajim.interface.instances[account].has_key('privacy_lists'): + gajim.interface.instances[account]['privacy_lists'].window.present() + else: + gajim.interface.instances[account]['privacy_lists'] = \ + dialogs.PrivacyListsWindow(account) + def on_set_motd_menuitem_activate(self, widget, account): server = gajim.config.get_per('accounts', account, 'hostname') server += '/announce/motd' @@ -619,6 +626,7 @@ class RosterWindow: send_single_message_menuitem = xml.get_widget( 'send_single_message_menuitem') xml_console_menuitem = xml.get_widget('xml_console_menuitem') + privacy_lists_menuitem = xml.get_widget('privacy_lists_menuitem') administrator_menuitem = xml.get_widget('administrator_menuitem') send_server_message_menuitem = xml.get_widget( 'send_server_message_menuitem') @@ -632,6 +640,9 @@ class RosterWindow: xml_console_menuitem.connect('activate', self.on_xml_console_menuitem_activate, account) + privacy_lists_menuitem.connect('activate', + self.on_privacy_lists_menuitem_activate, account) + send_server_message_menuitem.connect('activate', self.on_send_server_message_menuitem_activate, account)