diff --git a/data/glade/advanced_menuitem_menu.glade b/data/glade/advanced_menuitem_menu.glade index 93d21d083..c15a28ce3 100644 --- a/data/glade/advanced_menuitem_menu.glade +++ b/data/glade/advanced_menuitem_menu.glade @@ -11,7 +11,7 @@ True - + True gtk-new 1 @@ -31,6 +31,15 @@ + + + True + _Blocked Contacts + True + + + + _Privacy Lists @@ -58,7 +67,7 @@ True - + True gtk-new 1 @@ -100,7 +109,7 @@ True - + True gtk-clear 1 diff --git a/data/glade/blocked_contacts_window.glade b/data/glade/blocked_contacts_window.glade new file mode 100644 index 000000000..9c22f40bc --- /dev/null +++ b/data/glade/blocked_contacts_window.glade @@ -0,0 +1,84 @@ + + + + + + + True + Blocked Contacts + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + 5 + True + False + 0 + + + + 3 + 250 + 300 + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + True + False + True + False + False + False + + + + + 0 + True + True + + + + + + 3 + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + + diff --git a/data/glade/roster_contact_context_menu.glade b/data/glade/roster_contact_context_menu.glade index e92be9686..68af27275 100644 --- a/data/glade/roster_contact_context_menu.glade +++ b/data/glade/roster_contact_context_menu.glade @@ -12,7 +12,7 @@ True - + True gtk-jump-to 1 @@ -32,7 +32,7 @@ True - + True gtk-go-up 1 @@ -52,7 +52,7 @@ True - + True gtk-new 1 @@ -72,7 +72,7 @@ True - + True gtk-go-back 1 @@ -91,7 +91,7 @@ True - + True gtk-refresh 1 @@ -111,6 +111,48 @@ + + + True + _Block + True + + + + + True + gtk-stop + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _Unblock + True + + + + + True + gtk-stop + 1 + 0.5 + 0.5 + 0 + 0 + + + + + True @@ -124,7 +166,7 @@ True - + True gtk-file 1 @@ -144,7 +186,7 @@ - + True gtk-dialog-authentication 1 @@ -164,7 +206,7 @@ True - + True gtk-info 1 @@ -184,7 +226,7 @@ True - + True gtk-execute 1 @@ -209,7 +251,7 @@ True - + True gtk-dialog-question 1 @@ -230,7 +272,7 @@ True - + True gtk-go-up 1 @@ -250,7 +292,7 @@ True - + True gtk-go-down 1 @@ -270,7 +312,7 @@ True - + True gtk-stop 1 @@ -293,7 +335,7 @@ True - + True gtk-add 1 @@ -312,7 +354,7 @@ True - + True gtk-remove 1 @@ -344,7 +386,7 @@ True - + True gtk-justify-fill 1 diff --git a/po/fr.po b/po/fr.po index 97f63577c..c649e2c9e 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6504,6 +6504,21 @@ msgstr "[Ce message est chiffré]" msgid "Error while adding service. %s" msgstr "Erreur en ajoutant le service. %s" +msgid "_Blocked Contacts" +msgstr "Contacts _Bloqués" + +msgid "Blocked Contacts for %s" +msgstr "Contacts Bloqués avec le compte %s" + +msgid "Blocked Contacts" +msgstr "Contacts Bloqués" + +msgid "_Block" +msgstr "_Bloquer" + +msgid "_Unblock" +msgstr "_Débloquer" + #~ msgid "2003-12-13T18:30:02Z" #~ msgstr "2003-12-13T18:30:02Z" #~ msgid "Romeo and Juliet" diff --git a/src/common/connection.py b/src/common/connection.py index 86d4bb23d..e14cb6fab 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -87,6 +87,9 @@ class Connection(ConnectionHandlers): else: self.keepalives = 0 self.privacy_rules_supported = False + self.blocked_list = [] + self.blocked_contacts = [] + self.blocked_groups = [] self.pep_supported = False # Do we continue connection when we get roster (send presence,get vcard...) self.continue_connect_info = None @@ -741,7 +744,7 @@ class Connection(ConnectionHandlers): msg = '' keyID = gajim.config.get_per('accounts', self.name, 'keyid') if show == 'offline': - p = common.xmpp.Presence(typ = 'unavailable') + p = common.xmpp.Presence(typ = 'unavailable', to = jid) p = self.add_sha(p, False) if msg: p.setStatus(msg) diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index b8a064ce1..ea2ef6694 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -1051,6 +1051,7 @@ class ConnectionVcard: elif self.awaiting_answers[id][0] == PRIVACY_ARRIVED: if iq_obj.getType() != 'error': self.privacy_rules_supported = True + self.get_privacy_list('block') # Ask metacontacts before roster self.get_metacontacts() diff --git a/src/dialogs.py b/src/dialogs.py index a5bf43f5d..6a3388450 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -2276,7 +2276,7 @@ class PrivacyListWindow: gajim.connections[self.account].set_privacy_list( self.privacy_list_name, tags) - self.privacy_list_received(tags) + self.refresh_rules() self.add_edit_vbox.hide() if 'privacy_lists' in gajim.interface.instances[self.account]: win = gajim.interface.instances[self.account]['privacy_lists'] @@ -2299,6 +2299,78 @@ class PrivacyListWindow: def on_close_button_clicked(self, widget): self.window.destroy() +class BlockedContactsWindow: + '''Window that is the main window for ContactWindows;''' + def __init__(self, account): + self.account = account + self.xml = gtkgui_helpers.get_glade('blocked_contacts_window.glade') + self.window = self.xml.get_widget('blocked_contacts_window') + self.remove_button = self.xml.get_widget('remove_button') + self.contacts_treeview = self.xml.get_widget('contacts_treeview') + renderer = gtk.CellRendererText() + + + self.store = gtk.ListStore(str) + self.contacts_treeview.set_model(self.store) + + column = gtk.TreeViewColumn("Contact", renderer, text=0) + self.contacts_treeview.append_column(column) + + if len(gajim.connections) > 1: + title = _('Blocked Contacts for %s') % self.account + else: + title = _('Blocked Contacts') + self.window.set_title(title) + + self.window.show_all() + self.xml.signal_autoconnect(self) + gajim.connections[self.account].get_privacy_list('block') + + def on_blocked_contacts_window_destroy(self, widget): + key_name = 'blocked_contacts' + if key_name in gajim.interface.instances[self.account]: + del gajim.interface.instances[self.account][key_name] + + def on_remove_button_clicked(self, widget): + tags=[] + rule_selected = self.store.get_path( + self.contacts_treeview.get_selection().get_selected()[1])[0] + for i in range(0,len(self.global_rules)): + if i != rule_selected: + tags.append(self.global_rules[i]) + for rule in self.global_rules_to_append: + tags.append(rule) + gajim.connections[self.account].set_privacy_list( + 'block', tags) + gajim.connections[self.account].set_active_list('block') + gajim.connections[self.account].set_default_list('block') + gajim.connections[self.account].get_privacy_list('block') + if len(tags) == 0: + self.privacy_list_received([]) + gajim.connections[self.account].blocked_contacts = [] + gajim.connections[self.account].blocked_list = [] + gajim.connections[self.account].set_default_list('') + gajim.connections[self.account].set_active_list('') + gajim.connections[self.account].del_privacy_list('block') + + + def privacy_list_received(self, rules): + self.store.clear() + self.global_rules = [] + self.global_rules_to_append = [] + for rule in rules: + if rule['type'] == "jid" and rule['action'] == "deny": + #self.global_rules[text_item] = rule + self.store.append([rule['value']]) + self.global_rules.append(rule) + elif rule['type'] == "group" and rule['action'] == "deny": + text_item = _('Group %s') % rule['value'] + self.store.append([text_item]) + self.global_rules.append(rule) + else: + self.global_rules_to_append.append(rule) + + class PrivacyListsWindow: '''Window that is the main window for Privacy Lists; we can list there the privacy lists and ask to create a new one diff --git a/src/gajim.py b/src/gajim.py index 20308e5ae..cfcd4340d 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -1620,6 +1620,25 @@ class Interface: if self.instances[account].has_key('privacy_list_%s' % name): self.instances[account]['privacy_list_%s' % name].\ privacy_list_received(rules) + if name == 'block': + gajim.connections[account].blocked_contacts = [] + gajim.connections[account].blocked_groups = [] + gajim.connections[account].blocked_list = [] + for rule in rules: + if rule['type'] == 'jid' and rule['action'] == 'deny': + gajim.connections[account].blocked_contacts.append(rule['value']) + if rule['type'] == 'group' and rule['action'] == 'deny': + gajim.connections[account].blocked_groups.append(rule['value']) + gajim.connections[account].blocked_list.append(rule) + #elif rule['type'] == "group" and action == "deny": + # text_item = _('%s group "%s"') % _(rule['action']), rule['value'] + # self.store.append([text_item]) + # self.global_rules.append(rule) + #else: + # self.global_rules_to_append.append(rule) + if self.instances[account].has_key('blocked_contacts'): + self.instances[account]['blocked_contacts'].\ + privacy_list_received(rules) def handle_event_privacy_lists_active_default(self, account, data): if not data: diff --git a/src/roster_window.py b/src/roster_window.py index 53eecafc1..ac7c0d38e 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -730,6 +730,13 @@ class RosterWindow: else: gajim.interface.instances[account]['privacy_lists'] = \ dialogs.PrivacyListsWindow(account) + + def on_blocked_contacts_menuitem_activate(self, widget, account): + if gajim.interface.instances[account].has_key('blocked_contacts'): + gajim.interface.instances[account]['blocked_contacts'].window.present() + else: + gajim.interface.instances[account]['blocked_contacts'] = \ + dialogs.BlockedContactsWindow(account) def on_set_motd_menuitem_activate(self, widget, account): server = gajim.config.get_per('accounts', account, 'hostname') @@ -763,6 +770,7 @@ class RosterWindow: send_single_message_menuitem = xml.get_widget( 'send_single_message_menuitem') xml_console_menuitem = xml.get_widget('xml_console_menuitem') + blocked_contacts_menuitem = xml.get_widget('blocked_contacts_menuitem') privacy_lists_menuitem = xml.get_widget('privacy_lists_menuitem') administrator_menuitem = xml.get_widget('administrator_menuitem') send_server_message_menuitem = xml.get_widget( @@ -776,9 +784,12 @@ class RosterWindow: if gajim.connections[account] and gajim.connections[account].\ privacy_rules_supported: + blocked_contacts_menuitem.connect('activate', + self.on_blocked_contacts_menuitem_activate, account) privacy_lists_menuitem.connect('activate', self.on_privacy_lists_menuitem_activate, account) else: + blocked_contacts_menuitem.set_sensitive(False) privacy_lists_menuitem.set_sensitive(False) if gajim.connections[account].is_zeroconf: @@ -1413,6 +1424,97 @@ class RosterWindow: self.dialog = dialogs.ConfirmationDialog(pritext, sectext, on_response_ok = (remove, list_)) + def on_block(self, widget, iter, blockedlist): + model = self.tree.get_model() + accounts = [] + if blockedlist == None: + jid = model[iter][C_JID].decode('utf-8') + account = model[iter][C_ACCOUNT].decode('utf-8') + accounts.append(account) + msg = self.get_status_message('offline') + self.send_status(account, 'offline', msg, to = jid) + new_rule = {'order': u'1', 'type': u'jid', 'action': u'deny', + 'value' : jid, 'child': [u'message', u'iq', u'presence-out']} + else: + model = self.tree.get_model() + group = model[iter][C_JID].decode('utf-8') + msg = self.get_status_message('offline') + for (contact, account) in blockedlist: + if account not in accounts: + if gajim.connections[account].privacy_rules_supported: + accounts.append(account) + self.send_status(account, 'offline', msg, to = contact.jid) + else: + self.send_status(account, 'offline', msg, to = contact.jid) + new_rule = {'order': u'1', 'type': u'group', 'action': u'deny', + 'value' : group, 'child': [u'message', u'iq', u'presence-out']} + for account in accounts: + gajim.connections[account].blocked_list.append(new_rule) + gajim.connections[account].set_privacy_list( + 'block', gajim.connections[account].blocked_list) + if len(gajim.connections[account].blocked_list) == 1: + gajim.connections[account].set_active_list('block') + gajim.connections[account].set_default_list('block') + gajim.connections[account].get_privacy_list('block') + + def on_unblock(self, widget, iter, blockedlist): + model = self.tree.get_model() + accounts = [] + if blockedlist == None: + jid = model[iter][C_JID].decode('utf-8') + jid_account = model[iter][C_ACCOUNT].decode('utf-8') + accounts.append(jid_account) + gajim.connections[jid_account].new_blocked_list = [] + for rule in gajim.connections[jid_account].blocked_list: + if rule['action'] != 'deny' or rule['type'] != 'jid' or rule['value'] != jid: + gajim.connections[jid_account].new_blocked_list.append(rule) + else: + model = self.tree.get_model() + group = model[iter][C_JID].decode('utf-8') + for (contact, account) in blockedlist: + if account not in accounts: + if gajim.connections[account].privacy_rules_supported: + accounts.append(account) + gajim.connections[account].new_blocked_list = [] + for rule in gajim.connections[account].blocked_list: + if rule['action'] != 'deny' or rule['type'] != 'group' or rule['value'] != group: + gajim.connections[account].new_blocked_list.append(rule) + for account in accounts: + gajim.connections[account].set_privacy_list( + 'block', gajim.connections[account].new_blocked_list) + gajim.connections[account].get_privacy_list('block') + if len(gajim.connections[account].new_blocked_list) == 0: + gajim.connections[account].blocked_list = [] + gajim.connections[account].blocked_contacts = [] + gajim.connections[account].blocked_groups = [] + gajim.connections[account].set_default_list('') + gajim.connections[account].set_active_list('') + gajim.connections[account].del_privacy_list('block') + if blockedlist == None: + status = gajim.connections[jid_account].connected + msg = gajim.connections[jid_account].status + if not self.regroup: + show = gajim.SHOW_LIST[status] + else: # accounts merged + show = helpers.get_global_show() + self.send_status(jid_account, show, msg, to = jid) + else: + for (contact, account) in blockedlist: + if not self.regroup: + show = gajim.SHOW_LIST[gajim.connections[account].connected] + else: # accounts merged + show = helpers.get_global_show() + if account not in accounts: + if gajim.connections[account].privacy_rules_supported: + accounts.append(account) + self.send_status(account, show, + gajim.connections[account].status, to = contact.jid) + else: + self.send_status(account, show, + gajim.connections[account].status, to = contact.jid) + + + def on_rename(self, widget, iter, path): # this function is called either by F2 or by Rename menuitem if gajim.interface.instances.has_key('rename'): @@ -1739,6 +1841,8 @@ class RosterWindow: send_single_message_menuitem = xml.get_widget( 'send_single_message_menuitem') invite_menuitem = xml.get_widget('invite_menuitem') + block_menuitem = xml.get_widget('block_menuitem') + unblock_menuitem = xml.get_widget('unblock_menuitem') rename_menuitem = xml.get_widget('rename_menuitem') edit_groups_menuitem = xml.get_widget('edit_groups_menuitem') # separator has with send file, assign_openpgp_key_menuitem, etc.. @@ -1968,6 +2072,22 @@ class RosterWindow: remove_from_roster_menuitem, execute_command_menuitem]: widget.set_sensitive(False) + if gajim.connections[account] and gajim.connections[account].\ + privacy_rules_supported: + if jid in gajim.connections[account].blocked_contacts: + block_menuitem.set_no_show_all(True) + unblock_menuitem.connect('activate', self.on_unblock, iter, None) + block_menuitem.hide() + else: + unblock_menuitem.set_no_show_all(True) + block_menuitem.connect('activate', self.on_block, iter, None) + unblock_menuitem.hide() + else: + block_menuitem.set_no_show_all(True) + unblock_menuitem.set_no_show_all(True) + block_menuitem.hide() + unblock_menuitem.hide() + event_button = gtkgui_helpers.get_possible_button_event(event) roster_contact_context_menu.attach_to_widget(self.tree, None) @@ -2198,6 +2318,28 @@ class RosterWindow: status_menuitem.set_image(icon) status_menuitems.append(status_menuitem) menu.append(send_custom_status_menuitem) + is_blocked = False + if self.regroup: + for g_account in gajim.connections: + if group in gajim.connections[g_account].blocked_groups: + is_blocked = True + else: + if group in gajim.connections[account].blocked_groups: + is_blocked = True + + if group not in helpers.special_groups + (_('General'),): + if is_blocked: + unblock_menuitem = gtk.ImageMenuItem(_('_Unblock')) + icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU) + unblock_menuitem.set_image(icon) + unblock_menuitem.connect('activate', self.on_unblock, iter, list_) + menu.append(unblock_menuitem) + else: + block_menuitem = gtk.ImageMenuItem(_('_Block')) + icon = gtk.image_new_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_MENU) + block_menuitem.set_image(icon) + block_menuitem.connect('activate', self.on_block, iter, list_) + menu.append(block_menuitem) event_button = gtkgui_helpers.get_possible_button_event(event)