Philipp Hörist pushed to branch gajim_1.2 at gajim / gajim
Commits:
-
1448b59b
by wurstsalat at 2020-07-07T21:59:30+02:00
-
216eae42
by wurstsalat at 2020-07-07T21:59:30+02:00
-
a0810652
by wurstsalat at 2020-07-07T21:59:30+02:00
-
aad99763
by lovetox at 2020-07-07T21:59:30+02:00
-
e6ac4e4b
by lovetox at 2020-07-07T21:59:30+02:00
-
2362db29
by lovetox at 2020-07-07T21:59:30+02:00
-
2a3927f7
by lovetox at 2020-07-07T21:59:30+02:00
-
d16eaa93
by Daniel Brötzmann at 2020-07-07T21:59:30+02:00
-
ad93a76d
by lovetox at 2020-07-07T21:59:30+02:00
-
e5d7704d
by wurstsalat at 2020-07-07T21:59:30+02:00
-
8801e04a
by wurstsalat at 2020-07-07T21:59:30+02:00
-
0e405e2a
by lovetox at 2020-07-07T21:59:30+02:00
-
391256de
by wurstsalat at 2020-07-07T21:59:30+02:00
22 changed files:
- data/gajim.doap
- gajim/app_actions.py
- gajim/application.py
- gajim/chat_control.py
- gajim/chat_control_base.py
- gajim/command_system/implementation/standard.py
- gajim/common/app.py
- gajim/common/helpers.py
- gajim/common/logger.py
- gajim/common/modules/__init__.py
- gajim/common/modules/discovery.py
- gajim/common/modules/muc.py
- − gajim/common/modules/privacylists.py
- gajim/data/gui/preferences_window.ui
- gajim/dialog_messages.py
- gajim/groupchat_control.py
- gajim/gtk/const.py
- gajim/gtk/preferences.py
- − gajim/gtk/privacy_list.py
- gajim/gtk/server_info.py
- gajim/gui_menu_builder.py
- gajim/roster_window.py
Changes:
| ... | ... | @@ -46,13 +46,6 @@ |
| 46 | 46 |
<xmpp:version>2.9</xmpp:version>
|
| 47 | 47 |
</xmpp:SupportedXep>
|
| 48 | 48 |
</implements>
|
| 49 |
- <implements>
|
|
| 50 |
- <xmpp:SupportedXep>
|
|
| 51 |
- <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0016.html" />
|
|
| 52 |
- <xmpp:status>complete</xmpp:status>
|
|
| 53 |
- <xmpp:version>1.6</xmpp:version>
|
|
| 54 |
- </xmpp:SupportedXep>
|
|
| 55 |
- </implements>
|
|
| 56 | 49 |
<implements>
|
| 57 | 50 |
<xmpp:SupportedXep>
|
| 58 | 51 |
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0027.html" />
|
| ... | ... | @@ -546,6 +539,14 @@ |
| 546 | 539 |
<xmpp:note>OpenPGP plugin.</xmpp:note>
|
| 547 | 540 |
</xmpp:SupportedXep>
|
| 548 | 541 |
</implements>
|
| 542 |
+ <implements>
|
|
| 543 |
+ <xmpp:SupportedXep>
|
|
| 544 |
+ <xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0377.html" />
|
|
| 545 |
+ <xmpp:status>partial</xmpp:status>
|
|
| 546 |
+ <xmpp:version>0.2</xmpp:version>
|
|
| 547 |
+ <xmpp:note>Basic Spam/Abuse reporting via XEP-0191</xmpp:note>
|
|
| 548 |
+ </xmpp:SupportedXep>
|
|
| 549 |
+ </implements>
|
|
| 549 | 550 |
<implements>
|
| 550 | 551 |
<xmpp:SupportedXep>
|
| 551 | 552 |
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0380.html" />
|
| ... | ... | @@ -26,7 +26,6 @@ from gajim import dialogs |
| 26 | 26 |
from gajim.gtk.dialogs import ShortcutsWindow
|
| 27 | 27 |
from gajim.gtk.single_message import SingleMessageWindow
|
| 28 | 28 |
from gajim.gtk.about import AboutDialog
|
| 29 |
-from gajim.gtk.privacy_list import PrivacyListsWindow
|
|
| 30 | 29 |
from gajim.gtk.history import HistoryWindow
|
| 31 | 30 |
from gajim.gtk.discovery import ServiceDiscoveryWindow
|
| 32 | 31 |
from gajim.gtk.util import open_window
|
| ... | ... | @@ -171,15 +170,6 @@ def on_history_sync(_action, param): |
| 171 | 170 |
parent=interface.roster.window)
|
| 172 | 171 |
|
| 173 | 172 |
|
| 174 |
-def on_privacy_lists(_action, param):
|
|
| 175 |
- account = param.get_string()
|
|
| 176 |
- if 'privacy_lists' in interface.instances[account]:
|
|
| 177 |
- interface.instances[account]['privacy_lists'].window.present()
|
|
| 178 |
- else:
|
|
| 179 |
- interface.instances[account]['privacy_lists'] = \
|
|
| 180 |
- PrivacyListsWindow(account)
|
|
| 181 |
- |
|
| 182 |
- |
|
| 183 | 173 |
def on_server_info(_action, param):
|
| 184 | 174 |
account = param.get_string()
|
| 185 | 175 |
open_window('ServerInfo', account=account)
|
| ... | ... | @@ -473,7 +473,6 @@ class GajimApplication(Gtk.Application): |
| 473 | 473 |
('-archive', a.on_mam_preferences, 'feature', 's'),
|
| 474 | 474 |
('-pep-config', a.on_pep_config, 'online', 's'),
|
| 475 | 475 |
('-sync-history', a.on_history_sync, 'online', 's'),
|
| 476 |
- ('-privacylists', a.on_privacy_lists, 'feature', 's'),
|
|
| 477 | 476 |
('-blocking', a.on_blocking_list, 'feature', 's'),
|
| 478 | 477 |
('-send-server-message', a.on_send_server_message, 'online', 's'),
|
| 479 | 478 |
('-set-motd', a.on_set_motd, 'online', 's'),
|
| ... | ... | @@ -571,9 +570,6 @@ class GajimApplication(Gtk.Application): |
| 571 | 570 |
elif event.feature == Namespace.MAM_2:
|
| 572 | 571 |
action = '%s-archive' % event.account
|
| 573 | 572 |
self.lookup_action(action).set_enabled(True)
|
| 574 |
- elif event.feature == Namespace.PRIVACY:
|
|
| 575 |
- action = '%s-privacylists' % event.account
|
|
| 576 |
- self.lookup_action(action).set_enabled(True)
|
|
| 577 | 573 |
elif event.feature == Namespace.BLOCKING:
|
| 578 | 574 |
action = '%s-blocking' % event.account
|
| 579 | 575 |
self.lookup_action(action).set_enabled(True)
|
| ... | ... | @@ -251,8 +251,9 @@ class ChatControl(ChatControlBase): |
| 251 | 251 |
actions = [
|
| 252 | 252 |
('invite-contacts-', self._on_invite_contacts),
|
| 253 | 253 |
('add-to-roster-', self._on_add_to_roster),
|
| 254 |
+ ('block-contact-', self._on_block_contact),
|
|
| 254 | 255 |
('information-', self._on_information),
|
| 255 |
- ]
|
|
| 256 |
+ ]
|
|
| 256 | 257 |
|
| 257 | 258 |
for action in actions:
|
| 258 | 259 |
action_name, func = action
|
| ... | ... | @@ -300,6 +301,11 @@ class ChatControl(ChatControlBase): |
| 300 | 301 |
win.lookup_action(
|
| 301 | 302 |
'add-to-roster-' + self.control_id).set_enabled(False)
|
| 302 | 303 |
|
| 304 |
+ # Block contact
|
|
| 305 |
+ win.lookup_action(
|
|
| 306 |
+ 'block-contact-' + self.control_id).set_enabled(
|
|
| 307 |
+ online and con.get_module('Blocking').supported)
|
|
| 308 |
+ |
|
| 303 | 309 |
# Audio
|
| 304 | 310 |
win.lookup_action('toggle-audio-' + self.control_id).set_enabled(
|
| 305 | 311 |
online and self.jingle['audio'].available)
|
| ... | ... | @@ -376,6 +382,33 @@ class ChatControl(ChatControlBase): |
| 376 | 382 |
def _on_add_to_roster(self, _action, _param):
|
| 377 | 383 |
AddNewContactWindow(self.account, self.contact.jid)
|
| 378 | 384 |
|
| 385 |
+ def _on_block_contact(self, _action, _param):
|
|
| 386 |
+ def _block_contact(report=None):
|
|
| 387 |
+ con = app.connections[self.account]
|
|
| 388 |
+ con.get_module('Blocking').block([self.contact.jid], report=report)
|
|
| 389 |
+ |
|
| 390 |
+ self.parent_win.remove_tab(self, None, force=True)
|
|
| 391 |
+ if _('Not in contact list') in self.contact.get_shown_groups():
|
|
| 392 |
+ app.interface.roster.remove_contact(
|
|
| 393 |
+ self.contact.jid, self.account, force=True, backend=True)
|
|
| 394 |
+ return
|
|
| 395 |
+ app.interface.roster.draw_contact(self.contact.jid, self.account)
|
|
| 396 |
+ |
|
| 397 |
+ NewConfirmationDialog(
|
|
| 398 |
+ _('Block Contact'),
|
|
| 399 |
+ _('Really block this contact?'),
|
|
| 400 |
+ _('You will appear offline for this contact and you will '
|
|
| 401 |
+ 'not receive further messages.'),
|
|
| 402 |
+ [DialogButton.make('Cancel'),
|
|
| 403 |
+ DialogButton.make('OK',
|
|
| 404 |
+ text=_('_Report Spam'),
|
|
| 405 |
+ callback=_block_contact,
|
|
| 406 |
+ kwargs={'report': 'spam'}),
|
|
| 407 |
+ DialogButton.make('Remove',
|
|
| 408 |
+ text=_('_Block'),
|
|
| 409 |
+ callback=_block_contact)],
|
|
| 410 |
+ modal=False).show()
|
|
| 411 |
+ |
|
| 379 | 412 |
def _on_information(self, _action, _param):
|
| 380 | 413 |
app.interface.roster.on_info(None, self.contact, self.account)
|
| 381 | 414 |
|
| ... | ... | @@ -802,37 +835,15 @@ class ChatControl(ChatControlBase): |
| 802 | 835 |
name, jid
|
| 803 | 836 |
"""
|
| 804 | 837 |
contact = self.contact
|
| 805 |
- jid = contact.jid
|
|
| 806 |
- |
|
| 807 | 838 |
name = contact.get_shown_name()
|
| 808 | 839 |
if self.resource:
|
| 809 | 840 |
name += '/' + self.resource
|
| 810 | 841 |
if self._type.is_privatechat:
|
| 811 |
- name = i18n.direction_mark + _(
|
|
| 842 |
+ name = i18n.direction_mark + _(
|
|
| 812 | 843 |
'%(nickname)s from group chat %(room_name)s') % \
|
| 813 | 844 |
{'nickname': name, 'room_name': self.room_name}
|
| 814 | 845 |
name = i18n.direction_mark + GLib.markup_escape_text(name)
|
| 815 | 846 |
|
| 816 |
- # We know our contacts nick, but if another contact has the same nick
|
|
| 817 |
- # in another account we need to also display the account.
|
|
| 818 |
- # except if we are talking to two different resources of the
|
|
| 819 |
- # same contact
|
|
| 820 |
- acct_info = ''
|
|
| 821 |
- for account in app.contacts.get_accounts():
|
|
| 822 |
- if account == self.account:
|
|
| 823 |
- continue
|
|
| 824 |
- if acct_info: # We already found a contact with same nick
|
|
| 825 |
- break
|
|
| 826 |
- for jid in app.contacts.get_jid_list(account):
|
|
| 827 |
- other_contact_ = \
|
|
| 828 |
- app.contacts.get_first_contact_from_jid(account, jid)
|
|
| 829 |
- if other_contact_.get_shown_name() == \
|
|
| 830 |
- self.contact.get_shown_name():
|
|
| 831 |
- acct_info = i18n.direction_mark + ' (%s)' % \
|
|
| 832 |
- GLib.markup_escape_text(
|
|
| 833 |
- app.get_account_label(self.account))
|
|
| 834 |
- break
|
|
| 835 |
- |
|
| 836 | 847 |
status = contact.status
|
| 837 | 848 |
if status is not None:
|
| 838 | 849 |
status_reduced = helpers.reduce_chars_newlines(status, max_lines=1)
|
| ... | ... | @@ -849,17 +860,12 @@ class ChatControl(ChatControlBase): |
| 849 | 860 |
if app.config.get('show_chatstate_in_banner'):
|
| 850 | 861 |
chatstate = helpers.get_uf_chatstate(cs)
|
| 851 | 862 |
|
| 852 |
- label_text = '<span>%s</span><span size="x-small" weight="light">%s %s</span>' \
|
|
| 853 |
- % (name, acct_info, chatstate)
|
|
| 854 |
- if acct_info:
|
|
| 855 |
- acct_info = i18n.direction_mark + ' ' + acct_info
|
|
| 856 |
- label_tooltip = '%s%s %s' % (name, acct_info, chatstate)
|
|
| 863 |
+ label_text = '<span>%s</span><span size="x-small" weight="light"> %s</span>' % \
|
|
| 864 |
+ (name, chatstate)
|
|
| 865 |
+ label_tooltip = '%s %s' % (name, chatstate)
|
|
| 857 | 866 |
else:
|
| 858 |
- label_text = '<span>%s</span><span size="x-small" weight="light">%s</span>' % \
|
|
| 859 |
- (name, acct_info)
|
|
| 860 |
- if acct_info:
|
|
| 861 |
- acct_info = i18n.direction_mark + ' ' + acct_info
|
|
| 862 |
- label_tooltip = '%s%s' % (name, acct_info)
|
|
| 867 |
+ label_text = '<span>%s</span>' % name
|
|
| 868 |
+ label_tooltip = name
|
|
| 863 | 869 |
|
| 864 | 870 |
if status_escaped:
|
| 865 | 871 |
status_text = make_href_markup(status_escaped)
|
| ... | ... | @@ -1071,9 +1071,9 @@ class ChatControlBase(ChatCommandProcessor, CommandTools, EventHelper): |
| 1071 | 1071 |
else:
|
| 1072 | 1072 |
self.received_history_pos = pos
|
| 1073 | 1073 |
|
| 1074 |
- def add_info_message(self, text):
|
|
| 1074 |
+ def add_info_message(self, text, message_id=None):
|
|
| 1075 | 1075 |
self.conv_textview.print_conversation_line(
|
| 1076 |
- text, 'info', '', None, graphics=False)
|
|
| 1076 |
+ text, 'info', '', None, message_id=message_id, graphics=False)
|
|
| 1077 | 1077 |
|
| 1078 | 1078 |
def add_status_message(self, text):
|
| 1079 | 1079 |
self.conv_textview.print_conversation_line(
|
| ... | ... | @@ -308,10 +308,9 @@ class StandardGroupChatCommands(CommandContainer): |
| 308 | 308 |
@command(raw=True, empty=True)
|
| 309 | 309 |
@doc(_("Invite a user to a group chat for a reason"))
|
| 310 | 310 |
def invite(self, jid, reason):
|
| 311 |
- self.connection.get_module('MUC').invite(self.room_jid, jid, reason)
|
|
| 312 |
- return _("Invited %(jid)s to %(room_jid)s") % {
|
|
| 313 |
- 'jid': jid,
|
|
| 314 |
- 'room_jid': self.room_jid}
|
|
| 311 |
+ control = app.get_groupchat_control(self.account, self.room_jid)
|
|
| 312 |
+ if control is not None:
|
|
| 313 |
+ control.invite(jid)
|
|
| 315 | 314 |
|
| 316 | 315 |
@command(raw=True, empty=True)
|
| 317 | 316 |
@doc(_("Join a group chat given by an XMPP Address"))
|
| ... | ... | @@ -644,3 +644,12 @@ def get_stored_bob_data(algo_hash: str) -> Optional[bytes]: |
| 644 | 644 |
data = file.read()
|
| 645 | 645 |
return data
|
| 646 | 646 |
return None
|
| 647 |
+ |
|
| 648 |
+def get_groupchat_control(account, jid):
|
|
| 649 |
+ control = app.interface.msg_win_mgr.get_gc_control(jid, account)
|
|
| 650 |
+ if control is not None:
|
|
| 651 |
+ return control
|
|
| 652 |
+ try:
|
|
| 653 |
+ return app.interface.minimized_controls[account][jid]
|
|
| 654 |
+ except Exception:
|
|
| 655 |
+ return None
|
| ... | ... | @@ -833,14 +833,7 @@ def get_optional_features(account): |
| 833 | 833 |
|
| 834 | 834 |
def jid_is_blocked(account, jid):
|
| 835 | 835 |
con = app.connections[account]
|
| 836 |
- return (jid in con.get_module('Blocking').blocked or
|
|
| 837 |
- jid in con.get_module('PrivacyLists').blocked_contacts or
|
|
| 838 |
- con.get_module('PrivacyLists').blocked_all)
|
|
| 839 |
- |
|
| 840 |
-def group_is_blocked(account, group):
|
|
| 841 |
- con = app.connections[account]
|
|
| 842 |
- return (group in con.get_module('PrivacyLists').blocked_groups or
|
|
| 843 |
- con.get_module('PrivacyLists').blocked_all)
|
|
| 836 |
+ return jid in con.get_module('Blocking').blocked
|
|
| 844 | 837 |
|
| 845 | 838 |
def get_subscription_request_msg(account=None):
|
| 846 | 839 |
s = app.config.get_per('accounts', account, 'subscription_request_msg')
|
| ... | ... | @@ -526,9 +526,9 @@ class Logger: |
| 526 | 526 |
return [user['jid'] for user in family]
|
| 527 | 527 |
return [jid]
|
| 528 | 528 |
|
| 529 |
- def get_account_id(self, account):
|
|
| 529 |
+ def get_account_id(self, account, type_=JIDConstant.NORMAL_TYPE):
|
|
| 530 | 530 |
jid = app.get_jid_from_account(account)
|
| 531 |
- return self.get_jid_id(jid, type_=JIDConstant.NORMAL_TYPE)
|
|
| 531 |
+ return self.get_jid_id(jid, type_=type_)
|
|
| 532 | 532 |
|
| 533 | 533 |
@timeit
|
| 534 | 534 |
def get_jid_id(self, jid, kind=None, type_=None):
|
| ... | ... | @@ -755,6 +755,26 @@ class Logger: |
| 755 | 755 |
all_messages.append((result, shown))
|
| 756 | 756 |
return all_messages
|
| 757 | 757 |
|
| 758 |
+ def load_groupchat_messages(self, account, jid):
|
|
| 759 |
+ account_id = self.get_account_id(account, type_=JIDConstant.ROOM_TYPE)
|
|
| 760 |
+ |
|
| 761 |
+ sql = '''
|
|
| 762 |
+ SELECT time, contact_name, message, additional_data, message_id
|
|
| 763 |
+ FROM logs NATURAL JOIN jids WHERE jid = ?
|
|
| 764 |
+ AND account_id = ? AND kind = ?
|
|
| 765 |
+ ORDER BY time DESC, log_line_id DESC LIMIT ?'''
|
|
| 766 |
+ |
|
| 767 |
+ try:
|
|
| 768 |
+ messages = self._con.execute(
|
|
| 769 |
+ sql, (jid, account_id, KindConstant.GC_MSG, 50)).fetchall()
|
|
| 770 |
+ except sqlite.DatabaseError:
|
|
| 771 |
+ self.dispatch('DB_ERROR',
|
|
| 772 |
+ exceptions.DatabaseMalformed(self._log_db_path))
|
|
| 773 |
+ return []
|
|
| 774 |
+ |
|
| 775 |
+ messages.reverse()
|
|
| 776 |
+ return messages
|
|
| 777 |
+ |
|
| 758 | 778 |
@timeit
|
| 759 | 779 |
def get_last_conversation_lines(self, account, jid, pending):
|
| 760 | 780 |
"""
|
| ... | ... | @@ -56,7 +56,6 @@ MODULES = [ |
| 56 | 56 |
'pep',
|
| 57 | 57 |
'ping',
|
| 58 | 58 |
'presence',
|
| 59 |
- 'privacylists',
|
|
| 60 | 59 |
'pubsub',
|
| 61 | 60 |
'receipts',
|
| 62 | 61 |
'register',
|
| ... | ... | @@ -99,11 +98,6 @@ class ModuleMock: |
| 99 | 98 |
# Blocking
|
| 100 | 99 |
self.blocked = [] # type: List[Any]
|
| 101 | 100 |
|
| 102 |
- # Privacy Lists
|
|
| 103 |
- self.blocked_contacts = [] # type: List[Any]
|
|
| 104 |
- self.blocked_groups = [] # type: List[Any]
|
|
| 105 |
- self.blocked_all = False
|
|
| 106 |
- |
|
| 107 | 101 |
# Delimiter
|
| 108 | 102 |
self.delimiter = '::'
|
| 109 | 103 |
|
| ... | ... | @@ -137,7 +137,6 @@ class Discovery(BaseModule): |
| 137 | 137 |
self._con.get_module('Blocking').pass_disco(result)
|
| 138 | 138 |
self._con.get_module('VCardTemp').pass_disco(result)
|
| 139 | 139 |
self._con.get_module('Carbons').pass_disco(result)
|
| 140 |
- self._con.get_module('PrivacyLists').pass_disco(result)
|
|
| 141 | 140 |
self._con.get_module('HTTPUpload').pass_disco(result)
|
| 142 | 141 |
|
| 143 | 142 |
if Namespace.REGISTER in result.features:
|
| ... | ... | @@ -777,7 +777,8 @@ class MUC(BaseModule): |
| 777 | 777 |
|
| 778 | 778 |
password = app.gc_passwords.get(room, None)
|
| 779 | 779 |
self._log.info('Invite %s to %s', to, room)
|
| 780 |
- self._nbxmpp('MUC').invite(room, to, reason, password, continue_, type_)
|
|
| 780 |
+ return self._nbxmpp('MUC').invite(room, to, reason, password,
|
|
| 781 |
+ continue_, type_)
|
|
| 781 | 782 |
|
| 782 | 783 |
@event_filter(['account'])
|
| 783 | 784 |
def _on_account_disconnected(self, _event):
|
| 1 |
-# This file is part of Gajim.
|
|
| 2 |
-#
|
|
| 3 |
-# Gajim is free software; you can redistribute it and/or modify
|
|
| 4 |
-# it under the terms of the GNU General Public License as published
|
|
| 5 |
-# by the Free Software Foundation; version 3 only.
|
|
| 6 |
-#
|
|
| 7 |
-# Gajim is distributed in the hope that it will be useful,
|
|
| 8 |
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 9 |
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 10 |
-# GNU General Public License for more details.
|
|
| 11 |
-#
|
|
| 12 |
-# You should have received a copy of the GNU General Public License
|
|
| 13 |
-# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
| 14 |
- |
|
| 15 |
-# XEP-0016: Privacy Lists
|
|
| 16 |
- |
|
| 17 |
-import nbxmpp
|
|
| 18 |
-from nbxmpp.namespaces import Namespace
|
|
| 19 |
-from nbxmpp.structs import StanzaHandler
|
|
| 20 |
- |
|
| 21 |
-from gajim.common import app
|
|
| 22 |
-from gajim.common import helpers
|
|
| 23 |
-from gajim.common.nec import NetworkEvent
|
|
| 24 |
-from gajim.common.nec import NetworkIncomingEvent
|
|
| 25 |
-from gajim.common.modules.base import BaseModule
|
|
| 26 |
-from gajim.common.connection_handlers_events import InformationEvent
|
|
| 27 |
- |
|
| 28 |
- |
|
| 29 |
-class PrivacyLists(BaseModule):
|
|
| 30 |
- def __init__(self, con):
|
|
| 31 |
- BaseModule.__init__(self, con)
|
|
| 32 |
- |
|
| 33 |
- self.default_list = None
|
|
| 34 |
- self.active_list = None
|
|
| 35 |
- self.blocked_contacts = []
|
|
| 36 |
- self.blocked_groups = []
|
|
| 37 |
- self.blocked_list = []
|
|
| 38 |
- self.blocked_all = False
|
|
| 39 |
- |
|
| 40 |
- self.handlers = [
|
|
| 41 |
- StanzaHandler(name='iq',
|
|
| 42 |
- callback=self._list_push_received,
|
|
| 43 |
- typ='set',
|
|
| 44 |
- ns=Namespace.PRIVACY),
|
|
| 45 |
- ]
|
|
| 46 |
- |
|
| 47 |
- self.supported = False
|
|
| 48 |
- |
|
| 49 |
- def pass_disco(self, info):
|
|
| 50 |
- if Namespace.PRIVACY not in info.features:
|
|
| 51 |
- return
|
|
| 52 |
- |
|
| 53 |
- self.supported = True
|
|
| 54 |
- self._log.info('Discovered XEP-0016: Privacy Lists: %s', info.jid)
|
|
| 55 |
- |
|
| 56 |
- app.nec.push_incoming_event(
|
|
| 57 |
- NetworkEvent('feature-discovered',
|
|
| 58 |
- account=self._account,
|
|
| 59 |
- feature=Namespace.PRIVACY))
|
|
| 60 |
- |
|
| 61 |
- def _list_push_received(self, _con, stanza, _properties):
|
|
| 62 |
- result = stanza.buildReply('result')
|
|
| 63 |
- result.delChild(result.getTag('query'))
|
|
| 64 |
- self._con.connection.send(result)
|
|
| 65 |
- |
|
| 66 |
- for list_ in stanza.getQueryPayload():
|
|
| 67 |
- if list_.getName() == 'list':
|
|
| 68 |
- name = list_.getAttr('name')
|
|
| 69 |
- self._log.info('Received Push: %s', name)
|
|
| 70 |
- self.get_privacy_list(name)
|
|
| 71 |
- |
|
| 72 |
- raise nbxmpp.NodeProcessed
|
|
| 73 |
- |
|
| 74 |
- def get_privacy_lists(self, callback=None):
|
|
| 75 |
- self._log.info('Request lists')
|
|
| 76 |
- iq = nbxmpp.Iq('get', Namespace.PRIVACY)
|
|
| 77 |
- self._con.connection.SendAndCallForResponse(
|
|
| 78 |
- iq, self._privacy_lists_received, {'callback': callback})
|
|
| 79 |
- |
|
| 80 |
- def _privacy_lists_received(self, _nbxmpp_client, stanza, callback):
|
|
| 81 |
- lists = []
|
|
| 82 |
- new_default = None
|
|
| 83 |
- result = nbxmpp.isResultNode(stanza)
|
|
| 84 |
- if not result:
|
|
| 85 |
- self._log.warning('List not available: %s', stanza.getError())
|
|
| 86 |
- else:
|
|
| 87 |
- for list_ in stanza.getQueryPayload():
|
|
| 88 |
- name = list_.getAttr('name')
|
|
| 89 |
- if list_.getName() == 'active':
|
|
| 90 |
- self.active_list = name
|
|
| 91 |
- elif list_.getName() == 'default':
|
|
| 92 |
- new_default = name
|
|
| 93 |
- else:
|
|
| 94 |
- lists.append(name)
|
|
| 95 |
- |
|
| 96 |
- self._log.info('Received lists: %s', lists)
|
|
| 97 |
- |
|
| 98 |
- # Download default list if we don’t have it
|
|
| 99 |
- if self.default_list != new_default:
|
|
| 100 |
- self.default_list = new_default
|
|
| 101 |
- if new_default is not None:
|
|
| 102 |
- self._log.info('Found new default list: %s', new_default)
|
|
| 103 |
- self.get_privacy_list(new_default)
|
|
| 104 |
- |
|
| 105 |
- if callback:
|
|
| 106 |
- callback(result)
|
|
| 107 |
- else:
|
|
| 108 |
- app.nec.push_incoming_event(
|
|
| 109 |
- PrivacyListsReceivedEvent(None,
|
|
| 110 |
- conn=self._con,
|
|
| 111 |
- active_list=self.active_list,
|
|
| 112 |
- default_list=self.default_list,
|
|
| 113 |
- lists=lists))
|
|
| 114 |
- |
|
| 115 |
- def get_privacy_list(self, name):
|
|
| 116 |
- self._log.info('Request list: %s', name)
|
|
| 117 |
- list_ = nbxmpp.Node('list', {'name': name})
|
|
| 118 |
- iq = nbxmpp.Iq('get', Namespace.PRIVACY, payload=[list_])
|
|
| 119 |
- self._con.connection.SendAndCallForResponse(
|
|
| 120 |
- iq, self._privacy_list_received)
|
|
| 121 |
- |
|
| 122 |
- def _privacy_list_received(self, _nbxmpp_client, stanza):
|
|
| 123 |
- if not nbxmpp.isResultNode(stanza):
|
|
| 124 |
- self._log.warning('List not available: %s', stanza.getError())
|
|
| 125 |
- return
|
|
| 126 |
- |
|
| 127 |
- rules = []
|
|
| 128 |
- list_ = stanza.getQueryPayload()[0]
|
|
| 129 |
- name = list_.getAttr('name')
|
|
| 130 |
- |
|
| 131 |
- for child in list_.getChildren():
|
|
| 132 |
- |
|
| 133 |
- item = child.getAttrs()
|
|
| 134 |
- |
|
| 135 |
- children = []
|
|
| 136 |
- for scnd_child in child.getChildren():
|
|
| 137 |
- children.append(scnd_child.getName())
|
|
| 138 |
- |
|
| 139 |
- item['child'] = children
|
|
| 140 |
- if len(item) not in (3, 5):
|
|
| 141 |
- self._log.warning('Wrong count of attrs: %s', stanza)
|
|
| 142 |
- continue
|
|
| 143 |
- rules.append(item)
|
|
| 144 |
- |
|
| 145 |
- self._log.info('Received list: %s', name)
|
|
| 146 |
- |
|
| 147 |
- if name == self.default_list:
|
|
| 148 |
- self._default_list_received(rules)
|
|
| 149 |
- |
|
| 150 |
- app.nec.push_incoming_event(PrivacyListReceivedEvent(
|
|
| 151 |
- None, conn=self._con, list_name=name, rules=rules))
|
|
| 152 |
- |
|
| 153 |
- def del_privacy_list(self, name):
|
|
| 154 |
- self._log.info('Remove list: %s', name)
|
|
| 155 |
- |
|
| 156 |
- def _del_privacy_list_result(_nbxmpp_client, stanza):
|
|
| 157 |
- if not nbxmpp.isResultNode(stanza):
|
|
| 158 |
- self._log.warning('List deletion failed: %s', stanza.getError())
|
|
| 159 |
- app.nec.push_incoming_event(InformationEvent(
|
|
| 160 |
- None, dialog_name='privacy-list-error', args=name))
|
|
| 161 |
- else:
|
|
| 162 |
- app.nec.push_incoming_event(PrivacyListRemovedEvent(
|
|
| 163 |
- None, conn=self._con, list_name=name))
|
|
| 164 |
- |
|
| 165 |
- node = nbxmpp.Node('list', {'name': name})
|
|
| 166 |
- iq = nbxmpp.Iq('set', Namespace.PRIVACY, payload=[node])
|
|
| 167 |
- self._con.connection.SendAndCallForResponse(
|
|
| 168 |
- iq, _del_privacy_list_result)
|
|
| 169 |
- |
|
| 170 |
- def set_privacy_list(self, name, rules):
|
|
| 171 |
- node = nbxmpp.Node('list', {'name': name})
|
|
| 172 |
- iq = nbxmpp.Iq('set', Namespace.PRIVACY, payload=[node])
|
|
| 173 |
- for item in rules:
|
|
| 174 |
- children = item.get('child', [])
|
|
| 175 |
- for child in children:
|
|
| 176 |
- node.setTag(child)
|
|
| 177 |
- item.pop('child', None)
|
|
| 178 |
- node.setTag('item', item)
|
|
| 179 |
- self._log.info('Update list: %s %s', name, rules)
|
|
| 180 |
- self._con.connection.SendAndCallForResponse(
|
|
| 181 |
- iq, self._default_result_handler, {})
|
|
| 182 |
- |
|
| 183 |
- def _default_list_received(self, rules):
|
|
| 184 |
- roster = app.interface.roster
|
|
| 185 |
- |
|
| 186 |
- for rule in rules:
|
|
| 187 |
- if rule['action'] == 'allow':
|
|
| 188 |
- if 'type' not in rule:
|
|
| 189 |
- self.blocked_all = False
|
|
| 190 |
- |
|
| 191 |
- elif rule['type'] == 'jid':
|
|
| 192 |
- if rule['value'] in self.blocked_contacts:
|
|
| 193 |
- self.blocked_contacts.remove(rule['value'])
|
|
| 194 |
- |
|
| 195 |
- elif rule['type'] == 'group':
|
|
| 196 |
- if rule['value'] in self.blocked_groups:
|
|
| 197 |
- self.blocked_groups.remove(rule['value'])
|
|
| 198 |
- |
|
| 199 |
- elif rule['action'] == 'deny':
|
|
| 200 |
- if 'type' not in rule:
|
|
| 201 |
- self.blocked_all = True
|
|
| 202 |
- |
|
| 203 |
- elif rule['type'] == 'jid':
|
|
| 204 |
- if rule['value'] not in self.blocked_contacts:
|
|
| 205 |
- self.blocked_contacts.append(rule['value'])
|
|
| 206 |
- |
|
| 207 |
- elif rule['type'] == 'group':
|
|
| 208 |
- if rule['value'] not in self.blocked_groups:
|
|
| 209 |
- self.blocked_groups.append(rule['value'])
|
|
| 210 |
- |
|
| 211 |
- self.blocked_list.append(rule)
|
|
| 212 |
- |
|
| 213 |
- if 'type' in rule:
|
|
| 214 |
- if rule['type'] == 'jid':
|
|
| 215 |
- roster.draw_contact(rule['value'], self._account)
|
|
| 216 |
- if rule['type'] == 'group':
|
|
| 217 |
- roster.draw_group(rule['value'], self._account)
|
|
| 218 |
- |
|
| 219 |
- def set_active_list(self, name=None):
|
|
| 220 |
- self._log.info('Set active list: %s', name)
|
|
| 221 |
- attr = {}
|
|
| 222 |
- if name:
|
|
| 223 |
- attr['name'] = name
|
|
| 224 |
- node = nbxmpp.Node('active', attr)
|
|
| 225 |
- iq = nbxmpp.Iq('set', Namespace.PRIVACY, payload=[node])
|
|
| 226 |
- self._con.connection.SendAndCallForResponse(
|
|
| 227 |
- iq, self._default_result_handler, {})
|
|
| 228 |
- |
|
| 229 |
- def set_default_list(self, name=None):
|
|
| 230 |
- self._log.info('Set default list: %s', name)
|
|
| 231 |
- attr = {}
|
|
| 232 |
- if name:
|
|
| 233 |
- attr['name'] = name
|
|
| 234 |
- node = nbxmpp.Node('default', attr)
|
|
| 235 |
- iq = nbxmpp.Iq('set', Namespace.PRIVACY, payload=[node])
|
|
| 236 |
- self._con.connection.SendAndCallForResponse(
|
|
| 237 |
- iq, self._default_result_handler, {})
|
|
| 238 |
- |
|
| 239 |
- def _default_result_handler(self, _nbxmpp_client, stanza):
|
|
| 240 |
- if not nbxmpp.isResultNode(stanza):
|
|
| 241 |
- self._log.warning('Operation failed: %s', stanza.getError())
|
|
| 242 |
- |
|
| 243 |
- def _get_max_blocked_list_order(self):
|
|
| 244 |
- max_order = 0
|
|
| 245 |
- for rule in self.blocked_list:
|
|
| 246 |
- order = int(rule['order'])
|
|
| 247 |
- if order > max_order:
|
|
| 248 |
- max_order = order
|
|
| 249 |
- return max_order
|
|
| 250 |
- |
|
| 251 |
- def block_gc_contact(self, jid):
|
|
| 252 |
- if jid in self.blocked_contacts:
|
|
| 253 |
- return
|
|
| 254 |
- self._log.info('Block GC contact: %s', jid)
|
|
| 255 |
- |
|
| 256 |
- if self.default_list is None:
|
|
| 257 |
- self.default_list = 'block'
|
|
| 258 |
- |
|
| 259 |
- max_order = self._get_max_blocked_list_order()
|
|
| 260 |
- new_rule = {'order': str(max_order + 1),
|
|
| 261 |
- 'type': 'jid',
|
|
| 262 |
- 'action': 'deny',
|
|
| 263 |
- 'value': jid,
|
|
| 264 |
- 'child': ['message', 'iq', 'presence-out']}
|
|
| 265 |
- self.blocked_list.append(new_rule)
|
|
| 266 |
- self.blocked_contacts.append(jid)
|
|
| 267 |
- self.set_privacy_list(self.default_list, self.blocked_list)
|
|
| 268 |
- if len(self.blocked_list) == 1:
|
|
| 269 |
- self.set_default_list(self.default_list)
|
|
| 270 |
- |
|
| 271 |
- def block_contacts(self, contact_list, _message):
|
|
| 272 |
- if not self.supported:
|
|
| 273 |
- jid_list = [contact.jid for contact in contact_list]
|
|
| 274 |
- self._con.get_module('Blocking').block(jid_list)
|
|
| 275 |
- return
|
|
| 276 |
- |
|
| 277 |
- if self.default_list is None:
|
|
| 278 |
- self.default_list = 'block'
|
|
| 279 |
- for contact in contact_list:
|
|
| 280 |
- self._log.info('Block contacts: %s', contact.jid)
|
|
| 281 |
- contact.show = 'offline'
|
|
| 282 |
- self._con.get_module('Presence').send_presence(contact.jid,
|
|
| 283 |
- typ='unavailable')
|
|
| 284 |
- max_order = self._get_max_blocked_list_order()
|
|
| 285 |
- new_rule = {'order': str(max_order + 1),
|
|
| 286 |
- 'type': 'jid',
|
|
| 287 |
- 'action': 'deny',
|
|
| 288 |
- 'value': contact.jid}
|
|
| 289 |
- self.blocked_list.append(new_rule)
|
|
| 290 |
- self.blocked_contacts.append(contact.jid)
|
|
| 291 |
- self.set_privacy_list(self.default_list, self.blocked_list)
|
|
| 292 |
- if len(self.blocked_list) == 1:
|
|
| 293 |
- self.set_default_list(self.default_list)
|
|
| 294 |
- |
|
| 295 |
- def unblock_gc_contact(self, jid):
|
|
| 296 |
- new_blocked_list = []
|
|
| 297 |
- # needed for draw_contact:
|
|
| 298 |
- if jid not in self.blocked_contacts:
|
|
| 299 |
- return
|
|
| 300 |
- |
|
| 301 |
- self.blocked_contacts.remove(jid)
|
|
| 302 |
- |
|
| 303 |
- self._log.info('Unblock GC contact: %s', jid)
|
|
| 304 |
- for rule in self.blocked_list:
|
|
| 305 |
- if (rule['action'] != 'deny' or
|
|
| 306 |
- rule['type'] != 'jid' or
|
|
| 307 |
- rule['value'] != jid):
|
|
| 308 |
- new_blocked_list.append(rule)
|
|
| 309 |
- |
|
| 310 |
- if not new_blocked_list:
|
|
| 311 |
- self.blocked_list = []
|
|
| 312 |
- self.blocked_contacts = []
|
|
| 313 |
- self.blocked_groups = []
|
|
| 314 |
- self.set_default_list(None)
|
|
| 315 |
- self.del_privacy_list(self.default_list)
|
|
| 316 |
- else:
|
|
| 317 |
- self.set_privacy_list(self.default_list, new_blocked_list)
|
|
| 318 |
- |
|
| 319 |
- def unblock_contacts(self, contact_list):
|
|
| 320 |
- if not self.supported:
|
|
| 321 |
- jid_list = [contact.jid for contact in contact_list]
|
|
| 322 |
- self._con.get_module('Blocking').unblock(jid_list)
|
|
| 323 |
- return
|
|
| 324 |
- |
|
| 325 |
- new_blocked_list = []
|
|
| 326 |
- to_unblock = []
|
|
| 327 |
- for contact in contact_list:
|
|
| 328 |
- self._log.info('Unblock contacts: %s', contact.jid)
|
|
| 329 |
- to_unblock.append(contact.jid)
|
|
| 330 |
- if contact.jid in self.blocked_contacts:
|
|
| 331 |
- self.blocked_contacts.remove(contact.jid)
|
|
| 332 |
- for rule in self.blocked_list:
|
|
| 333 |
- if (rule['action'] != 'deny' or
|
|
| 334 |
- rule['type'] != 'jid' or
|
|
| 335 |
- rule['value'] not in to_unblock):
|
|
| 336 |
- new_blocked_list.append(rule)
|
|
| 337 |
- |
|
| 338 |
- if not new_blocked_list:
|
|
| 339 |
- self.blocked_list = []
|
|
| 340 |
- self.blocked_contacts = []
|
|
| 341 |
- self.blocked_groups = []
|
|
| 342 |
- self.set_default_list(None)
|
|
| 343 |
- self.del_privacy_list(self.default_list)
|
|
| 344 |
- else:
|
|
| 345 |
- self.set_privacy_list(self.default_list, new_blocked_list)
|
|
| 346 |
- if not app.interface.roster.regroup:
|
|
| 347 |
- show = self._con.status
|
|
| 348 |
- else: # accounts merged
|
|
| 349 |
- show = helpers.get_global_show()
|
|
| 350 |
- |
|
| 351 |
- for contact in contact_list:
|
|
| 352 |
- self._con.get_module('Presence').send_presence(
|
|
| 353 |
- contact.jid, show=show, status=self._con.status_message)
|
|
| 354 |
- self._presence_probe(contact.jid)
|
|
| 355 |
- |
|
| 356 |
- def block_group(self, group, contact_list, _message):
|
|
| 357 |
- if not self.supported:
|
|
| 358 |
- return
|
|
| 359 |
- if group in self.blocked_groups:
|
|
| 360 |
- return
|
|
| 361 |
- self.blocked_groups.append(group)
|
|
| 362 |
- |
|
| 363 |
- self._log.info('Block group: %s', group)
|
|
| 364 |
- |
|
| 365 |
- if self.default_list is None:
|
|
| 366 |
- self.default_list = 'block'
|
|
| 367 |
- |
|
| 368 |
- for contact in contact_list:
|
|
| 369 |
- self._con.get_module('Presence').send_presence(
|
|
| 370 |
- contact.jid, typ='unavailable')
|
|
| 371 |
- |
|
| 372 |
- max_order = self._get_max_blocked_list_order()
|
|
| 373 |
- new_rule = {'order': str(max_order + 1),
|
|
| 374 |
- 'type': 'group',
|
|
| 375 |
- 'action': 'deny',
|
|
| 376 |
- 'value': group}
|
|
| 377 |
- |
|
| 378 |
- self.blocked_list.append(new_rule)
|
|
| 379 |
- self.set_privacy_list(self.default_list, self.blocked_list)
|
|
| 380 |
- if len(self.blocked_list) == 1:
|
|
| 381 |
- self.set_default_list(self.default_list)
|
|
| 382 |
- |
|
| 383 |
- def unblock_group(self, group, contact_list):
|
|
| 384 |
- if not self.supported:
|
|
| 385 |
- return
|
|
| 386 |
- |
|
| 387 |
- if group not in self.blocked_groups:
|
|
| 388 |
- return
|
|
| 389 |
- self.blocked_groups.remove(group)
|
|
| 390 |
- |
|
| 391 |
- self._log.info('Unblock group: %s', group)
|
|
| 392 |
- new_blocked_list = []
|
|
| 393 |
- for rule in self.blocked_list:
|
|
| 394 |
- if (rule['action'] != 'deny' or
|
|
| 395 |
- rule['type'] != 'group' or
|
|
| 396 |
- rule['value'] != group):
|
|
| 397 |
- new_blocked_list.append(rule)
|
|
| 398 |
- |
|
| 399 |
- if not new_blocked_list:
|
|
| 400 |
- self.blocked_list = []
|
|
| 401 |
- self.blocked_contacts = []
|
|
| 402 |
- self.blocked_groups = []
|
|
| 403 |
- self.set_default_list('')
|
|
| 404 |
- self.del_privacy_list(self.default_list)
|
|
| 405 |
- else:
|
|
| 406 |
- self.set_privacy_list(self.default_list, new_blocked_list)
|
|
| 407 |
- if not app.interface.roster.regroup:
|
|
| 408 |
- show = self._con.status
|
|
| 409 |
- else: # accounts merged
|
|
| 410 |
- show = helpers.get_global_show()
|
|
| 411 |
- |
|
| 412 |
- for contact in contact_list:
|
|
| 413 |
- self._con.get_module('Presence').send_presence(
|
|
| 414 |
- contact.jid, show=show, status=self._con.status_message)
|
|
| 415 |
- |
|
| 416 |
- def _presence_probe(self, jid):
|
|
| 417 |
- self._log.info('Presence probe: %s', jid)
|
|
| 418 |
- # Send a presence Probe to get the current Status
|
|
| 419 |
- probe = nbxmpp.Presence(jid, 'probe', frm=self._con.get_own_jid())
|
|
| 420 |
- self._con.connection.send(probe)
|
|
| 421 |
- |
|
| 422 |
- |
|
| 423 |
-class PrivacyListsReceivedEvent(NetworkIncomingEvent):
|
|
| 424 |
- name = 'privacy-lists-received'
|
|
| 425 |
- |
|
| 426 |
- |
|
| 427 |
-class PrivacyListReceivedEvent(NetworkIncomingEvent):
|
|
| 428 |
- name = 'privacy-list-received'
|
|
| 429 |
- |
|
| 430 |
- |
|
| 431 |
-class PrivacyListRemovedEvent(NetworkIncomingEvent):
|
|
| 432 |
- name = 'privacy-list-removed'
|
|
| 433 |
- |
|
| 434 |
- |
|
| 435 |
-def get_instance(*args, **kwargs):
|
|
| 436 |
- return PrivacyLists(*args, **kwargs), 'PrivacyLists'
|
| ... | ... | @@ -2181,312 +2181,422 @@ $T will be replaced by auto-not-available timeout.</property> |
| 2181 | 2181 |
</packing>
|
| 2182 | 2182 |
</child>
|
| 2183 | 2183 |
<child>
|
| 2184 |
- <object class="GtkBox" id="audio_video_tab">
|
|
| 2184 |
+ <object class="GtkScrolledWindow">
|
|
| 2185 | 2185 |
<property name="visible">True</property>
|
| 2186 |
- <property name="can_focus">False</property>
|
|
| 2187 |
- <property name="border_width">18</property>
|
|
| 2188 |
- <property name="orientation">vertical</property>
|
|
| 2189 |
- <property name="spacing">6</property>
|
|
| 2186 |
+ <property name="can_focus">True</property>
|
|
| 2190 | 2187 |
<child>
|
| 2191 |
- <object class="GtkGrid">
|
|
| 2188 |
+ <object class="GtkViewport">
|
|
| 2192 | 2189 |
<property name="visible">True</property>
|
| 2193 | 2190 |
<property name="can_focus">False</property>
|
| 2194 |
- <property name="halign">start</property>
|
|
| 2195 |
- <property name="row_spacing">6</property>
|
|
| 2196 |
- <property name="column_spacing">12</property>
|
|
| 2197 |
- <child>
|
|
| 2198 |
- <object class="GtkLabel">
|
|
| 2199 |
- <property name="width_request">-1</property>
|
|
| 2200 |
- <property name="visible">True</property>
|
|
| 2201 |
- <property name="can_focus">False</property>
|
|
| 2202 |
- <property name="halign">end</property>
|
|
| 2203 |
- <property name="label" translatable="yes">A_udio output device</property>
|
|
| 2204 |
- <property name="use_underline">True</property>
|
|
| 2205 |
- <property name="mnemonic_widget">audio_output_combobox</property>
|
|
| 2206 |
- <style>
|
|
| 2207 |
- <class name="dim-label"/>
|
|
| 2208 |
- </style>
|
|
| 2209 |
- </object>
|
|
| 2210 |
- <packing>
|
|
| 2211 |
- <property name="left_attach">0</property>
|
|
| 2212 |
- <property name="top_attach">2</property>
|
|
| 2213 |
- </packing>
|
|
| 2214 |
- </child>
|
|
| 2215 |
- <child>
|
|
| 2216 |
- <object class="GtkComboBox" id="audio_output_combobox">
|
|
| 2217 |
- <property name="visible">True</property>
|
|
| 2218 |
- <property name="can_focus">False</property>
|
|
| 2219 |
- <signal name="changed" handler="on_audio_output_combobox_changed" swapped="no"/>
|
|
| 2220 |
- </object>
|
|
| 2221 |
- <packing>
|
|
| 2222 |
- <property name="left_attach">1</property>
|
|
| 2223 |
- <property name="top_attach">2</property>
|
|
| 2224 |
- </packing>
|
|
| 2225 |
- </child>
|
|
| 2226 |
- <child>
|
|
| 2227 |
- <object class="GtkComboBox" id="audio_input_combobox">
|
|
| 2228 |
- <property name="width_request">200</property>
|
|
| 2229 |
- <property name="visible">True</property>
|
|
| 2230 |
- <property name="can_focus">False</property>
|
|
| 2231 |
- <signal name="changed" handler="on_audio_input_combobox_changed" swapped="no"/>
|
|
| 2232 |
- </object>
|
|
| 2233 |
- <packing>
|
|
| 2234 |
- <property name="left_attach">1</property>
|
|
| 2235 |
- <property name="top_attach">1</property>
|
|
| 2236 |
- </packing>
|
|
| 2237 |
- </child>
|
|
| 2238 |
- <child>
|
|
| 2239 |
- <object class="GtkLabel">
|
|
| 2240 |
- <property name="width_request">-1</property>
|
|
| 2241 |
- <property name="visible">True</property>
|
|
| 2242 |
- <property name="can_focus">False</property>
|
|
| 2243 |
- <property name="halign">end</property>
|
|
| 2244 |
- <property name="label" translatable="yes">_Audio input device</property>
|
|
| 2245 |
- <property name="use_underline">True</property>
|
|
| 2246 |
- <property name="mnemonic_widget">audio_input_combobox</property>
|
|
| 2247 |
- <style>
|
|
| 2248 |
- <class name="dim-label"/>
|
|
| 2249 |
- </style>
|
|
| 2250 |
- </object>
|
|
| 2251 |
- <packing>
|
|
| 2252 |
- <property name="left_attach">0</property>
|
|
| 2253 |
- <property name="top_attach">1</property>
|
|
| 2254 |
- </packing>
|
|
| 2255 |
- </child>
|
|
| 2256 |
- <child>
|
|
| 2257 |
- <object class="GtkLabel">
|
|
| 2258 |
- <property name="visible">True</property>
|
|
| 2259 |
- <property name="can_focus">False</property>
|
|
| 2260 |
- <property name="halign">start</property>
|
|
| 2261 |
- <property name="label" translatable="yes">Audio</property>
|
|
| 2262 |
- <property name="use_markup">True</property>
|
|
| 2263 |
- <style>
|
|
| 2264 |
- <class name="bold"/>
|
|
| 2265 |
- <class name="margin-top6"/>
|
|
| 2266 |
- </style>
|
|
| 2267 |
- </object>
|
|
| 2268 |
- <packing>
|
|
| 2269 |
- <property name="left_attach">0</property>
|
|
| 2270 |
- <property name="top_attach">0</property>
|
|
| 2271 |
- </packing>
|
|
| 2272 |
- </child>
|
|
| 2273 |
- <child>
|
|
| 2274 |
- <object class="GtkLabel">
|
|
| 2275 |
- <property name="visible">True</property>
|
|
| 2276 |
- <property name="can_focus">False</property>
|
|
| 2277 |
- <property name="halign">start</property>
|
|
| 2278 |
- <property name="label" translatable="yes">Video</property>
|
|
| 2279 |
- <property name="use_markup">True</property>
|
|
| 2280 |
- <style>
|
|
| 2281 |
- <class name="bold"/>
|
|
| 2282 |
- <class name="margin-top6"/>
|
|
| 2283 |
- </style>
|
|
| 2284 |
- </object>
|
|
| 2285 |
- <packing>
|
|
| 2286 |
- <property name="left_attach">0</property>
|
|
| 2287 |
- <property name="top_attach">3</property>
|
|
| 2288 |
- </packing>
|
|
| 2289 |
- </child>
|
|
| 2290 | 2191 |
<child>
|
| 2291 |
- <object class="GtkLabel">
|
|
| 2292 |
- <property name="visible">True</property>
|
|
| 2293 |
- <property name="can_focus">False</property>
|
|
| 2294 |
- <property name="halign">end</property>
|
|
| 2295 |
- <property name="label" translatable="yes">_Video input device</property>
|
|
| 2296 |
- <property name="use_underline">True</property>
|
|
| 2297 |
- <property name="mnemonic_widget">video_input_combobox</property>
|
|
| 2298 |
- <style>
|
|
| 2299 |
- <class name="dim-label"/>
|
|
| 2300 |
- </style>
|
|
| 2301 |
- </object>
|
|
| 2302 |
- <packing>
|
|
| 2303 |
- <property name="left_attach">0</property>
|
|
| 2304 |
- <property name="top_attach">4</property>
|
|
| 2305 |
- </packing>
|
|
| 2306 |
- </child>
|
|
| 2307 |
- <child>
|
|
| 2308 |
- <object class="GtkComboBox" id="video_input_combobox">
|
|
| 2309 |
- <property name="visible">True</property>
|
|
| 2310 |
- <property name="can_focus">False</property>
|
|
| 2311 |
- <signal name="changed" handler="on_video_input_combobox_changed" swapped="no"/>
|
|
| 2312 |
- </object>
|
|
| 2313 |
- <packing>
|
|
| 2314 |
- <property name="left_attach">1</property>
|
|
| 2315 |
- <property name="top_attach">4</property>
|
|
| 2316 |
- </packing>
|
|
| 2317 |
- </child>
|
|
| 2318 |
- <child>
|
|
| 2319 |
- <object class="GtkLabel">
|
|
| 2320 |
- <property name="visible">True</property>
|
|
| 2321 |
- <property name="can_focus">False</property>
|
|
| 2322 |
- <property name="halign">end</property>
|
|
| 2323 |
- <property name="label" translatable="yes">Video output</property>
|
|
| 2324 |
- <property name="mnemonic_widget">selected_video_output</property>
|
|
| 2325 |
- <style>
|
|
| 2326 |
- <class name="dim-label"/>
|
|
| 2327 |
- </style>
|
|
| 2328 |
- </object>
|
|
| 2329 |
- <packing>
|
|
| 2330 |
- <property name="left_attach">0</property>
|
|
| 2331 |
- <property name="top_attach">5</property>
|
|
| 2332 |
- </packing>
|
|
| 2333 |
- </child>
|
|
| 2334 |
- <child>
|
|
| 2335 |
- <object class="GtkLabel" id="selected_video_output">
|
|
| 2336 |
- <property name="visible">True</property>
|
|
| 2337 |
- <property name="can_focus">False</property>
|
|
| 2338 |
- <property name="halign">start</property>
|
|
| 2339 |
- </object>
|
|
| 2340 |
- <packing>
|
|
| 2341 |
- <property name="left_attach">1</property>
|
|
| 2342 |
- <property name="top_attach">5</property>
|
|
| 2343 |
- </packing>
|
|
| 2344 |
- </child>
|
|
| 2345 |
- <child>
|
|
| 2346 |
- <object class="GtkLabel">
|
|
| 2347 |
- <property name="visible">True</property>
|
|
| 2348 |
- <property name="can_focus">False</property>
|
|
| 2349 |
- <property name="halign">end</property>
|
|
| 2350 |
- <property name="margin_top">12</property>
|
|
| 2351 |
- <property name="label" translatable="yes">Video _framerate</property>
|
|
| 2352 |
- <property name="use_underline">True</property>
|
|
| 2353 |
- <property name="mnemonic_widget">video_framerate_combobox</property>
|
|
| 2354 |
- <style>
|
|
| 2355 |
- <class name="dim-label"/>
|
|
| 2356 |
- </style>
|
|
| 2357 |
- </object>
|
|
| 2358 |
- <packing>
|
|
| 2359 |
- <property name="left_attach">0</property>
|
|
| 2360 |
- <property name="top_attach">6</property>
|
|
| 2361 |
- </packing>
|
|
| 2362 |
- </child>
|
|
| 2363 |
- <child>
|
|
| 2364 |
- <object class="GtkComboBox" id="video_framerate_combobox">
|
|
| 2365 |
- <property name="visible">True</property>
|
|
| 2366 |
- <property name="can_focus">False</property>
|
|
| 2367 |
- <property name="margin_top">12</property>
|
|
| 2368 |
- <signal name="changed" handler="on_video_framerate_combobox_changed" swapped="no"/>
|
|
| 2369 |
- </object>
|
|
| 2370 |
- <packing>
|
|
| 2371 |
- <property name="left_attach">1</property>
|
|
| 2372 |
- <property name="top_attach">6</property>
|
|
| 2373 |
- </packing>
|
|
| 2374 |
- </child>
|
|
| 2375 |
- <child>
|
|
| 2376 |
- <object class="GtkLabel">
|
|
| 2377 |
- <property name="visible">True</property>
|
|
| 2378 |
- <property name="can_focus">False</property>
|
|
| 2379 |
- <property name="halign">end</property>
|
|
| 2380 |
- <property name="label" translatable="yes">Video si_ze</property>
|
|
| 2381 |
- <property name="use_underline">True</property>
|
|
| 2382 |
- <property name="mnemonic_widget">video_size_combobox</property>
|
|
| 2383 |
- <style>
|
|
| 2384 |
- <class name="dim-label"/>
|
|
| 2385 |
- </style>
|
|
| 2386 |
- </object>
|
|
| 2387 |
- <packing>
|
|
| 2388 |
- <property name="left_attach">0</property>
|
|
| 2389 |
- <property name="top_attach">7</property>
|
|
| 2390 |
- </packing>
|
|
| 2391 |
- </child>
|
|
| 2392 |
- <child>
|
|
| 2393 |
- <object class="GtkComboBox" id="video_size_combobox">
|
|
| 2394 |
- <property name="visible">True</property>
|
|
| 2395 |
- <property name="can_focus">False</property>
|
|
| 2396 |
- <signal name="changed" handler="on_video_size_combobox_changed" swapped="no"/>
|
|
| 2397 |
- </object>
|
|
| 2398 |
- <packing>
|
|
| 2399 |
- <property name="left_attach">1</property>
|
|
| 2400 |
- <property name="top_attach">7</property>
|
|
| 2401 |
- </packing>
|
|
| 2402 |
- </child>
|
|
| 2403 |
- <child>
|
|
| 2404 |
- <object class="GtkCheckButton" id="video_see_self_checkbutton">
|
|
| 2405 |
- <property name="label" translatable="yes">Vi_ew own video source</property>
|
|
| 2406 |
- <property name="visible">True</property>
|
|
| 2407 |
- <property name="can_focus">True</property>
|
|
| 2408 |
- <property name="receives_default">False</property>
|
|
| 2409 |
- <property name="halign">start</property>
|
|
| 2410 |
- <property name="use_underline">True</property>
|
|
| 2411 |
- <property name="draw_indicator">True</property>
|
|
| 2412 |
- <signal name="toggled" handler="on_video_see_self_checkbutton_toggled" swapped="no"/>
|
|
| 2413 |
- </object>
|
|
| 2414 |
- <packing>
|
|
| 2415 |
- <property name="left_attach">1</property>
|
|
| 2416 |
- <property name="top_attach">8</property>
|
|
| 2417 |
- </packing>
|
|
| 2418 |
- </child>
|
|
| 2419 |
- <child>
|
|
| 2420 |
- <object class="GtkLabel">
|
|
| 2192 |
+ <object class="GtkBox">
|
|
| 2421 | 2193 |
<property name="visible">True</property>
|
| 2422 | 2194 |
<property name="can_focus">False</property>
|
| 2423 |
- <property name="halign">start</property>
|
|
| 2424 |
- <property name="label" translatable="yes">Connection</property>
|
|
| 2425 |
- <property name="use_markup">True</property>
|
|
| 2426 |
- <style>
|
|
| 2427 |
- <class name="bold"/>
|
|
| 2428 |
- <class name="margin-top6"/>
|
|
| 2429 |
- </style>
|
|
| 2430 |
- </object>
|
|
| 2431 |
- <packing>
|
|
| 2432 |
- <property name="left_attach">0</property>
|
|
| 2433 |
- <property name="top_attach">9</property>
|
|
| 2434 |
- </packing>
|
|
| 2435 |
- </child>
|
|
| 2436 |
- <child>
|
|
| 2437 |
- <object class="GtkCheckButton" id="stun_checkbutton">
|
|
| 2438 |
- <property name="label" translatable="yes">STU_N server</property>
|
|
| 2439 |
- <property name="visible">True</property>
|
|
| 2440 |
- <property name="can_focus">True</property>
|
|
| 2441 |
- <property name="receives_default">False</property>
|
|
| 2442 |
- <property name="halign">end</property>
|
|
| 2443 |
- <property name="use_underline">True</property>
|
|
| 2444 |
- <property name="draw_indicator">True</property>
|
|
| 2445 |
- <signal name="toggled" handler="on_stun_checkbutton_toggled" swapped="no"/>
|
|
| 2446 |
- </object>
|
|
| 2447 |
- <packing>
|
|
| 2448 |
- <property name="left_attach">0</property>
|
|
| 2449 |
- <property name="top_attach">10</property>
|
|
| 2450 |
- </packing>
|
|
| 2451 |
- </child>
|
|
| 2452 |
- <child>
|
|
| 2453 |
- <object class="GtkEntry" id="stun_server_entry">
|
|
| 2454 |
- <property name="visible">True</property>
|
|
| 2455 |
- <property name="can_focus">True</property>
|
|
| 2456 |
- <property name="tooltip_text" translatable="yes">STUN server hostname. If no hostname was given, Gajim will try
|
|
| 2195 |
+ <property name="orientation">vertical</property>
|
|
| 2196 |
+ <child>
|
|
| 2197 |
+ <object class="GtkGrid">
|
|
| 2198 |
+ <property name="visible">True</property>
|
|
| 2199 |
+ <property name="can_focus">False</property>
|
|
| 2200 |
+ <property name="hexpand">True</property>
|
|
| 2201 |
+ <property name="border_width">18</property>
|
|
| 2202 |
+ <property name="row_spacing">6</property>
|
|
| 2203 |
+ <property name="column_spacing">12</property>
|
|
| 2204 |
+ <child>
|
|
| 2205 |
+ <object class="GtkLabel">
|
|
| 2206 |
+ <property name="width_request">-1</property>
|
|
| 2207 |
+ <property name="visible">True</property>
|
|
| 2208 |
+ <property name="can_focus">False</property>
|
|
| 2209 |
+ <property name="halign">end</property>
|
|
| 2210 |
+ <property name="label" translatable="yes">A_udio output device</property>
|
|
| 2211 |
+ <property name="use_underline">True</property>
|
|
| 2212 |
+ <property name="mnemonic_widget">audio_output_combobox</property>
|
|
| 2213 |
+ <style>
|
|
| 2214 |
+ <class name="dim-label"/>
|
|
| 2215 |
+ </style>
|
|
| 2216 |
+ </object>
|
|
| 2217 |
+ <packing>
|
|
| 2218 |
+ <property name="left_attach">0</property>
|
|
| 2219 |
+ <property name="top_attach">2</property>
|
|
| 2220 |
+ </packing>
|
|
| 2221 |
+ </child>
|
|
| 2222 |
+ <child>
|
|
| 2223 |
+ <object class="GtkComboBox" id="audio_output_combobox">
|
|
| 2224 |
+ <property name="visible">True</property>
|
|
| 2225 |
+ <property name="can_focus">False</property>
|
|
| 2226 |
+ <signal name="changed" handler="on_audio_output_combobox_changed" swapped="no"/>
|
|
| 2227 |
+ </object>
|
|
| 2228 |
+ <packing>
|
|
| 2229 |
+ <property name="left_attach">1</property>
|
|
| 2230 |
+ <property name="top_attach">2</property>
|
|
| 2231 |
+ </packing>
|
|
| 2232 |
+ </child>
|
|
| 2233 |
+ <child>
|
|
| 2234 |
+ <object class="GtkComboBox" id="audio_input_combobox">
|
|
| 2235 |
+ <property name="width_request">200</property>
|
|
| 2236 |
+ <property name="visible">True</property>
|
|
| 2237 |
+ <property name="can_focus">False</property>
|
|
| 2238 |
+ <signal name="changed" handler="on_audio_input_combobox_changed" swapped="no"/>
|
|
| 2239 |
+ </object>
|
|
| 2240 |
+ <packing>
|
|
| 2241 |
+ <property name="left_attach">1</property>
|
|
| 2242 |
+ <property name="top_attach">1</property>
|
|
| 2243 |
+ </packing>
|
|
| 2244 |
+ </child>
|
|
| 2245 |
+ <child>
|
|
| 2246 |
+ <object class="GtkLabel">
|
|
| 2247 |
+ <property name="width_request">-1</property>
|
|
| 2248 |
+ <property name="visible">True</property>
|
|
| 2249 |
+ <property name="can_focus">False</property>
|
|
| 2250 |
+ <property name="halign">end</property>
|
|
| 2251 |
+ <property name="label" translatable="yes">_Audio input device</property>
|
|
| 2252 |
+ <property name="use_underline">True</property>
|
|
| 2253 |
+ <property name="mnemonic_widget">audio_input_combobox</property>
|
|
| 2254 |
+ <style>
|
|
| 2255 |
+ <class name="dim-label"/>
|
|
| 2256 |
+ </style>
|
|
| 2257 |
+ </object>
|
|
| 2258 |
+ <packing>
|
|
| 2259 |
+ <property name="left_attach">0</property>
|
|
| 2260 |
+ <property name="top_attach">1</property>
|
|
| 2261 |
+ </packing>
|
|
| 2262 |
+ </child>
|
|
| 2263 |
+ <child>
|
|
| 2264 |
+ <object class="GtkLabel">
|
|
| 2265 |
+ <property name="visible">True</property>
|
|
| 2266 |
+ <property name="can_focus">False</property>
|
|
| 2267 |
+ <property name="halign">start</property>
|
|
| 2268 |
+ <property name="label" translatable="yes">Audio</property>
|
|
| 2269 |
+ <property name="use_markup">True</property>
|
|
| 2270 |
+ <style>
|
|
| 2271 |
+ <class name="bold"/>
|
|
| 2272 |
+ <class name="margin-top6"/>
|
|
| 2273 |
+ </style>
|
|
| 2274 |
+ </object>
|
|
| 2275 |
+ <packing>
|
|
| 2276 |
+ <property name="left_attach">0</property>
|
|
| 2277 |
+ <property name="top_attach">0</property>
|
|
| 2278 |
+ </packing>
|
|
| 2279 |
+ </child>
|
|
| 2280 |
+ <child>
|
|
| 2281 |
+ <object class="GtkLabel">
|
|
| 2282 |
+ <property name="visible">True</property>
|
|
| 2283 |
+ <property name="can_focus">False</property>
|
|
| 2284 |
+ <property name="halign">start</property>
|
|
| 2285 |
+ <property name="label" translatable="yes">Video</property>
|
|
| 2286 |
+ <property name="use_markup">True</property>
|
|
| 2287 |
+ <style>
|
|
| 2288 |
+ <class name="bold"/>
|
|
| 2289 |
+ <class name="margin-top6"/>
|
|
| 2290 |
+ </style>
|
|
| 2291 |
+ </object>
|
|
| 2292 |
+ <packing>
|
|
| 2293 |
+ <property name="left_attach">0</property>
|
|
| 2294 |
+ <property name="top_attach">3</property>
|
|
| 2295 |
+ </packing>
|
|
| 2296 |
+ </child>
|
|
| 2297 |
+ <child>
|
|
| 2298 |
+ <object class="GtkLabel">
|
|
| 2299 |
+ <property name="visible">True</property>
|
|
| 2300 |
+ <property name="can_focus">False</property>
|
|
| 2301 |
+ <property name="halign">end</property>
|
|
| 2302 |
+ <property name="label" translatable="yes">_Video input device</property>
|
|
| 2303 |
+ <property name="use_underline">True</property>
|
|
| 2304 |
+ <property name="mnemonic_widget">video_input_combobox</property>
|
|
| 2305 |
+ <style>
|
|
| 2306 |
+ <class name="dim-label"/>
|
|
| 2307 |
+ </style>
|
|
| 2308 |
+ </object>
|
|
| 2309 |
+ <packing>
|
|
| 2310 |
+ <property name="left_attach">0</property>
|
|
| 2311 |
+ <property name="top_attach">4</property>
|
|
| 2312 |
+ </packing>
|
|
| 2313 |
+ </child>
|
|
| 2314 |
+ <child>
|
|
| 2315 |
+ <object class="GtkComboBox" id="video_input_combobox">
|
|
| 2316 |
+ <property name="visible">True</property>
|
|
| 2317 |
+ <property name="can_focus">False</property>
|
|
| 2318 |
+ <signal name="changed" handler="on_video_input_combobox_changed" swapped="no"/>
|
|
| 2319 |
+ </object>
|
|
| 2320 |
+ <packing>
|
|
| 2321 |
+ <property name="left_attach">1</property>
|
|
| 2322 |
+ <property name="top_attach">4</property>
|
|
| 2323 |
+ </packing>
|
|
| 2324 |
+ </child>
|
|
| 2325 |
+ <child>
|
|
| 2326 |
+ <object class="GtkCheckButton" id="stun_checkbutton">
|
|
| 2327 |
+ <property name="label" translatable="yes">STU_N server</property>
|
|
| 2328 |
+ <property name="visible">True</property>
|
|
| 2329 |
+ <property name="can_focus">True</property>
|
|
| 2330 |
+ <property name="receives_default">False</property>
|
|
| 2331 |
+ <property name="halign">end</property>
|
|
| 2332 |
+ <property name="use_underline">True</property>
|
|
| 2333 |
+ <property name="draw_indicator">True</property>
|
|
| 2334 |
+ <signal name="toggled" handler="on_stun_checkbutton_toggled" swapped="no"/>
|
|
| 2335 |
+ </object>
|
|
| 2336 |
+ <packing>
|
|
| 2337 |
+ <property name="left_attach">0</property>
|
|
| 2338 |
+ <property name="top_attach">11</property>
|
|
| 2339 |
+ </packing>
|
|
| 2340 |
+ </child>
|
|
| 2341 |
+ <child>
|
|
| 2342 |
+ <object class="GtkEntry" id="stun_server_entry">
|
|
| 2343 |
+ <property name="visible">True</property>
|
|
| 2344 |
+ <property name="can_focus">True</property>
|
|
| 2345 |
+ <property name="tooltip_text" translatable="yes">STUN server hostname. If no hostname was given, Gajim will try
|
|
| 2457 | 2346 |
to discover one from the server. (Example: stun.iptel.org)</property>
|
| 2458 |
- <property name="invisible_char">●</property>
|
|
| 2459 |
- <signal name="changed" handler="stun_server_entry_changed" swapped="no"/>
|
|
| 2347 |
+ <property name="invisible_char">●</property>
|
|
| 2348 |
+ <signal name="changed" handler="stun_server_entry_changed" swapped="no"/>
|
|
| 2349 |
+ </object>
|
|
| 2350 |
+ <packing>
|
|
| 2351 |
+ <property name="left_attach">1</property>
|
|
| 2352 |
+ <property name="top_attach">11</property>
|
|
| 2353 |
+ </packing>
|
|
| 2354 |
+ </child>
|
|
| 2355 |
+ <child>
|
|
| 2356 |
+ <object class="GtkLabel">
|
|
| 2357 |
+ <property name="visible">True</property>
|
|
| 2358 |
+ <property name="can_focus">False</property>
|
|
| 2359 |
+ <property name="halign">start</property>
|
|
| 2360 |
+ <property name="label" translatable="yes">Connection</property>
|
|
| 2361 |
+ <property name="use_markup">True</property>
|
|
| 2362 |
+ <style>
|
|
| 2363 |
+ <class name="bold"/>
|
|
| 2364 |
+ <class name="margin-top6"/>
|
|
| 2365 |
+ </style>
|
|
| 2366 |
+ </object>
|
|
| 2367 |
+ <packing>
|
|
| 2368 |
+ <property name="left_attach">0</property>
|
|
| 2369 |
+ <property name="top_attach">10</property>
|
|
| 2370 |
+ </packing>
|
|
| 2371 |
+ </child>
|
|
| 2372 |
+ <child>
|
|
| 2373 |
+ <object class="GtkCheckButton" id="video_see_self_checkbutton">
|
|
| 2374 |
+ <property name="label" translatable="yes">Vi_ew own video source</property>
|
|
| 2375 |
+ <property name="visible">True</property>
|
|
| 2376 |
+ <property name="can_focus">True</property>
|
|
| 2377 |
+ <property name="receives_default">False</property>
|
|
| 2378 |
+ <property name="halign">start</property>
|
|
| 2379 |
+ <property name="use_underline">True</property>
|
|
| 2380 |
+ <property name="draw_indicator">True</property>
|
|
| 2381 |
+ <signal name="toggled" handler="on_video_see_self_checkbutton_toggled" swapped="no"/>
|
|
| 2382 |
+ </object>
|
|
| 2383 |
+ <packing>
|
|
| 2384 |
+ <property name="left_attach">1</property>
|
|
| 2385 |
+ <property name="top_attach">9</property>
|
|
| 2386 |
+ </packing>
|
|
| 2387 |
+ </child>
|
|
| 2388 |
+ <child>
|
|
| 2389 |
+ <object class="GtkComboBox" id="video_size_combobox">
|
|
| 2390 |
+ <property name="visible">True</property>
|
|
| 2391 |
+ <property name="can_focus">False</property>
|
|
| 2392 |
+ <signal name="changed" handler="on_video_size_combobox_changed" swapped="no"/>
|
|
| 2393 |
+ </object>
|
|
| 2394 |
+ <packing>
|
|
| 2395 |
+ <property name="left_attach">1</property>
|
|
| 2396 |
+ <property name="top_attach">8</property>
|
|
| 2397 |
+ </packing>
|
|
| 2398 |
+ </child>
|
|
| 2399 |
+ <child>
|
|
| 2400 |
+ <object class="GtkLabel">
|
|
| 2401 |
+ <property name="visible">True</property>
|
|
| 2402 |
+ <property name="can_focus">False</property>
|
|
| 2403 |
+ <property name="halign">end</property>
|
|
| 2404 |
+ <property name="label" translatable="yes">Video si_ze</property>
|
|
| 2405 |
+ <property name="use_underline">True</property>
|
|
| 2406 |
+ <style>
|
|
| 2407 |
+ <class name="dim-label"/>
|
|
| 2408 |
+ </style>
|
|
| 2409 |
+ </object>
|
|
| 2410 |
+ <packing>
|
|
| 2411 |
+ <property name="left_attach">0</property>
|
|
| 2412 |
+ <property name="top_attach">8</property>
|
|
| 2413 |
+ </packing>
|
|
| 2414 |
+ </child>
|
|
| 2415 |
+ <child>
|
|
| 2416 |
+ <object class="GtkLabel">
|
|
| 2417 |
+ <property name="visible">True</property>
|
|
| 2418 |
+ <property name="can_focus">False</property>
|
|
| 2419 |
+ <property name="halign">end</property>
|
|
| 2420 |
+ <property name="margin_top">12</property>
|
|
| 2421 |
+ <property name="label" translatable="yes">Video _framerate</property>
|
|
| 2422 |
+ <property name="use_underline">True</property>
|
|
| 2423 |
+ <style>
|
|
| 2424 |
+ <class name="dim-label"/>
|
|
| 2425 |
+ </style>
|
|
| 2426 |
+ </object>
|
|
| 2427 |
+ <packing>
|
|
| 2428 |
+ <property name="left_attach">0</property>
|
|
| 2429 |
+ <property name="top_attach">7</property>
|
|
| 2430 |
+ </packing>
|
|
| 2431 |
+ </child>
|
|
| 2432 |
+ <child>
|
|
| 2433 |
+ <object class="GtkComboBox" id="video_framerate_combobox">
|
|
| 2434 |
+ <property name="visible">True</property>
|
|
| 2435 |
+ <property name="can_focus">False</property>
|
|
| 2436 |
+ <property name="margin_top">12</property>
|
|
| 2437 |
+ <signal name="changed" handler="on_video_framerate_combobox_changed" swapped="no"/>
|
|
| 2438 |
+ </object>
|
|
| 2439 |
+ <packing>
|
|
| 2440 |
+ <property name="left_attach">1</property>
|
|
| 2441 |
+ <property name="top_attach">7</property>
|
|
| 2442 |
+ </packing>
|
|
| 2443 |
+ </child>
|
|
| 2444 |
+ <child>
|
|
| 2445 |
+ <object class="GtkLabel">
|
|
| 2446 |
+ <property name="visible">True</property>
|
|
| 2447 |
+ <property name="can_focus">False</property>
|
|
| 2448 |
+ <property name="halign">end</property>
|
|
| 2449 |
+ <property name="label" translatable="yes">Video output</property>
|
|
| 2450 |
+ <style>
|
|
| 2451 |
+ <class name="dim-label"/>
|
|
| 2452 |
+ </style>
|
|
| 2453 |
+ </object>
|
|
| 2454 |
+ <packing>
|
|
| 2455 |
+ <property name="left_attach">0</property>
|
|
| 2456 |
+ <property name="top_attach">6</property>
|
|
| 2457 |
+ </packing>
|
|
| 2458 |
+ </child>
|
|
| 2459 |
+ <child>
|
|
| 2460 |
+ <object class="GtkLabel" id="selected_video_output">
|
|
| 2461 |
+ <property name="visible">True</property>
|
|
| 2462 |
+ <property name="can_focus">False</property>
|
|
| 2463 |
+ <property name="halign">start</property>
|
|
| 2464 |
+ </object>
|
|
| 2465 |
+ <packing>
|
|
| 2466 |
+ <property name="left_attach">1</property>
|
|
| 2467 |
+ <property name="top_attach">6</property>
|
|
| 2468 |
+ </packing>
|
|
| 2469 |
+ </child>
|
|
| 2470 |
+ <child>
|
|
| 2471 |
+ <object class="GtkCheckButton" id="live_preview_checkbutton">
|
|
| 2472 |
+ <property name="label" translatable="yes">Show live _preview</property>
|
|
| 2473 |
+ <property name="visible">True</property>
|
|
| 2474 |
+ <property name="can_focus">True</property>
|
|
| 2475 |
+ <property name="receives_default">False</property>
|
|
| 2476 |
+ <property name="halign">start</property>
|
|
| 2477 |
+ <property name="use_underline">True</property>
|
|
| 2478 |
+ <property name="draw_indicator">True</property>
|
|
| 2479 |
+ <signal name="toggled" handler="_on_live_preview_toggled" swapped="no"/>
|
|
| 2480 |
+ </object>
|
|
| 2481 |
+ <packing>
|
|
| 2482 |
+ <property name="left_attach">1</property>
|
|
| 2483 |
+ <property name="top_attach">5</property>
|
|
| 2484 |
+ </packing>
|
|
| 2485 |
+ </child>
|
|
| 2486 |
+ <child>
|
|
| 2487 |
+ <placeholder/>
|
|
| 2488 |
+ </child>
|
|
| 2489 |
+ <child>
|
|
| 2490 |
+ <placeholder/>
|
|
| 2491 |
+ </child>
|
|
| 2492 |
+ <child>
|
|
| 2493 |
+ <placeholder/>
|
|
| 2494 |
+ </child>
|
|
| 2495 |
+ <child>
|
|
| 2496 |
+ <placeholder/>
|
|
| 2497 |
+ </child>
|
|
| 2498 |
+ <child>
|
|
| 2499 |
+ <placeholder/>
|
|
| 2500 |
+ </child>
|
|
| 2501 |
+ </object>
|
|
| 2502 |
+ <packing>
|
|
| 2503 |
+ <property name="expand">False</property>
|
|
| 2504 |
+ <property name="fill">True</property>
|
|
| 2505 |
+ <property name="position">0</property>
|
|
| 2506 |
+ </packing>
|
|
| 2507 |
+ </child>
|
|
| 2508 |
+ <child>
|
|
| 2509 |
+ <object class="GtkBox">
|
|
| 2510 |
+ <property name="visible">True</property>
|
|
| 2511 |
+ <property name="can_focus">False</property>
|
|
| 2512 |
+ <property name="orientation">vertical</property>
|
|
| 2513 |
+ <child>
|
|
| 2514 |
+ <object class="GtkSeparator">
|
|
| 2515 |
+ <property name="visible">True</property>
|
|
| 2516 |
+ <property name="can_focus">False</property>
|
|
| 2517 |
+ <property name="margin_top">12</property>
|
|
| 2518 |
+ </object>
|
|
| 2519 |
+ <packing>
|
|
| 2520 |
+ <property name="expand">False</property>
|
|
| 2521 |
+ <property name="fill">True</property>
|
|
| 2522 |
+ <property name="position">0</property>
|
|
| 2523 |
+ </packing>
|
|
| 2524 |
+ </child>
|
|
| 2525 |
+ <child>
|
|
| 2526 |
+ <object class="GtkBox" id="av_preview_box">
|
|
| 2527 |
+ <property name="height_request">250</property>
|
|
| 2528 |
+ <property name="visible">True</property>
|
|
| 2529 |
+ <property name="can_focus">False</property>
|
|
| 2530 |
+ <property name="orientation">vertical</property>
|
|
| 2531 |
+ <child>
|
|
| 2532 |
+ <object class="GtkBox" id="av_preview_placeholder">
|
|
| 2533 |
+ <property name="visible">True</property>
|
|
| 2534 |
+ <property name="can_focus">False</property>
|
|
| 2535 |
+ <property name="orientation">vertical</property>
|
|
| 2536 |
+ <child>
|
|
| 2537 |
+ <object class="GtkImage">
|
|
| 2538 |
+ <property name="visible">True</property>
|
|
| 2539 |
+ <property name="can_focus">False</property>
|
|
| 2540 |
+ <property name="margin_top">12</property>
|
|
| 2541 |
+ <property name="icon_name">camera-web-symbolic</property>
|
|
| 2542 |
+ <property name="icon_size">6</property>
|
|
| 2543 |
+ <style>
|
|
| 2544 |
+ <class name="dim-label"/>
|
|
| 2545 |
+ </style>
|
|
| 2546 |
+ </object>
|
|
| 2547 |
+ <packing>
|
|
| 2548 |
+ <property name="expand">False</property>
|
|
| 2549 |
+ <property name="fill">True</property>
|
|
| 2550 |
+ <property name="position">0</property>
|
|
| 2551 |
+ </packing>
|
|
| 2552 |
+ </child>
|
|
| 2553 |
+ <child>
|
|
| 2554 |
+ <object class="GtkLabel">
|
|
| 2555 |
+ <property name="visible">True</property>
|
|
| 2556 |
+ <property name="can_focus">False</property>
|
|
| 2557 |
+ <property name="label" translatable="yes">Live Preview</property>
|
|
| 2558 |
+ <property name="justify">center</property>
|
|
| 2559 |
+ <style>
|
|
| 2560 |
+ <class name="bold"/>
|
|
| 2561 |
+ <class name="dim-label"/>
|
|
| 2562 |
+ </style>
|
|
| 2563 |
+ </object>
|
|
| 2564 |
+ <packing>
|
|
| 2565 |
+ <property name="expand">False</property>
|
|
| 2566 |
+ <property name="fill">True</property>
|
|
| 2567 |
+ <property name="position">1</property>
|
|
| 2568 |
+ </packing>
|
|
| 2569 |
+ </child>
|
|
| 2570 |
+ </object>
|
|
| 2571 |
+ <packing>
|
|
| 2572 |
+ <property name="expand">True</property>
|
|
| 2573 |
+ <property name="fill">True</property>
|
|
| 2574 |
+ <property name="position">0</property>
|
|
| 2575 |
+ </packing>
|
|
| 2576 |
+ </child>
|
|
| 2577 |
+ </object>
|
|
| 2578 |
+ <packing>
|
|
| 2579 |
+ <property name="expand">False</property>
|
|
| 2580 |
+ <property name="fill">True</property>
|
|
| 2581 |
+ <property name="position">1</property>
|
|
| 2582 |
+ </packing>
|
|
| 2583 |
+ </child>
|
|
| 2584 |
+ </object>
|
|
| 2585 |
+ <packing>
|
|
| 2586 |
+ <property name="expand">False</property>
|
|
| 2587 |
+ <property name="fill">True</property>
|
|
| 2588 |
+ <property name="position">1</property>
|
|
| 2589 |
+ </packing>
|
|
| 2590 |
+ </child>
|
|
| 2460 | 2591 |
</object>
|
| 2461 |
- <packing>
|
|
| 2462 |
- <property name="left_attach">1</property>
|
|
| 2463 |
- <property name="top_attach">10</property>
|
|
| 2464 |
- </packing>
|
|
| 2465 |
- </child>
|
|
| 2466 |
- <child>
|
|
| 2467 |
- <placeholder/>
|
|
| 2468 |
- </child>
|
|
| 2469 |
- <child>
|
|
| 2470 |
- <placeholder/>
|
|
| 2471 |
- </child>
|
|
| 2472 |
- <child>
|
|
| 2473 |
- <placeholder/>
|
|
| 2474 |
- </child>
|
|
| 2475 |
- <child>
|
|
| 2476 |
- <placeholder/>
|
|
| 2477 | 2592 |
</child>
|
| 2478 | 2593 |
</object>
|
| 2479 |
- <packing>
|
|
| 2480 |
- <property name="expand">False</property>
|
|
| 2481 |
- <property name="fill">True</property>
|
|
| 2482 |
- <property name="position">0</property>
|
|
| 2483 |
- </packing>
|
|
| 2484 | 2594 |
</child>
|
| 2485 | 2595 |
</object>
|
| 2486 | 2596 |
<packing>
|
| 2487 |
- <property name="expand">False</property>
|
|
| 2597 |
+ <property name="expand">True</property>
|
|
| 2488 | 2598 |
<property name="fill">True</property>
|
| 2489 |
- <property name="position">1</property>
|
|
| 2599 |
+ <property name="position">2</property>
|
|
| 2490 | 2600 |
</packing>
|
| 2491 | 2601 |
</child>
|
| 2492 | 2602 |
</object>
|
| ... | ... | @@ -71,18 +71,6 @@ messages = { |
| 71 | 71 |
_('Custom hostname "%s" is wrong. It will be ignored.'),
|
| 72 | 72 |
ErrorDialog),
|
| 73 | 73 |
|
| 74 |
- 'privacy-list-error': Message(
|
|
| 75 |
- _('Error While Removing Privacy List'),
|
|
| 76 |
- _('Privacy list %s has not been removed. '
|
|
| 77 |
- 'It is probably active in one of your connected resources. '
|
|
| 78 |
- 'Please deactivate it and try again.'),
|
|
| 79 |
- ErrorDialog),
|
|
| 80 |
- |
|
| 81 |
- 'invisibility-not-supported': Message(
|
|
| 82 |
- _('Invisibility Not Supported'),
|
|
| 83 |
- _('This account %s doesn\'t support invisibility.'),
|
|
| 84 |
- ErrorDialog),
|
|
| 85 |
- |
|
| 86 | 74 |
'agent-register-success': Message(
|
| 87 | 75 |
_('Registration Succeeded'),
|
| 88 | 76 |
_('Registration with agent %s succeeded.'),
|
| ... | ... | @@ -218,6 +218,7 @@ class GroupchatControl(ChatControlBase): |
| 218 | 218 |
('signed-in', ged.GUI1, self._on_signed_in),
|
| 219 | 219 |
('decrypted-message-received', ged.GUI2, self._on_decrypted_message_received),
|
| 220 | 220 |
('message-sent', ged.OUT_POSTCORE, self._on_message_sent),
|
| 221 |
+ ('message-error', ged.GUI1, self._on_message_error),
|
|
| 221 | 222 |
('bookmarks-received', ged.GUI2, self._on_bookmarks_received),
|
| 222 | 223 |
])
|
| 223 | 224 |
# pylint: enable=line-too-long
|
| ... | ... | @@ -241,6 +242,7 @@ class GroupchatControl(ChatControlBase): |
| 241 | 242 |
# PluginSystem: adding GUI extension point for this GroupchatControl
|
| 242 | 243 |
# instance object
|
| 243 | 244 |
app.plugin_manager.gui_extension_point('groupchat_control', self)
|
| 245 |
+ self._restore_conversation()
|
|
| 244 | 246 |
|
| 245 | 247 |
@property
|
| 246 | 248 |
def nick(self):
|
| ... | ... | @@ -275,8 +277,6 @@ class GroupchatControl(ChatControlBase): |
| 275 | 277 |
('invite-', None, self._on_invite),
|
| 276 | 278 |
('contact-information-', 's', self._on_contact_information),
|
| 277 | 279 |
('execute-command-', 's', self._on_execute_command),
|
| 278 |
- ('block-', 's', self._on_block),
|
|
| 279 |
- ('unblock-', 's', self._on_unblock),
|
|
| 280 | 280 |
('ban-', 's', self._on_ban),
|
| 281 | 281 |
('kick-', 's', self._on_kick),
|
| 282 | 282 |
('change-role-', 'as', self._on_change_role),
|
| ... | ... | @@ -440,17 +440,29 @@ class GroupchatControl(ChatControlBase): |
| 440 | 440 |
|
| 441 | 441 |
self._get_action('execute-command-').set_enabled(self.is_connected)
|
| 442 | 442 |
|
| 443 |
- block_supported = con.get_module('PrivacyLists').supported
|
|
| 444 |
- self._get_action('block-').set_enabled(self.is_connected and
|
|
| 445 |
- block_supported)
|
|
| 446 |
- |
|
| 447 |
- self._get_action('unblock-').set_enabled(self.is_connected and
|
|
| 448 |
- block_supported)
|
|
| 449 |
- |
|
| 450 | 443 |
self._get_action('ban-').set_enabled(self.is_connected)
|
| 451 | 444 |
|
| 452 | 445 |
self._get_action('kick-').set_enabled(self.is_connected)
|
| 453 | 446 |
|
| 447 |
+ def _restore_conversation(self):
|
|
| 448 |
+ rows = app.logger.load_groupchat_messages(
|
|
| 449 |
+ self.account, self.contact.jid)
|
|
| 450 |
+ |
|
| 451 |
+ for row in rows:
|
|
| 452 |
+ other_tags_for_name = ['muc_nickname_color_%s' % row.contact_name]
|
|
| 453 |
+ ChatControlBase.add_message(self,
|
|
| 454 |
+ row.message,
|
|
| 455 |
+ 'incoming',
|
|
| 456 |
+ row.contact_name,
|
|
| 457 |
+ float(row.time),
|
|
| 458 |
+ other_tags_for_name=other_tags_for_name,
|
|
| 459 |
+ message_id=row.message_id,
|
|
| 460 |
+ restored=True,
|
|
| 461 |
+ additional_data=row.additional_data)
|
|
| 462 |
+ |
|
| 463 |
+ if rows:
|
|
| 464 |
+ self.conv_textview.print_empty_line()
|
|
| 465 |
+ |
|
| 454 | 466 |
def _is_subject_change_allowed(self):
|
| 455 | 467 |
contact = app.contacts.get_gc_contact(
|
| 456 | 468 |
self.account, self.room_jid, self.nick)
|
| ... | ... | @@ -521,11 +533,17 @@ class GroupchatControl(ChatControlBase): |
| 521 | 533 |
|
| 522 | 534 |
def _on_invite_clicked(self, _button):
|
| 523 | 535 |
invitees = self._invite_box.get_invitees()
|
| 524 |
- con = app.connections[self.account]
|
|
| 525 | 536 |
for jid in invitees:
|
| 526 |
- con.get_module('MUC').invite(self.room_jid, jid)
|
|
| 537 |
+ self.invite(jid)
|
|
| 527 | 538 |
self._show_page('groupchat')
|
| 528 | 539 |
|
| 540 |
+ def invite(self, contact_jid):
|
|
| 541 |
+ con = app.connections[self.account]
|
|
| 542 |
+ message_id = con.get_module('MUC').invite(self.room_jid, contact_jid)
|
|
| 543 |
+ self.add_info_message(
|
|
| 544 |
+ _(f'{contact_jid} has been invited to this group chat'),
|
|
| 545 |
+ message_id=message_id)
|
|
| 546 |
+ |
|
| 529 | 547 |
def _on_destroy_room(self, _action, _param):
|
| 530 | 548 |
self.xml.destroy_reason_entry.grab_focus()
|
| 531 | 549 |
self.xml.destroy_button.grab_default()
|
| ... | ... | @@ -661,20 +679,6 @@ class GroupchatControl(ChatControlBase): |
| 661 | 679 |
app.interface.instances[self.account]['infos'][contact.jid] = \
|
| 662 | 680 |
vcard.VcardWindow(contact, self.account, gc_contact)
|
| 663 | 681 |
|
| 664 |
- def _on_block(self, _action, param):
|
|
| 665 |
- nick = param.get_string()
|
|
| 666 |
- fjid = self.room_jid + '/' + nick
|
|
| 667 |
- con = app.connections[self.account]
|
|
| 668 |
- con.get_module('PrivacyLists').block_gc_contact(fjid)
|
|
| 669 |
- self.roster.draw_contact(nick)
|
|
| 670 |
- |
|
| 671 |
- def _on_unblock(self, _action, param):
|
|
| 672 |
- nick = param.get_string()
|
|
| 673 |
- fjid = self.room_jid + '/' + nick
|
|
| 674 |
- con = app.connections[self.account]
|
|
| 675 |
- con.get_module('PrivacyLists').unblock_gc_contact(fjid)
|
|
| 676 |
- self.roster.draw_contact(nick)
|
|
| 677 |
- |
|
| 678 | 682 |
def _on_kick(self, _action, param):
|
| 679 | 683 |
nick = param.get_string()
|
| 680 | 684 |
self._kick_nick = nick
|
| ... | ... | @@ -1780,10 +1784,7 @@ class GroupchatControl(ChatControlBase): |
| 1780 | 1784 |
return
|
| 1781 | 1785 |
contact_jid = data
|
| 1782 | 1786 |
|
| 1783 |
- con = app.connections[self.account]
|
|
| 1784 |
- con.get_module('MUC').invite(self.room_jid, contact_jid)
|
|
| 1785 |
- self.add_info_message(_('%(jid)s has been invited to this '
|
|
| 1786 |
- 'group chat') % {'jid': contact_jid})
|
|
| 1787 |
+ self.invite(contact_jid)
|
|
| 1787 | 1788 |
|
| 1788 | 1789 |
def _jid_not_blocked(self, bare_jid: str) -> bool:
|
| 1789 | 1790 |
fjid = self.room_jid + '/' + bare_jid
|
| ... | ... | @@ -101,7 +101,6 @@ WINDOW_MODULES = { |
| 101 | 101 |
'StartChatDialog': 'gajim.gtk.start_chat',
|
| 102 | 102 |
'AddNewContactWindow': 'gajim.gtk.add_contact',
|
| 103 | 103 |
'SingleMessageWindow': 'gajim.gtk.single_message',
|
| 104 |
- 'PrivacyListsWindow': 'gajim.gtk.privacy_list',
|
|
| 105 | 104 |
'Bookmarks': 'gajim.gtk.bookmarks',
|
| 106 | 105 |
'AccountWizard': 'gajim.gtk.account_wizard',
|
| 107 | 106 |
'HistoryWindow': 'gajim.gtk.history',
|
| ... | ... | @@ -369,9 +369,12 @@ class Preferences(Gtk.ApplicationWindow): |
| 369 | 369 |
self._ui.av_dependencies_infobar.set_no_show_all(True)
|
| 370 | 370 |
self._ui.av_dependencies_infobar.hide()
|
| 371 | 371 |
|
| 372 |
- create_av_combobox('audio_input', AudioInputManager().get_devices())
|
|
| 373 |
- create_av_combobox('audio_output', AudioOutputManager().get_devices())
|
|
| 374 |
- create_av_combobox('video_input', VideoInputManager().get_devices())
|
|
| 372 |
+ create_av_combobox(
|
|
| 373 |
+ 'audio_input', AudioInputManager().get_devices())
|
|
| 374 |
+ create_av_combobox(
|
|
| 375 |
+ 'audio_output', AudioOutputManager().get_devices())
|
|
| 376 |
+ create_av_combobox(
|
|
| 377 |
+ 'video_input', VideoInputManager().get_devices())
|
|
| 375 | 378 |
|
| 376 | 379 |
create_av_combobox(
|
| 377 | 380 |
'video_framerate',
|
| ... | ... | @@ -393,99 +396,22 @@ class Preferences(Gtk.ApplicationWindow): |
| 393 | 396 |
st = app.config.get('video_see_self')
|
| 394 | 397 |
self._ui.video_see_self_checkbutton.set_active(st)
|
| 395 | 398 |
|
| 396 |
- def on_av_map(tab):
|
|
| 397 |
- label = self._ui.selected_video_output
|
|
| 398 |
- sink, widget, name = gstreamer.create_gtk_widget()
|
|
| 399 |
- if sink is None:
|
|
| 400 |
- log.error('Failed to obtain a working Gstreamer GTK+ sink, '
|
|
| 401 |
- 'video support will be disabled')
|
|
| 402 |
- self._ui.video_input_combobox.set_sensitive(False)
|
|
| 403 |
- label.set_markup(
|
|
| 404 |
- _('<span color="red" font-weight="bold">'
|
|
| 405 |
- 'Unavailable</span>, video support will be disabled'))
|
|
| 406 |
- return
|
|
| 407 |
- |
|
| 408 |
- text = ''
|
|
| 409 |
- if name == 'gtkglsink':
|
|
| 410 |
- text = _('<span color="green" font-weight="bold">'
|
|
| 411 |
- 'OpenGL</span> accelerated')
|
|
| 412 |
- elif name == 'gtksink':
|
|
| 413 |
- text = _('<span color="yellow" font-weight="bold">'
|
|
| 414 |
- 'Unaccelerated</span>')
|
|
| 415 |
- label.set_markup(text)
|
|
| 416 |
- if self.av_pipeline is None:
|
|
| 417 |
- self.av_pipeline = Gst.Pipeline.new('preferences-pipeline')
|
|
| 418 |
- else:
|
|
| 419 |
- self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 420 |
- self.av_pipeline.add(sink)
|
|
| 421 |
- self.av_sink = sink
|
|
| 422 |
- if self.av_widget is not None:
|
|
| 423 |
- tab.remove(self.av_widget)
|
|
| 424 |
- tab.add(widget)
|
|
| 425 |
- self.av_widget = widget
|
|
| 426 |
- |
|
| 427 |
- src_name = app.config.get('video_input_device')
|
|
| 428 |
- try:
|
|
| 429 |
- self.av_src = Gst.parse_bin_from_description(src_name, True)
|
|
| 430 |
- except GLib.Error:
|
|
| 431 |
- log.error('Failed to parse "%s" as Gstreamer element,'
|
|
| 432 |
- ' falling back to autovideosrc', src_name)
|
|
| 433 |
- self.av_src = None
|
|
| 434 |
- if self.av_src is not None:
|
|
| 435 |
- self.av_pipeline.add(self.av_src)
|
|
| 436 |
- self.av_src.link(self.av_sink)
|
|
| 437 |
- self.av_pipeline.set_state(Gst.State.PLAYING)
|
|
| 438 |
- else:
|
|
| 439 |
- # Parsing the pipeline stored in video_input_device failed,
|
|
| 440 |
- # let’s try the default one.
|
|
| 441 |
- self.av_src = Gst.ElementFactory.make('autovideosrc', None)
|
|
| 442 |
- if self.av_src is None:
|
|
| 443 |
- log.error('Failed to obtain a working Gstreamer source,'
|
|
| 444 |
- ' video will be disabled.')
|
|
| 445 |
- self._ui.video_input_combobox.set_sensitive(False)
|
|
| 446 |
- return
|
|
| 447 |
- # Great, this succeeded, let’s store it back into the
|
|
| 448 |
- # config and use it. We’ve made autovideosrc the first
|
|
| 449 |
- # element in the combobox so we can pick index 0 without
|
|
| 450 |
- # worry.
|
|
| 451 |
- combobox = self._ui.video_input_combobox
|
|
| 452 |
- combobox.set_active(0)
|
|
| 453 |
- |
|
| 454 |
- def on_av_unmap(tab):
|
|
| 455 |
- if self.av_pipeline is not None:
|
|
| 456 |
- self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 457 |
- if self.av_src is not None:
|
|
| 458 |
- self.av_pipeline.remove(self.av_src)
|
|
| 459 |
- self.av_src = None
|
|
| 460 |
- if self.av_sink is not None:
|
|
| 461 |
- self.av_pipeline.remove(self.av_sink)
|
|
| 462 |
- self.av_sink = None
|
|
| 463 |
- if self.av_widget is not None:
|
|
| 464 |
- tab.remove(self.av_widget)
|
|
| 465 |
- self.av_widget = None
|
|
| 466 |
- self.av_pipeline = None
|
|
| 467 |
- |
|
| 468 | 399 |
self.av_pipeline = None
|
| 469 | 400 |
self.av_src = None
|
| 470 | 401 |
self.av_sink = None
|
| 471 | 402 |
self.av_widget = None
|
| 472 |
- tab = self._ui.audio_video_tab
|
|
| 473 |
- tab.connect('map', on_av_map)
|
|
| 474 |
- tab.connect('unmap', on_av_unmap)
|
|
| 475 |
- |
|
| 476 | 403 |
else:
|
| 477 | 404 |
for opt_name in ('audio_input', 'audio_output', 'video_input',
|
| 478 | 405 |
'video_framerate', 'video_size'):
|
| 479 | 406 |
combobox = self._ui.get_object(opt_name + '_combobox')
|
| 480 | 407 |
combobox.set_sensitive(False)
|
| 408 |
+ self._ui.live_preview_checkbutton.set_sensitive(False)
|
|
| 481 | 409 |
|
| 482 | 410 |
# STUN
|
| 483 | 411 |
st = app.config.get('use_stun_server')
|
| 484 | 412 |
self._ui.stun_checkbutton.set_active(st)
|
| 485 |
- |
|
| 413 |
+ self._ui.stun_server_entry.set_sensitive(st)
|
|
| 486 | 414 |
self._ui.stun_server_entry.set_text(app.config.get('stun_server'))
|
| 487 |
- if not st:
|
|
| 488 |
- self._ui.stun_server_entry.set_sensitive(False)
|
|
| 489 | 415 |
|
| 490 | 416 |
### Advanced tab ###
|
| 491 | 417 |
|
| ... | ... | @@ -994,15 +920,89 @@ class Preferences(Gtk.ApplicationWindow): |
| 994 | 920 |
widget.set_active(0)
|
| 995 | 921 |
return
|
| 996 | 922 |
|
| 997 |
- self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 998 |
- if self.av_src is not None:
|
|
| 999 |
- self.av_pipeline.remove(self.av_src)
|
|
| 1000 |
- self.av_pipeline.add(src)
|
|
| 1001 |
- src.link(self.av_sink)
|
|
| 1002 |
- self.av_src = src
|
|
| 1003 |
- self.av_pipeline.set_state(Gst.State.PLAYING)
|
|
| 923 |
+ if self._ui.live_preview_checkbutton.get_active():
|
|
| 924 |
+ self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 925 |
+ if self.av_src is not None:
|
|
| 926 |
+ self.av_pipeline.remove(self.av_src)
|
|
| 927 |
+ self.av_pipeline.add(src)
|
|
| 928 |
+ src.link(self.av_sink)
|
|
| 929 |
+ self.av_src = src
|
|
| 930 |
+ self.av_pipeline.set_state(Gst.State.PLAYING)
|
|
| 1004 | 931 |
app.config.set('video_input_device', device)
|
| 1005 | 932 |
|
| 933 |
+ def _on_live_preview_toggled(self, widget):
|
|
| 934 |
+ if widget.get_active():
|
|
| 935 |
+ sink, widget, name = gstreamer.create_gtk_widget()
|
|
| 936 |
+ if sink is None:
|
|
| 937 |
+ log.error('Failed to obtain a working Gstreamer GTK+ sink, '
|
|
| 938 |
+ 'video support will be disabled')
|
|
| 939 |
+ self._ui.video_input_combobox.set_sensitive(False)
|
|
| 940 |
+ self._ui.selected_video_output.set_markup(
|
|
| 941 |
+ _('<span color="red" font-weight="bold">'
|
|
| 942 |
+ 'Unavailable</span>, video support will be disabled'))
|
|
| 943 |
+ return
|
|
| 944 |
+ |
|
| 945 |
+ text = ''
|
|
| 946 |
+ if name == 'gtkglsink':
|
|
| 947 |
+ text = _('<span color="green" font-weight="bold">'
|
|
| 948 |
+ 'OpenGL</span> accelerated')
|
|
| 949 |
+ elif name == 'gtksink':
|
|
| 950 |
+ text = _('<span color="yellow" font-weight="bold">'
|
|
| 951 |
+ 'Unaccelerated</span>')
|
|
| 952 |
+ self._ui.selected_video_output.set_markup(text)
|
|
| 953 |
+ if self.av_pipeline is None:
|
|
| 954 |
+ self.av_pipeline = Gst.Pipeline.new('preferences-pipeline')
|
|
| 955 |
+ else:
|
|
| 956 |
+ self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 957 |
+ self.av_pipeline.add(sink)
|
|
| 958 |
+ self.av_sink = sink
|
|
| 959 |
+ |
|
| 960 |
+ if self.av_widget is not None:
|
|
| 961 |
+ self._ui.av_preview_box.remove(self.av_widget)
|
|
| 962 |
+ self._ui.av_preview_placeholder.set_visible(False)
|
|
| 963 |
+ self._ui.av_preview_box.add(widget)
|
|
| 964 |
+ self.av_widget = widget
|
|
| 965 |
+ |
|
| 966 |
+ src_name = app.config.get('video_input_device')
|
|
| 967 |
+ try:
|
|
| 968 |
+ self.av_src = Gst.parse_bin_from_description(src_name, True)
|
|
| 969 |
+ except GLib.Error:
|
|
| 970 |
+ log.error('Failed to parse "%s" as Gstreamer element, '
|
|
| 971 |
+ 'falling back to autovideosrc', src_name)
|
|
| 972 |
+ self.av_src = None
|
|
| 973 |
+ if self.av_src is not None:
|
|
| 974 |
+ self.av_pipeline.add(self.av_src)
|
|
| 975 |
+ self.av_src.link(self.av_sink)
|
|
| 976 |
+ self.av_pipeline.set_state(Gst.State.PLAYING)
|
|
| 977 |
+ else:
|
|
| 978 |
+ # Parsing the pipeline stored in video_input_device failed,
|
|
| 979 |
+ # let’s try the default one.
|
|
| 980 |
+ self.av_src = Gst.ElementFactory.make('autovideosrc', None)
|
|
| 981 |
+ if self.av_src is None:
|
|
| 982 |
+ log.error('Failed to obtain a working Gstreamer source, '
|
|
| 983 |
+ 'video will be disabled.')
|
|
| 984 |
+ self._ui.video_input_combobox.set_sensitive(False)
|
|
| 985 |
+ return
|
|
| 986 |
+ # Great, this succeeded, let’s store it back into the
|
|
| 987 |
+ # config and use it. We’ve made autovideosrc the first
|
|
| 988 |
+ # element in the combobox so we can pick index 0 without
|
|
| 989 |
+ # worry.
|
|
| 990 |
+ self._ui.video_input_combobox.set_active(0)
|
|
| 991 |
+ else:
|
|
| 992 |
+ if self.av_pipeline is not None:
|
|
| 993 |
+ self.av_pipeline.set_state(Gst.State.NULL)
|
|
| 994 |
+ if self.av_src is not None:
|
|
| 995 |
+ self.av_pipeline.remove(self.av_src)
|
|
| 996 |
+ self.av_src = None
|
|
| 997 |
+ if self.av_sink is not None:
|
|
| 998 |
+ self.av_pipeline.remove(self.av_sink)
|
|
| 999 |
+ self.av_sink = None
|
|
| 1000 |
+ if self.av_widget is not None:
|
|
| 1001 |
+ self._ui.av_preview_box.remove(self.av_widget)
|
|
| 1002 |
+ self._ui.av_preview_placeholder.set_visible(True)
|
|
| 1003 |
+ self.av_widget = None
|
|
| 1004 |
+ self.av_pipeline = None
|
|
| 1005 |
+ |
|
| 1006 | 1006 |
def on_video_framerate_combobox_changed(self, widget):
|
| 1007 | 1007 |
self.on_av_combobox_changed(widget, 'video_framerate')
|
| 1008 | 1008 |
|
| 1 |
-# This file is part of Gajim.
|
|
| 2 |
-#
|
|
| 3 |
-# Gajim is free software; you can redistribute it and/or modify
|
|
| 4 |
-# it under the terms of the GNU General Public License as published
|
|
| 5 |
-# by the Free Software Foundation; version 3 only.
|
|
| 6 |
-#
|
|
| 7 |
-# Gajim is distributed in the hope that it will be useful,
|
|
| 8 |
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| 9 |
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| 10 |
-# GNU General Public License for more details.
|
|
| 11 |
-#
|
|
| 12 |
-# You should have received a copy of the GNU General Public License
|
|
| 13 |
-# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
| 14 |
- |
|
| 15 |
-from gi.repository import Gdk
|
|
| 16 |
-from gi.repository import Gtk
|
|
| 17 |
-from gi.repository import GLib
|
|
| 18 |
-from gi.repository import GObject
|
|
| 19 |
- |
|
| 20 |
-from gajim.common import app
|
|
| 21 |
-from gajim.common import ged
|
|
| 22 |
-from gajim.common.i18n import _
|
|
| 23 |
-from gajim.common.nec import EventHelper
|
|
| 24 |
- |
|
| 25 |
-from gajim.gtk.dialogs import ErrorDialog
|
|
| 26 |
-from gajim.gtk.util import get_builder
|
|
| 27 |
- |
|
| 28 |
- |
|
| 29 |
-class PrivacyListWindow(EventHelper):
|
|
| 30 |
- def __init__(self, account, privacy_list_name, action):
|
|
| 31 |
- # action is 'EDIT' or 'NEW' depending on if we create a new priv list
|
|
| 32 |
- # or edit an already existing one
|
|
| 33 |
- EventHelper.__init__(self)
|
|
| 34 |
- self.account = account
|
|
| 35 |
- self.privacy_list_name = privacy_list_name
|
|
| 36 |
- |
|
| 37 |
- # Dicts and Default Values
|
|
| 38 |
- self.active_rule = ''
|
|
| 39 |
- self.global_rules = {}
|
|
| 40 |
- self.list_of_groups = {}
|
|
| 41 |
- |
|
| 42 |
- self.max_order = 0
|
|
| 43 |
- |
|
| 44 |
- # Default Edit Values
|
|
| 45 |
- self.edit_rule_type = 'jid'
|
|
| 46 |
- self.allow_deny = 'allow'
|
|
| 47 |
- |
|
| 48 |
- # Connect to gtk builder
|
|
| 49 |
- self._ui = get_builder('privacy_list_window.ui')
|
|
| 50 |
- self.window = self._ui.get_object('privacy_list_edit_window')
|
|
| 51 |
- |
|
| 52 |
- self._ui.privacy_lists_title_label.set_label(
|
|
| 53 |
- _('Privacy List <b><i>%s</i></b>') %
|
|
| 54 |
- GLib.markup_escape_text(self.privacy_list_name))
|
|
| 55 |
- |
|
| 56 |
- if len(app.connections) > 1:
|
|
| 57 |
- title = _('Privacy List for %s') % self.account
|
|
| 58 |
- else:
|
|
| 59 |
- title = _('Privacy List')
|
|
| 60 |
- |
|
| 61 |
- self._ui.delete_rule_button.set_sensitive(False)
|
|
| 62 |
- self._ui.open_rule_button.set_sensitive(False)
|
|
| 63 |
- self._ui.privacy_list_active_checkbutton.set_sensitive(False)
|
|
| 64 |
- self._ui.privacy_list_default_checkbutton.set_sensitive(False)
|
|
| 65 |
- self._ui.list_of_rules_combobox.set_sensitive(False)
|
|
| 66 |
- |
|
| 67 |
- # set jabber id completion
|
|
| 68 |
- jids_list_store = Gtk.ListStore(GObject.TYPE_STRING)
|
|
| 69 |
- for jid in app.contacts.get_jid_list(self.account):
|
|
| 70 |
- jids_list_store.append([jid])
|
|
| 71 |
- jid_entry_completion = Gtk.EntryCompletion()
|
|
| 72 |
- jid_entry_completion.set_text_column(0)
|
|
| 73 |
- jid_entry_completion.set_model(jids_list_store)
|
|
| 74 |
- jid_entry_completion.set_popup_completion(True)
|
|
| 75 |
- self._ui.edit_type_jabberid_entry.set_completion(jid_entry_completion)
|
|
| 76 |
- if action == 'EDIT':
|
|
| 77 |
- self.refresh_rules()
|
|
| 78 |
- |
|
| 79 |
- model = self._ui.edit_type_group_combobox.get_model()
|
|
| 80 |
- count = 0
|
|
| 81 |
- for group in app.groups[self.account]:
|
|
| 82 |
- self.list_of_groups[group] = count
|
|
| 83 |
- count += 1
|
|
| 84 |
- model.append([group])
|
|
| 85 |
- self._ui.edit_type_group_combobox.set_active(0)
|
|
| 86 |
- |
|
| 87 |
- self.window.set_title(title)
|
|
| 88 |
- |
|
| 89 |
- # pylint: disable=line-too-long
|
|
| 90 |
- self.register_events([
|
|
| 91 |
- ('privacy-list-received', ged.GUI1, self._nec_privacy_list_received),
|
|
| 92 |
- ('privacy-lists-received', ged.GUI1, self._nec_privacy_lists_received)
|
|
| 93 |
- ])
|
|
| 94 |
- # pylint: enable=line-too-long
|
|
| 95 |
- |
|
| 96 |
- self.window.show_all()
|
|
| 97 |
- self._ui.add_edit_vbox.hide()
|
|
| 98 |
- |
|
| 99 |
- self._ui.connect_signals(self)
|
|
| 100 |
- |
|
| 101 |
- def on_key_press_event(self, _widget, event):
|
|
| 102 |
- if event.keyval == Gdk.KEY_Escape:
|
|
| 103 |
- self.window.destroy()
|
|
| 104 |
- |
|
| 105 |
- def _on_edit_window_destroy(self, _widget):
|
|
| 106 |
- key_name = 'privacy_list_%s' % self.privacy_list_name
|
|
| 107 |
- if key_name in app.interface.instances[self.account]:
|
|
| 108 |
- del app.interface.instances[self.account][key_name]
|
|
| 109 |
- self.unregister_events()
|
|
| 110 |
- |
|
| 111 |
- def _nec_privacy_lists_received(self, obj):
|
|
| 112 |
- if obj.conn.name != self.account:
|
|
| 113 |
- return
|
|
| 114 |
- if obj.active_list == self.privacy_list_name:
|
|
| 115 |
- self._ui.privacy_list_active_checkbutton.set_active(True)
|
|
| 116 |
- else:
|
|
| 117 |
- self._ui.privacy_list_active_checkbutton.set_active(False)
|
|
| 118 |
- if obj.default_list == self.privacy_list_name:
|
|
| 119 |
- self._ui.privacy_list_default_checkbutton.set_active(True)
|
|
| 120 |
- else:
|
|
| 121 |
- self._ui.privacy_list_default_checkbutton.set_active(False)
|
|
| 122 |
- |
|
| 123 |
- def privacy_list_received(self, rules):
|
|
| 124 |
- model = self._ui.list_of_rules_combobox.get_model()
|
|
| 125 |
- model.clear()
|
|
| 126 |
- self.global_rules = {}
|
|
| 127 |
- for rule in rules:
|
|
| 128 |
- if 'type' in rule:
|
|
| 129 |
- text_item = _(
|
|
| 130 |
- 'Order: %(order)s, action: %(action)s, type: %(type)s'
|
|
| 131 |
- ', value: %(value)s') % {
|
|
| 132 |
- 'order': rule['order'],
|
|
| 133 |
- 'action': rule['action'],
|
|
| 134 |
- 'type': rule['type'],
|
|
| 135 |
- 'value': rule['value']}
|
|
| 136 |
- else:
|
|
| 137 |
- text_item = _('Order: %(order)s, action: %(action)s') % \
|
|
| 138 |
- {'order': rule['order'], 'action': rule['action']}
|
|
| 139 |
- if int(rule['order']) > self.max_order:
|
|
| 140 |
- self.max_order = int(rule['order'])
|
|
| 141 |
- self.global_rules[text_item] = rule
|
|
| 142 |
- model.append([text_item])
|
|
| 143 |
- if not rules:
|
|
| 144 |
- self._ui.title_hbox.set_sensitive(False)
|
|
| 145 |
- self._ui.list_of_rules_combobox.set_sensitive(False)
|
|
| 146 |
- self._ui.delete_rule_button.set_sensitive(False)
|
|
| 147 |
- self._ui.open_rule_button.set_sensitive(False)
|
|
| 148 |
- self._ui.privacy_list_active_checkbutton.set_sensitive(False)
|
|
| 149 |
- self._ui.privacy_list_default_checkbutton.set_sensitive(False)
|
|
| 150 |
- else:
|
|
| 151 |
- self._ui.list_of_rules_combobox.set_active(0)
|
|
| 152 |
- self._ui.title_hbox.set_sensitive(True)
|
|
| 153 |
- self._ui.list_of_rules_combobox.set_sensitive(True)
|
|
| 154 |
- self._ui.delete_rule_button.set_sensitive(True)
|
|
| 155 |
- self._ui.open_rule_button.set_sensitive(True)
|
|
| 156 |
- self._ui.privacy_list_active_checkbutton.set_sensitive(True)
|
|
| 157 |
- self._ui.privacy_list_default_checkbutton.set_sensitive(True)
|
|
| 158 |
- self.reset_fields()
|
|
| 159 |
- con = app.connections[self.account]
|
|
| 160 |
- con.get_module('PrivacyLists').get_privacy_lists()
|
|
| 161 |
- |
|
| 162 |
- def _nec_privacy_list_received(self, obj):
|
|
| 163 |
- if obj.conn.name != self.account:
|
|
| 164 |
- return
|
|
| 165 |
- if obj.list_name != self.privacy_list_name:
|
|
| 166 |
- return
|
|
| 167 |
- self.privacy_list_received(obj.rules)
|
|
| 168 |
- |
|
| 169 |
- def refresh_rules(self):
|
|
| 170 |
- con = app.connections[self.account]
|
|
| 171 |
- con.get_module('PrivacyLists').get_privacy_list(self.privacy_list_name)
|
|
| 172 |
- |
|
| 173 |
- def on_delete_rule_button_clicked(self, _widget):
|
|
| 174 |
- model = self._ui.list_of_rules_combobox.get_model()
|
|
| 175 |
- iter_ = self._ui.list_of_rules_combobox.get_active_iter()
|
|
| 176 |
- _rule = model[iter_][0]
|
|
| 177 |
- tags = []
|
|
| 178 |
- for rule in self.global_rules:
|
|
| 179 |
- if rule != _rule:
|
|
| 180 |
- tags.append(self.global_rules[rule])
|
|
| 181 |
- con = app.connections[self.account]
|
|
| 182 |
- con.get_module('PrivacyLists').set_privacy_list(
|
|
| 183 |
- self.privacy_list_name, tags)
|
|
| 184 |
- self.privacy_list_received(tags)
|
|
| 185 |
- self._ui.add_edit_vbox.hide()
|
|
| 186 |
- if not tags: # we removed latest rule
|
|
| 187 |
- if 'privacy_lists' in app.interface.instances[self.account]:
|
|
| 188 |
- win = app.interface.instances[self.account]['privacy_lists']
|
|
| 189 |
- win.remove_privacy_list(self.privacy_list_name)
|
|
| 190 |
- win.draw_widgets()
|
|
| 191 |
- |
|
| 192 |
- def on_open_rule_button_clicked(self, _widget):
|
|
| 193 |
- self._ui.add_edit_rule_label.set_label(_('<b>Edit a rule</b>'))
|
|
| 194 |
- active_num = self._ui.list_of_rules_combobox.get_active()
|
|
| 195 |
- if active_num == -1:
|
|
| 196 |
- self.active_rule = ''
|
|
| 197 |
- else:
|
|
| 198 |
- model = self._ui.list_of_rules_combobox.get_model()
|
|
| 199 |
- iter_ = self._ui.list_of_rules_combobox.get_active_iter()
|
|
| 200 |
- self.active_rule = model[iter_][0]
|
|
| 201 |
- if self.active_rule != '':
|
|
| 202 |
- rule_info = self.global_rules[self.active_rule]
|
|
| 203 |
- self._ui.edit_order_spinbutton.set_value(int(rule_info['order']))
|
|
| 204 |
- if 'type' in rule_info:
|
|
| 205 |
- if rule_info['type'] == 'jid':
|
|
| 206 |
- self._ui.edit_type_jabberid_radiobutton.set_active(True)
|
|
| 207 |
- self._ui.edit_type_jabberid_entry.set_text(
|
|
| 208 |
- rule_info['value'])
|
|
| 209 |
- elif rule_info['type'] == 'group':
|
|
| 210 |
- self._ui.edit_type_group_radiobutton.set_active(True)
|
|
| 211 |
- if rule_info['value'] in self.list_of_groups:
|
|
| 212 |
- self._ui.edit_type_group_combobox.set_active(
|
|
| 213 |
- self.list_of_groups[rule_info['value']])
|
|
| 214 |
- else:
|
|
| 215 |
- self._ui.edit_type_group_combobox.set_active(0)
|
|
| 216 |
- elif rule_info['type'] == 'subscription':
|
|
| 217 |
- self._ui.edit_type_subscription_radiobutton.set_active(True)
|
|
| 218 |
- sub_value = rule_info['value']
|
|
| 219 |
- if sub_value == 'none':
|
|
| 220 |
- self._ui.edit_type_subscription_combobox.set_active(0)
|
|
| 221 |
- elif sub_value == 'both':
|
|
| 222 |
- self._ui.edit_type_subscription_combobox.set_active(1)
|
|
| 223 |
- elif sub_value == 'from':
|
|
| 224 |
- self._ui.edit_type_subscription_combobox.set_active(2)
|
|
| 225 |
- elif sub_value == 'to':
|
|
| 226 |
- self._ui.edit_type_subscription_combobox.set_active(3)
|
|
| 227 |
- else:
|
|
| 228 |
- self._ui.edit_type_select_all_radiobutton.set_active(True)
|
|
| 229 |
- else:
|
|
| 230 |
- self._ui.edit_type_select_all_radiobutton.set_active(True)
|
|
| 231 |
- self._ui.edit_send_messages_checkbutton.set_active(False)
|
|
| 232 |
- self._ui.edit_queries_send_checkbutton.set_active(False)
|
|
| 233 |
- self._ui.edit_view_status_checkbutton.set_active(False)
|
|
| 234 |
- self._ui.edit_send_status_checkbutton.set_active(False)
|
|
| 235 |
- self._ui.edit_all_checkbutton.set_active(False)
|
|
| 236 |
- if not rule_info['child']:
|
|
| 237 |
- self._ui.edit_all_checkbutton.set_active(True)
|
|
| 238 |
- else:
|
|
| 239 |
- if 'presence-out' in rule_info['child']:
|
|
| 240 |
- self._ui.edit_send_status_checkbutton.set_active(True)
|
|
| 241 |
- if 'presence-in' in rule_info['child']:
|
|
| 242 |
- self._ui.edit_view_status_checkbutton.set_active(True)
|
|
| 243 |
- if 'iq' in rule_info['child']:
|
|
| 244 |
- self._ui.edit_queries_send_checkbutton.set_active(True)
|
|
| 245 |
- if 'message' in rule_info['child']:
|
|
| 246 |
- self._ui.edit_send_messages_checkbutton.set_active(True)
|
|
| 247 |
- |
|
| 248 |
- if rule_info['action'] == 'allow':
|
|
| 249 |
- self._ui.edit_allow_radiobutton.set_active(True)
|
|
| 250 |
- else:
|
|
| 251 |
- self._ui.edit_deny_radiobutton.set_active(True)
|
|
| 252 |
- self._ui.add_edit_vbox.show()
|
|
| 253 |
- |
|
| 254 |
- def on_edit_all_checkbutton_toggled(self, widget):
|
|
| 255 |
- if widget.get_active():
|
|
| 256 |
- self._ui.edit_send_messages_checkbutton.set_active(True)
|
|
| 257 |
- self._ui.edit_queries_send_checkbutton.set_active(True)
|
|
| 258 |
- self._ui.edit_view_status_checkbutton.set_active(True)
|
|
| 259 |
- self._ui.edit_send_status_checkbutton.set_active(True)
|
|
| 260 |
- self._ui.edit_send_messages_checkbutton.set_sensitive(False)
|
|
| 261 |
- self._ui.edit_queries_send_checkbutton.set_sensitive(False)
|
|
| 262 |
- self._ui.edit_view_status_checkbutton.set_sensitive(False)
|
|
| 263 |
- self._ui.edit_send_status_checkbutton.set_sensitive(False)
|
|
| 264 |
- else:
|
|
| 265 |
- self._ui.edit_send_messages_checkbutton.set_active(False)
|
|
| 266 |
- self._ui.edit_queries_send_checkbutton.set_active(False)
|
|
| 267 |
- self._ui.edit_view_status_checkbutton.set_active(False)
|
|
| 268 |
- self._ui.edit_send_status_checkbutton.set_active(False)
|
|
| 269 |
- self._ui.edit_send_messages_checkbutton.set_sensitive(True)
|
|
| 270 |
- self._ui.edit_queries_send_checkbutton.set_sensitive(True)
|
|
| 271 |
- self._ui.edit_view_status_checkbutton.set_sensitive(True)
|
|
| 272 |
- self._ui.edit_send_status_checkbutton.set_sensitive(True)
|
|
| 273 |
- |
|
| 274 |
- def _on_privacy_list_active_toggled(self, widget):
|
|
| 275 |
- name = None
|
|
| 276 |
- if widget.get_active():
|
|
| 277 |
- name = self.privacy_list_name
|
|
| 278 |
- |
|
| 279 |
- con = app.connections[self.account]
|
|
| 280 |
- con.get_module('PrivacyLists').set_active_list(name)
|
|
| 281 |
- |
|
| 282 |
- def _on_privacy_list_default_toggled(self, widget):
|
|
| 283 |
- name = None
|
|
| 284 |
- if widget.get_active():
|
|
| 285 |
- name = self.privacy_list_name
|
|
| 286 |
- |
|
| 287 |
- con = app.connections[self.account]
|
|
| 288 |
- con.get_module('PrivacyLists').set_default_list(name)
|
|
| 289 |
- |
|
| 290 |
- def on_new_rule_button_clicked(self, _widget):
|
|
| 291 |
- self.reset_fields()
|
|
| 292 |
- self._ui.add_edit_vbox.show()
|
|
| 293 |
- |
|
| 294 |
- def reset_fields(self):
|
|
| 295 |
- self._ui.edit_type_jabberid_entry.set_text('')
|
|
| 296 |
- self._ui.edit_allow_radiobutton.set_active(True)
|
|
| 297 |
- self._ui.edit_type_jabberid_radiobutton.set_active(True)
|
|
| 298 |
- self.active_rule = ''
|
|
| 299 |
- self._ui.edit_send_messages_checkbutton.set_active(False)
|
|
| 300 |
- self._ui.edit_queries_send_checkbutton.set_active(False)
|
|
| 301 |
- self._ui.edit_view_status_checkbutton.set_active(False)
|
|
| 302 |
- self._ui.edit_send_status_checkbutton.set_active(False)
|
|
| 303 |
- self._ui.edit_all_checkbutton.set_active(False)
|
|
| 304 |
- self._ui.edit_order_spinbutton.set_value(self.max_order + 1)
|
|
| 305 |
- self._ui.edit_type_group_combobox.set_active(0)
|
|
| 306 |
- self._ui.edit_type_subscription_combobox.set_active(0)
|
|
| 307 |
- self._ui.add_edit_rule_label.set_label(_('<b>Add a rule</b>'))
|
|
| 308 |
- |
|
| 309 |
- def get_current_tags(self):
|
|
| 310 |
- if self._ui.edit_type_jabberid_radiobutton.get_active():
|
|
| 311 |
- edit_type = 'jid'
|
|
| 312 |
- edit_value = self._ui.edit_type_jabberid_entry.get_text()
|
|
| 313 |
- elif self._ui.edit_type_group_radiobutton.get_active():
|
|
| 314 |
- edit_type = 'group'
|
|
| 315 |
- model = self._ui.edit_type_group_combobox.get_model()
|
|
| 316 |
- iter_ = self._ui.edit_type_group_combobox.get_active_iter()
|
|
| 317 |
- edit_value = model[iter_][0]
|
|
| 318 |
- elif self._ui.edit_type_subscription_radiobutton.get_active():
|
|
| 319 |
- edit_type = 'subscription'
|
|
| 320 |
- subs = ['none', 'both', 'from', 'to']
|
|
| 321 |
- edit_value = subs[
|
|
| 322 |
- self._ui.edit_type_subscription_combobox.get_active()]
|
|
| 323 |
- elif self._ui.edit_type_select_all_radiobutton.get_active():
|
|
| 324 |
- edit_type = ''
|
|
| 325 |
- edit_value = ''
|
|
| 326 |
- edit_order = str(self._ui.edit_order_spinbutton.get_value_as_int())
|
|
| 327 |
- if self._ui.edit_allow_radiobutton.get_active():
|
|
| 328 |
- edit_deny = 'allow'
|
|
| 329 |
- else:
|
|
| 330 |
- edit_deny = 'deny'
|
|
| 331 |
- child = []
|
|
| 332 |
- if not self._ui.edit_all_checkbutton.get_active():
|
|
| 333 |
- if self._ui.edit_send_messages_checkbutton.get_active():
|
|
| 334 |
- child.append('message')
|
|
| 335 |
- if self._ui.edit_queries_send_checkbutton.get_active():
|
|
| 336 |
- child.append('iq')
|
|
| 337 |
- if self._ui.edit_send_status_checkbutton.get_active():
|
|
| 338 |
- child.append('presence-out')
|
|
| 339 |
- if self._ui.edit_view_status_checkbutton.get_active():
|
|
| 340 |
- child.append('presence-in')
|
|
| 341 |
- if edit_type != '':
|
|
| 342 |
- return {'order': edit_order, 'action': edit_deny,
|
|
| 343 |
- 'type': edit_type, 'value': edit_value, 'child': child}
|
|
| 344 |
- return {'order': edit_order, 'action': edit_deny, 'child': child}
|
|
| 345 |
- |
|
| 346 |
- def on_save_rule_button_clicked(self, _widget):
|
|
| 347 |
- tags = []
|
|
| 348 |
- current_tags = self.get_current_tags()
|
|
| 349 |
- if int(current_tags['order']) > self.max_order:
|
|
| 350 |
- self.max_order = int(current_tags['order'])
|
|
| 351 |
- if self.active_rule == '':
|
|
| 352 |
- tags.append(current_tags)
|
|
| 353 |
- |
|
| 354 |
- for rule in self.global_rules:
|
|
| 355 |
- if rule != self.active_rule:
|
|
| 356 |
- tags.append(self.global_rules[rule])
|
|
| 357 |
- else:
|
|
| 358 |
- tags.append(current_tags)
|
|
| 359 |
- |
|
| 360 |
- con = app.connections[self.account]
|
|
| 361 |
- con.get_module('PrivacyLists').set_privacy_list(
|
|
| 362 |
- self.privacy_list_name, tags)
|
|
| 363 |
- self.refresh_rules()
|
|
| 364 |
- self._ui.add_edit_vbox.hide()
|
|
| 365 |
- if 'privacy_lists' in app.interface.instances[self.account]:
|
|
| 366 |
- win = app.interface.instances[self.account]['privacy_lists']
|
|
| 367 |
- win.add_privacy_list_to_combobox(self.privacy_list_name)
|
|
| 368 |
- win.draw_widgets()
|
|
| 369 |
- |
|
| 370 |
- def _on_list_of_rules_changed(self, _widget):
|
|
| 371 |
- self._ui.add_edit_vbox.hide()
|
|
| 372 |
- |
|
| 373 |
- def _on_edit_type_changed(self, widget, radiobutton):
|
|
| 374 |
- active_bool = widget.get_active()
|
|
| 375 |
- if active_bool:
|
|
| 376 |
- self.edit_rule_type = radiobutton
|
|
| 377 |
- |
|
| 378 |
- def _on_edit_allow_changed(self, widget, radiobutton):
|
|
| 379 |
- active_bool = widget.get_active()
|
|
| 380 |
- if active_bool:
|
|
| 381 |
- self.allow_deny = radiobutton
|
|
| 382 |
- |
|
| 383 |
- def _on_close_clicked(self, _widget):
|
|
| 384 |
- self.window.destroy()
|
|
| 385 |
- |
|
| 386 |
- |
|
| 387 |
-class PrivacyListsWindow(EventHelper):
|
|
| 388 |
- """
|
|
| 389 |
- Window that is the main window for Privacy Lists; we can list there the
|
|
| 390 |
- privacy lists and ask to create a new one or edit an already there one
|
|
| 391 |
- """
|
|
| 392 |
- def __init__(self, account):
|
|
| 393 |
- EventHelper.__init__(self)
|
|
| 394 |
- self.account = account
|
|
| 395 |
- self.privacy_lists_save = []
|
|
| 396 |
- |
|
| 397 |
- self._ui = get_builder('privacy_lists_window.ui')
|
|
| 398 |
- |
|
| 399 |
- self.window = self._ui.get_object('privacy_lists_first_window')
|
|
| 400 |
- |
|
| 401 |
- self.draw_privacy_lists_in_combobox([])
|
|
| 402 |
- self.privacy_lists_refresh()
|
|
| 403 |
- |
|
| 404 |
- self.enabled = True
|
|
| 405 |
- |
|
| 406 |
- if len(app.connections) > 1:
|
|
| 407 |
- title = _('Privacy Lists for %s') % self.account
|
|
| 408 |
- else:
|
|
| 409 |
- title = _('Privacy Lists')
|
|
| 410 |
- |
|
| 411 |
- self.window.set_title(title)
|
|
| 412 |
- |
|
| 413 |
- # pylint: disable=line-too-long
|
|
| 414 |
- self.register_events([
|
|
| 415 |
- ('privacy-lists-received', ged.GUI1, self._nec_privacy_lists_received),
|
|
| 416 |
- ('privacy-list-removed', ged.GUI1, self._nec_privacy_lists_removed),
|
|
| 417 |
- ])
|
|
| 418 |
- # pylint: enable=line-too-long
|
|
| 419 |
- |
|
| 420 |
- self.window.show_all()
|
|
| 421 |
- |
|
| 422 |
- self._ui.connect_signals(self)
|
|
| 423 |
- |
|
| 424 |
- def on_key_press_event(self, _widget, event):
|
|
| 425 |
- if event.keyval == Gdk.KEY_Escape:
|
|
| 426 |
- self.window.destroy()
|
|
| 427 |
- |
|
| 428 |
- def _on_privacy_lists_first_destroy(self, _widget):
|
|
| 429 |
- if 'privacy_lists' in app.interface.instances[self.account]:
|
|
| 430 |
- del app.interface.instances[self.account]['privacy_lists']
|
|
| 431 |
- self.unregister_events()
|
|
| 432 |
- |
|
| 433 |
- def remove_privacy_list(self, privacy_list):
|
|
| 434 |
- if privacy_list not in self.privacy_lists_save:
|
|
| 435 |
- return
|
|
| 436 |
- |
|
| 437 |
- model = self._ui.list_of_privacy_lists_combobox.get_model()
|
|
| 438 |
- for entry in model:
|
|
| 439 |
- if entry[0] == privacy_list:
|
|
| 440 |
- model.remove(entry.iter)
|
|
| 441 |
- |
|
| 442 |
- self.privacy_lists_save.remove(privacy_list)
|
|
| 443 |
- |
|
| 444 |
- def add_privacy_list_to_combobox(self, privacy_list):
|
|
| 445 |
- if privacy_list in self.privacy_lists_save:
|
|
| 446 |
- return
|
|
| 447 |
- model = self._ui.list_of_privacy_lists_combobox.get_model()
|
|
| 448 |
- model.append([privacy_list])
|
|
| 449 |
- self.privacy_lists_save.append(privacy_list)
|
|
| 450 |
- |
|
| 451 |
- def draw_privacy_lists_in_combobox(self, privacy_lists):
|
|
| 452 |
- self._ui.list_of_privacy_lists_combobox.set_active(-1)
|
|
| 453 |
- self._ui.list_of_privacy_lists_combobox.get_model().clear()
|
|
| 454 |
- self.privacy_lists_save = []
|
|
| 455 |
- for add_item in privacy_lists:
|
|
| 456 |
- self.add_privacy_list_to_combobox(add_item)
|
|
| 457 |
- self.draw_widgets()
|
|
| 458 |
- |
|
| 459 |
- def draw_widgets(self):
|
|
| 460 |
- if not self.privacy_lists_save:
|
|
| 461 |
- self._ui.list_of_privacy_lists_combobox.set_sensitive(False)
|
|
| 462 |
- self._ui.open_privacy_list_button.set_sensitive(False)
|
|
| 463 |
- self._ui.delete_privacy_list_button.set_sensitive(False)
|
|
| 464 |
- else:
|
|
| 465 |
- self._ui.list_of_privacy_lists_combobox.set_sensitive(True)
|
|
| 466 |
- self._ui.list_of_privacy_lists_combobox.set_active(0)
|
|
| 467 |
- self._ui.open_privacy_list_button.set_sensitive(True)
|
|
| 468 |
- self._ui.delete_privacy_list_button.set_sensitive(True)
|
|
| 469 |
- |
|
| 470 |
- def _on_close_clicked(self, _widget):
|
|
| 471 |
- self.window.destroy()
|
|
| 472 |
- |
|
| 473 |
- def _on_delete_privacy_list_clicked(self, _widget):
|
|
| 474 |
- active_list = self.privacy_lists_save[
|
|
| 475 |
- self._ui.list_of_privacy_lists_combobox.get_active()]
|
|
| 476 |
- con = app.connections[self.account]
|
|
| 477 |
- con.get_module('PrivacyLists').del_privacy_list(active_list)
|
|
| 478 |
- |
|
| 479 |
- def privacy_list_removed(self, active_list):
|
|
| 480 |
- self.privacy_lists_save.remove(active_list)
|
|
| 481 |
- self.privacy_lists_received(self.privacy_lists_save)
|
|
| 482 |
- |
|
| 483 |
- def _nec_privacy_lists_removed(self, obj):
|
|
| 484 |
- if obj.conn.name != self.account:
|
|
| 485 |
- return
|
|
| 486 |
- self.privacy_list_removed(obj.list_name)
|
|
| 487 |
- |
|
| 488 |
- def privacy_lists_received(self, lists):
|
|
| 489 |
- privacy_lists = []
|
|
| 490 |
- for privacy_list in lists:
|
|
| 491 |
- privacy_lists.append(privacy_list)
|
|
| 492 |
- self.draw_privacy_lists_in_combobox(privacy_lists)
|
|
| 493 |
- |
|
| 494 |
- def _nec_privacy_lists_received(self, obj):
|
|
| 495 |
- if obj.conn.name != self.account:
|
|
| 496 |
- return
|
|
| 497 |
- self.privacy_lists_received(obj.lists)
|
|
| 498 |
- |
|
| 499 |
- def privacy_lists_refresh(self):
|
|
| 500 |
- con = app.connections[self.account]
|
|
| 501 |
- con.get_module('PrivacyLists').get_privacy_lists()
|
|
| 502 |
- |
|
| 503 |
- def _on_new_privacy_list_clicked(self, _widget):
|
|
| 504 |
- name = self._ui.new_privacy_list_entry.get_text()
|
|
| 505 |
- if not name:
|
|
| 506 |
- ErrorDialog(
|
|
| 507 |
- _('Invalid List Name'),
|
|
| 508 |
- _('You must enter a name to create a privacy list.'),
|
|
| 509 |
- transient_for=self.window)
|
|
| 510 |
- return
|
|
| 511 |
- key_name = 'privacy_list_%s' % name
|
|
| 512 |
- if key_name in app.interface.instances[self.account]:
|
|
| 513 |
- app.interface.instances[self.account][key_name].window.present()
|
|
| 514 |
- else:
|
|
| 515 |
- app.interface.instances[self.account][key_name] = \
|
|
| 516 |
- PrivacyListWindow(self.account, name, 'NEW')
|
|
| 517 |
- self._ui.new_privacy_list_entry.set_text('')
|
|
| 518 |
- |
|
| 519 |
- def _on_privacy_lists_refresh_clicked(self, _widget):
|
|
| 520 |
- self.privacy_lists_refresh()
|
|
| 521 |
- |
|
| 522 |
- def _on_open_privacy_list_clicked(self, _widget):
|
|
| 523 |
- name = self.privacy_lists_save[
|
|
| 524 |
- self._ui.list_of_privacy_lists_combobox.get_active()]
|
|
| 525 |
- key_name = 'privacy_list_%s' % name
|
|
| 526 |
- if key_name in app.interface.instances[self.account]:
|
|
| 527 |
- app.interface.instances[self.account][key_name].window.present()
|
|
| 528 |
- else:
|
|
| 529 |
- app.interface.instances[self.account][key_name] = \
|
|
| 530 |
- PrivacyListWindow(self.account, name, 'EDIT')
|
| ... | ... | @@ -258,8 +258,6 @@ class ServerInfo(Gtk.ApplicationWindow, EventHelper): |
| 258 | 258 |
max_file_size
|
| 259 | 259 |
|
| 260 | 260 |
return [
|
| 261 |
- Feature('XEP-0016: Privacy Lists',
|
|
| 262 |
- con.get_module('PrivacyLists').supported),
|
|
| 263 | 261 |
Feature('XEP-0045: Multi-User Chat',
|
| 264 | 262 |
con.get_module('MUC').supported),
|
| 265 | 263 |
Feature('XEP-0054: vcard-temp',
|
| ... | ... | @@ -391,8 +391,7 @@ control=None, gc_contact=None, is_anonymous=True): |
| 391 | 391 |
|
| 392 | 392 |
|
| 393 | 393 |
con = app.connections[account]
|
| 394 |
- if con and (con.get_module('PrivacyLists').supported or
|
|
| 395 |
- con.get_module('Blocking').supported):
|
|
| 394 |
+ if con.get_module('Blocking').supported:
|
|
| 396 | 395 |
transport = app.get_transport_name_from_jid(jid, use_config_setting=False)
|
| 397 | 396 |
if helpers.jid_is_blocked(account, jid):
|
| 398 | 397 |
block_menuitem.set_no_show_all(True)
|
| ... | ... | @@ -522,6 +521,7 @@ def get_singlechat_menu(control_id, account, jid): |
| 522 | 521 |
(_('Send Chatstate'), ['chatstate']),
|
| 523 | 522 |
('win.invite-contacts-', _('Invite Contacts…')),
|
| 524 | 523 |
('win.add-to-roster-', _('Add to Contact List…')),
|
| 524 |
+ ('win.block-contact-', _('Block Contact…')),
|
|
| 525 | 525 |
('win.toggle-audio-', _('Voice Chat')),
|
| 526 | 526 |
('win.toggle-video-', _('Video Chat')),
|
| 527 | 527 |
('win.information-', _('Information')),
|
| ... | ... | @@ -680,7 +680,6 @@ def get_account_menu(account): |
| 680 | 680 |
('-bookmarks', _('Bookmarks')),
|
| 681 | 681 |
('-pep-config', _('PEP Configuration')),
|
| 682 | 682 |
('-sync-history', _('Synchronise History…')),
|
| 683 |
- ('-privacylists', _('Privacy Lists')),
|
|
| 684 | 683 |
]),
|
| 685 | 684 |
(_('Admin'), [
|
| 686 | 685 |
('-send-server-message', _('Send Server Message…')),
|
| ... | ... | @@ -871,17 +870,6 @@ def get_groupchat_roster_menu(account, control_id, self_contact, contact): |
| 871 | 870 |
|
| 872 | 871 |
menu.append(Gtk.SeparatorMenuItem())
|
| 873 | 872 |
|
| 874 |
- if helpers.jid_is_blocked(account, contact.get_full_jid()):
|
|
| 875 |
- action = 'win.unblock-%s::%s' % (control_id, contact.name)
|
|
| 876 |
- label = _('Unblock')
|
|
| 877 |
- else:
|
|
| 878 |
- action = 'win.block-%s::%s' % (control_id, contact.name)
|
|
| 879 |
- label = _('Block')
|
|
| 880 |
- |
|
| 881 |
- item = Gtk.MenuItem(label=label)
|
|
| 882 |
- item.set_detailed_action_name(action)
|
|
| 883 |
- menu.append(item)
|
|
| 884 |
- |
|
| 885 | 873 |
item = Gtk.MenuItem(label=_('Kick'))
|
| 886 | 874 |
action = 'win.kick-%s::%s' % (control_id, contact.name)
|
| 887 | 875 |
if is_role_change_allowed(self_contact, contact):
|
| ... | ... | @@ -1073,8 +1073,6 @@ class RosterWindow: |
| 1073 | 1073 |
else:
|
| 1074 | 1074 |
accounts = [account]
|
| 1075 | 1075 |
text = GLib.markup_escape_text(group)
|
| 1076 |
- if helpers.group_is_blocked(account, group):
|
|
| 1077 |
- text = '<span strikethrough="true">%s</span>' % text
|
|
| 1078 | 1076 |
if app.config.get('show_contacts_number'):
|
| 1079 | 1077 |
nbr_on, nbr_total = app.contacts.get_nb_online_total_contacts(
|
| 1080 | 1078 |
accounts=accounts, groups=[group])
|
| ... | ... | @@ -1165,14 +1163,7 @@ class RosterWindow: |
| 1165 | 1163 |
name = '%s [%s]' % (name, str(nb_unread))
|
| 1166 | 1164 |
|
| 1167 | 1165 |
# Strike name if blocked
|
| 1168 |
- strike = False
|
|
| 1169 |
- if helpers.jid_is_blocked(account, jid):
|
|
| 1170 |
- strike = True
|
|
| 1171 |
- else:
|
|
| 1172 |
- for group in contact.get_shown_groups():
|
|
| 1173 |
- if helpers.group_is_blocked(account, group):
|
|
| 1174 |
- strike = True
|
|
| 1175 |
- break
|
|
| 1166 |
+ strike = helpers.jid_is_blocked(account, jid)
|
|
| 1176 | 1167 |
if strike:
|
| 1177 | 1168 |
name = '<span strikethrough="true">%s</span>' % name
|
| 1178 | 1169 |
|
| ... | ... | @@ -2744,55 +2735,40 @@ class RosterWindow: |
| 2744 | 2735 |
for jid in obj.changed:
|
| 2745 | 2736 |
self.draw_contact(jid, obj.conn.name)
|
| 2746 | 2737 |
|
| 2747 |
- def on_block(self, widget, list_, group=None):
|
|
| 2738 |
+ def on_block(self, widget, list_):
|
|
| 2748 | 2739 |
"""
|
| 2749 | 2740 |
When clicked on the 'block' button in context menu. list_ is a list of
|
| 2750 | 2741 |
(contact, account)
|
| 2751 | 2742 |
"""
|
| 2752 |
- def on_continue(msg, pep_dict):
|
|
| 2753 |
- if msg is None:
|
|
| 2754 |
- # user pressed Cancel to change status message dialog
|
|
| 2755 |
- return
|
|
| 2743 |
+ def _block_it(is_checked=None, report=None):
|
|
| 2744 |
+ if is_checked is not None: # Dialog has been shown
|
|
| 2745 |
+ if is_checked:
|
|
| 2746 |
+ app.config.set('confirm_block', 'no')
|
|
| 2747 |
+ else:
|
|
| 2748 |
+ app.config.set('confirm_block', 'yes')
|
|
| 2756 | 2749 |
|
| 2757 | 2750 |
accounts = []
|
| 2758 | 2751 |
for _, account in list_:
|
| 2759 | 2752 |
con = app.connections[account]
|
| 2760 |
- if con.get_module('PrivacyLists').supported or (
|
|
| 2761 |
- group is None and con.get_module('Blocking').supported):
|
|
| 2753 |
+ if con.get_module('Blocking').supported:
|
|
| 2762 | 2754 |
accounts.append(account)
|
| 2763 | 2755 |
|
| 2764 |
- if group is None:
|
|
| 2765 |
- for acct in accounts:
|
|
| 2766 |
- l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2767 |
- con = app.connections[acct]
|
|
| 2768 |
- con.get_module('PrivacyLists').block_contacts(l_, msg)
|
|
| 2769 |
- for contact in l_:
|
|
| 2770 |
- ctrl = app.interface.msg_win_mgr.get_control(
|
|
| 2771 |
- contact.jid, acct)
|
|
| 2772 |
- if ctrl:
|
|
| 2773 |
- ctrl.parent_win.remove_tab(
|
|
| 2774 |
- ctrl, ctrl.parent_win.CLOSE_COMMAND, force=True)
|
|
| 2775 |
- if contact.show == 'not in roster':
|
|
| 2776 |
- self.remove_contact(contact.jid, acct, force=True,
|
|
| 2777 |
- backend=True)
|
|
| 2778 |
- return
|
|
| 2779 |
- self.draw_contact(contact.jid, acct)
|
|
| 2780 |
- else:
|
|
| 2781 |
- for acct in accounts:
|
|
| 2782 |
- l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2783 |
- con = app.connections[acct]
|
|
| 2784 |
- con.get_module('PrivacyLists').block_group(group, l_, msg)
|
|
| 2785 |
- self.draw_group(group, acct)
|
|
| 2786 |
- for contact in l_:
|
|
| 2787 |
- self.draw_contact(contact.jid, acct)
|
|
| 2788 |
- |
|
| 2789 |
- def _block_it(is_checked=None):
|
|
| 2790 |
- if is_checked is not None: # dialog has been shown
|
|
| 2791 |
- if is_checked: # user does not want to be asked again
|
|
| 2792 |
- app.config.set('confirm_block', 'no')
|
|
| 2793 |
- else:
|
|
| 2794 |
- app.config.set('confirm_block', 'yes')
|
|
| 2795 |
- self.get_status_message('offline', on_continue, show_pep=False)
|
|
| 2756 |
+ for acct in accounts:
|
|
| 2757 |
+ l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2758 |
+ con = app.connections[acct]
|
|
| 2759 |
+ jid_list = [contact.jid for contact in l_]
|
|
| 2760 |
+ con.get_module('Blocking').block(jid_list, report)
|
|
| 2761 |
+ for contact in l_:
|
|
| 2762 |
+ ctrl = app.interface.msg_win_mgr.get_control(
|
|
| 2763 |
+ contact.jid, acct)
|
|
| 2764 |
+ if ctrl:
|
|
| 2765 |
+ ctrl.parent_win.remove_tab(
|
|
| 2766 |
+ ctrl, ctrl.parent_win.CLOSE_COMMAND, force=True)
|
|
| 2767 |
+ if contact.show == 'not in roster':
|
|
| 2768 |
+ self.remove_contact(contact.jid, acct, force=True,
|
|
| 2769 |
+ backend=True)
|
|
| 2770 |
+ return
|
|
| 2771 |
+ self.draw_contact(contact.jid, acct)
|
|
| 2796 | 2772 |
|
| 2797 | 2773 |
# Check if confirmation is needed for blocking
|
| 2798 | 2774 |
confirm_block = app.config.get('confirm_block')
|
| ... | ... | @@ -2800,61 +2776,39 @@ class RosterWindow: |
| 2800 | 2776 |
_block_it()
|
| 2801 | 2777 |
return
|
| 2802 | 2778 |
|
| 2803 |
- # Set dialog's labels depending on if it is a group or a single contact
|
|
| 2804 |
- if group is None:
|
|
| 2805 |
- title = _('Block Contact')
|
|
| 2806 |
- pritext = _('Really block this contact?')
|
|
| 2807 |
- sectext = _('This contact will see you offline and you will not '
|
|
| 2808 |
- 'receive any messages sent to you by this contact.')
|
|
| 2809 |
- button_text = _('_Block Contact')
|
|
| 2810 |
- else:
|
|
| 2811 |
- title = _('Block Group')
|
|
| 2812 |
- pritext = _('Really block this group?')
|
|
| 2813 |
- sectext = _('All contacts of this group will see you as offline '
|
|
| 2814 |
- 'and you will not receive any messages sent to you '
|
|
| 2815 |
- 'by any one of these contacts.')
|
|
| 2816 |
- button_text = _('_Block Group')
|
|
| 2817 |
- |
|
| 2818 | 2779 |
NewConfirmationCheckDialog(
|
| 2819 |
- title,
|
|
| 2820 |
- pritext,
|
|
| 2821 |
- sectext,
|
|
| 2822 |
- _('_Do not ask me again'),
|
|
| 2780 |
+ _('Block Contact'),
|
|
| 2781 |
+ _('Really block this contact?'),
|
|
| 2782 |
+ _('You will appear offline for this contact and you '
|
|
| 2783 |
+ 'will not receive further messages.'),
|
|
| 2784 |
+ _('_Do not ask again'),
|
|
| 2823 | 2785 |
[DialogButton.make('Cancel'),
|
| 2786 |
+ DialogButton.make('OK',
|
|
| 2787 |
+ text=_('_Report Spam'),
|
|
| 2788 |
+ callback=_block_it,
|
|
| 2789 |
+ kwargs={'report': 'spam'}),
|
|
| 2824 | 2790 |
DialogButton.make('Remove',
|
| 2825 |
- text=button_text,
|
|
| 2791 |
+ text=_('_Block'),
|
|
| 2826 | 2792 |
callback=_block_it)],
|
| 2827 | 2793 |
modal=False).show()
|
| 2828 | 2794 |
|
| 2829 |
- def on_unblock(self, widget, list_, group=None):
|
|
| 2795 |
+ def on_unblock(self, widget, list_):
|
|
| 2830 | 2796 |
"""
|
| 2831 | 2797 |
When clicked on the 'unblock' button in context menu.
|
| 2832 | 2798 |
"""
|
| 2833 | 2799 |
accounts = []
|
| 2834 | 2800 |
for _, account in list_:
|
| 2835 | 2801 |
con = app.connections[account]
|
| 2836 |
- if con.get_module('PrivacyLists').supported or (
|
|
| 2837 |
- group is None and con.get_module('Blocking').supported):
|
|
| 2802 |
+ if con.get_module('Blocking').supported:
|
|
| 2838 | 2803 |
accounts.append(account)
|
| 2839 | 2804 |
|
| 2840 |
- if group is None:
|
|
| 2841 |
- for acct in accounts:
|
|
| 2842 |
- l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2843 |
- con = app.connections[acct]
|
|
| 2844 |
- con.get_module('PrivacyLists').unblock_contacts(l_)
|
|
| 2845 |
- for contact in l_:
|
|
| 2846 |
- self.draw_contact(contact.jid, acct)
|
|
| 2847 |
- else:
|
|
| 2848 |
- for acct in accounts:
|
|
| 2849 |
- l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2850 |
- con = app.connections[acct]
|
|
| 2851 |
- con.get_module('PrivacyLists').unblock_group(group, l_)
|
|
| 2852 |
- self.draw_group(group, acct)
|
|
| 2853 |
- for contact in l_:
|
|
| 2854 |
- self.draw_contact(contact.jid, acct)
|
|
| 2855 | 2805 |
for acct in accounts:
|
| 2856 |
- if 'privacy_list_block' in app.interface.instances[acct]:
|
|
| 2857 |
- del app.interface.instances[acct]['privacy_list_block']
|
|
| 2806 |
+ l_ = [i[0] for i in list_ if i[1] == acct]
|
|
| 2807 |
+ con = app.connections[acct]
|
|
| 2808 |
+ jid_list = [contact.jid for contact in l_]
|
|
| 2809 |
+ con.get_module('Blocking').unblock(jid_list)
|
|
| 2810 |
+ for contact in l_:
|
|
| 2811 |
+ self.draw_contact(contact.jid, acct)
|
|
| 2858 | 2812 |
|
| 2859 | 2813 |
def on_rename(self, widget, row_type, jid, account):
|
| 2860 | 2814 |
# This function is called either by F2 or by Rename menuitem
|
| ... | ... | @@ -2967,24 +2921,24 @@ class RosterWindow: |
| 2967 | 2921 |
app.interface.instances['file_transfers'].show_file_send_request(
|
| 2968 | 2922 |
account, contact)
|
| 2969 | 2923 |
|
| 2970 |
- def on_invite_to_room(self, widget, list_, room_jid, room_account,
|
|
| 2971 |
- resource=None):
|
|
| 2924 |
+ def on_invite_to_room(self,
|
|
| 2925 |
+ _widget,
|
|
| 2926 |
+ list_,
|
|
| 2927 |
+ room_jid,
|
|
| 2928 |
+ room_account,
|
|
| 2929 |
+ resource=None):
|
|
| 2972 | 2930 |
"""
|
| 2973 | 2931 |
Resource parameter MUST NOT be used if more than one contact in list
|
| 2974 | 2932 |
"""
|
| 2975 |
- for e in list_:
|
|
| 2976 |
- contact = e[0]
|
|
| 2933 |
+ gc_control = app.get_groupchat_control(room_account, room_jid)
|
|
| 2934 |
+ if gc_control is None:
|
|
| 2935 |
+ return
|
|
| 2936 |
+ |
|
| 2937 |
+ for contact, _ in list_:
|
|
| 2977 | 2938 |
contact_jid = contact.jid
|
| 2978 | 2939 |
if resource: # we MUST have one contact only in list_
|
| 2979 | 2940 |
contact_jid += '/' + resource
|
| 2980 |
- con = app.connections[room_account]
|
|
| 2981 |
- con.get_module('MUC').invite(room_jid, contact_jid)
|
|
| 2982 |
- gc_control = app.interface.msg_win_mgr.get_gc_control(room_jid,
|
|
| 2983 |
- room_account)
|
|
| 2984 |
- if gc_control:
|
|
| 2985 |
- gc_control.add_info_message(
|
|
| 2986 |
- _('%(jid)s has been invited to this group chat') % {
|
|
| 2987 |
- 'jid': contact_jid})
|
|
| 2941 |
+ gc_control.invite(contact_jid)
|
|
| 2988 | 2942 |
|
| 2989 | 2943 |
def on_all_groupchat_maximized(self, widget, group_list):
|
| 2990 | 2944 |
for (contact, account) in group_list:
|
| ... | ... | @@ -4204,8 +4158,9 @@ class RosterWindow: |
| 4204 | 4158 |
if type_source != 'contact':
|
| 4205 | 4159 |
return
|
| 4206 | 4160 |
contact_jid = data
|
| 4207 |
- con = app.connections[account_dest]
|
|
| 4208 |
- con.get_module('MUC').invite(jid_dest, contact_jid)
|
|
| 4161 |
+ gc_control = app.get_groupchat_control(account_dest, jid_dest)
|
|
| 4162 |
+ if gc_control is not None:
|
|
| 4163 |
+ gc_control.invite(contact_jid)
|
|
| 4209 | 4164 |
return
|
| 4210 | 4165 |
|
| 4211 | 4166 |
if type_source == 'group':
|
| ... | ... | @@ -4902,28 +4857,6 @@ class RosterWindow: |
| 4902 | 4857 |
rename_item.connect('activate', self.on_rename, 'group', group,
|
| 4903 | 4858 |
account)
|
| 4904 | 4859 |
|
| 4905 |
- # Block group
|
|
| 4906 |
- is_blocked = False
|
|
| 4907 |
- if self.regroup:
|
|
| 4908 |
- for g_account in app.connections:
|
|
| 4909 |
- if helpers.group_is_blocked(g_account, group):
|
|
| 4910 |
- is_blocked = True
|
|
| 4911 |
- else:
|
|
| 4912 |
- if helpers.group_is_blocked(account, group):
|
|
| 4913 |
- is_blocked = True
|
|
| 4914 |
- |
|
| 4915 |
- if is_blocked and app.connections[account].get_module('PrivacyLists').supported:
|
|
| 4916 |
- unblock_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Unblock'))
|
|
| 4917 |
- unblock_menuitem.connect('activate', self.on_unblock, list_,
|
|
| 4918 |
- group)
|
|
| 4919 |
- menu.append(unblock_menuitem)
|
|
| 4920 |
- else:
|
|
| 4921 |
- block_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Block'))
|
|
| 4922 |
- block_menuitem.connect('activate', self.on_block, list_, group)
|
|
| 4923 |
- menu.append(block_menuitem)
|
|
| 4924 |
- if not app.connections[account].get_module('PrivacyLists').supported:
|
|
| 4925 |
- block_menuitem.set_sensitive(False)
|
|
| 4926 |
- |
|
| 4927 | 4860 |
# Remove group
|
| 4928 | 4861 |
remove_item = Gtk.MenuItem.new_with_mnemonic(_('Remo_ve'))
|
| 4929 | 4862 |
menu.append(remove_item)
|
| ... | ... | @@ -4967,16 +4900,18 @@ class RosterWindow: |
| 4967 | 4900 |
list_ = [] # list of (jid, account) tuples
|
| 4968 | 4901 |
one_account_offline = False
|
| 4969 | 4902 |
is_blocked = True
|
| 4970 |
- privacy_rules_supported = True
|
|
| 4903 |
+ blocking_supported = True
|
|
| 4971 | 4904 |
for titer in iters:
|
| 4972 | 4905 |
jid = model[titer][Column.JID]
|
| 4973 | 4906 |
account = model[titer][Column.ACCOUNT]
|
| 4974 | 4907 |
if not app.account_is_available(account):
|
| 4975 | 4908 |
one_account_offline = True
|
| 4976 |
- if not app.connections[account].get_module('PrivacyLists').supported:
|
|
| 4977 |
- privacy_rules_supported = False
|
|
| 4978 |
- contact = app.contacts.get_contact_with_highest_priority(account,
|
|
| 4979 |
- jid)
|
|
| 4909 |
+ |
|
| 4910 |
+ con = app.connections[account]
|
|
| 4911 |
+ if not con.get_module('Blocking').supported:
|
|
| 4912 |
+ blocking_supported = False
|
|
| 4913 |
+ contact = app.contacts.get_contact_with_highest_priority(
|
|
| 4914 |
+ account, jid)
|
|
| 4980 | 4915 |
if not helpers.jid_is_blocked(account, jid):
|
| 4981 | 4916 |
is_blocked = False
|
| 4982 | 4917 |
list_.append((contact, account))
|
| ... | ... | @@ -5027,7 +4962,7 @@ class RosterWindow: |
| 5027 | 4962 |
manage_contacts_submenu.append(item)
|
| 5028 | 4963 |
|
| 5029 | 4964 |
# Block
|
| 5030 |
- if is_blocked and privacy_rules_supported:
|
|
| 4965 |
+ if is_blocked and blocking_supported:
|
|
| 5031 | 4966 |
unblock_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Unblock'))
|
| 5032 | 4967 |
unblock_menuitem.connect('activate', self.on_unblock, list_)
|
| 5033 | 4968 |
manage_contacts_submenu.append(unblock_menuitem)
|
| ... | ... | @@ -5036,7 +4971,7 @@ class RosterWindow: |
| 5036 | 4971 |
block_menuitem.connect('activate', self.on_block, list_)
|
| 5037 | 4972 |
manage_contacts_submenu.append(block_menuitem)
|
| 5038 | 4973 |
|
| 5039 |
- if not privacy_rules_supported:
|
|
| 4974 |
+ if not blocking_supported:
|
|
| 5040 | 4975 |
block_menuitem.set_sensitive(False)
|
| 5041 | 4976 |
|
| 5042 | 4977 |
# Remove
|
| ... | ... | @@ -5122,75 +5057,6 @@ class RosterWindow: |
| 5122 | 5057 |
menu.show_all()
|
| 5123 | 5058 |
menu.popup(None, None, None, None, event_button, event.time)
|
| 5124 | 5059 |
|
| 5125 |
- def get_and_connect_advanced_menuitem_menu(self, account):
|
|
| 5126 |
- """
|
|
| 5127 |
- Add FOR ACCOUNT options
|
|
| 5128 |
- """
|
|
| 5129 |
- xml = get_builder('advanced_menuitem_menu.ui')
|
|
| 5130 |
- advanced_menuitem_menu = xml.get_object('advanced_menuitem_menu')
|
|
| 5131 |
- |
|
| 5132 |
- xml_console_menuitem = xml.get_object('xml_console_menuitem')
|
|
| 5133 |
- archiving_preferences_menuitem = xml.get_object(
|
|
| 5134 |
- 'archiving_preferences_menuitem')
|
|
| 5135 |
- privacy_lists_menuitem = xml.get_object('privacy_lists_menuitem')
|
|
| 5136 |
- administrator_menuitem = xml.get_object('administrator_menuitem')
|
|
| 5137 |
- send_server_message_menuitem = xml.get_object(
|
|
| 5138 |
- 'send_server_message_menuitem')
|
|
| 5139 |
- set_motd_menuitem = xml.get_object('set_motd_menuitem')
|
|
| 5140 |
- update_motd_menuitem = xml.get_object('update_motd_menuitem')
|
|
| 5141 |
- delete_motd_menuitem = xml.get_object('delete_motd_menuitem')
|
|
| 5142 |
- |
|
| 5143 |
- xml_console_menuitem.connect('activate',
|
|
| 5144 |
- self.on_xml_console_menuitem_activate, account)
|
|
| 5145 |
- |
|
| 5146 |
- if app.connections[account]:
|
|
| 5147 |
- if app.connections[account].get_module('PrivacyLists').supported:
|
|
| 5148 |
- privacy_lists_menuitem.connect('activate',
|
|
| 5149 |
- self.on_privacy_lists_menuitem_activate, account)
|
|
| 5150 |
- else:
|
|
| 5151 |
- privacy_lists_menuitem.set_sensitive(False)
|
|
| 5152 |
- if app.connections[account].get_module('MAM').available:
|
|
| 5153 |
- archiving_preferences_menuitem.connect(
|
|
| 5154 |
- 'activate',
|
|
| 5155 |
- self.on_archiving_preferences_menuitem_activate, account)
|
|
| 5156 |
- else:
|
|
| 5157 |
- archiving_preferences_menuitem.set_sensitive(False)
|
|
| 5158 |
- |
|
| 5159 |
- if app.connections[account].is_zeroconf:
|
|
| 5160 |
- administrator_menuitem.set_sensitive(False)
|
|
| 5161 |
- send_server_message_menuitem.set_sensitive(False)
|
|
| 5162 |
- set_motd_menuitem.set_sensitive(False)
|
|
| 5163 |
- update_motd_menuitem.set_sensitive(False)
|
|
| 5164 |
- delete_motd_menuitem.set_sensitive(False)
|
|
| 5165 |
- else:
|
|
| 5166 |
- send_server_message_menuitem.connect('activate',
|
|
| 5167 |
- self.on_send_server_message_menuitem_activate, account)
|
|
| 5168 |
- |
|
| 5169 |
- set_motd_menuitem.connect('activate',
|
|
| 5170 |
- self.on_set_motd_menuitem_activate, account)
|
|
| 5171 |
- |
|
| 5172 |
- update_motd_menuitem.connect('activate',
|
|
| 5173 |
- self.on_update_motd_menuitem_activate, account)
|
|
| 5174 |
- |
|
| 5175 |
- delete_motd_menuitem.connect('activate',
|
|
| 5176 |
- self.on_delete_motd_menuitem_activate, account)
|
|
| 5177 |
- |
|
| 5178 |
- advanced_menuitem_menu.show_all()
|
|
| 5179 |
- |
|
| 5180 |
- return advanced_menuitem_menu
|
|
| 5181 |
- |
|
| 5182 |
- def add_history_manager_menuitem(self, menu):
|
|
| 5183 |
- """
|
|
| 5184 |
- Add a separator and History Manager menuitem BELOW for account menuitems
|
|
| 5185 |
- """
|
|
| 5186 |
- item = Gtk.SeparatorMenuItem.new() # separator
|
|
| 5187 |
- menu.append(item)
|
|
| 5188 |
- |
|
| 5189 |
- # History manager
|
|
| 5190 |
- item = Gtk.MenuItem.new_with_mnemonic(_('History Manager'))
|
|
| 5191 |
- menu.append(item)
|
|
| 5192 |
- item.connect('activate', self.on_history_manager_menuitem_activate)
|
|
| 5193 |
- |
|
| 5194 | 5060 |
def show_appropriate_context_menu(self, event, iters):
|
| 5195 | 5061 |
# iters must be all of the same type
|
| 5196 | 5062 |
model = self.modelfilter
|