796 lines
		
	
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			796 lines
		
	
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from functools import partial
 | 
						|
 | 
						|
from gi.repository import Gtk, GLib, Gdk
 | 
						|
 | 
						|
from gajim.common import app
 | 
						|
from gajim import gtkgui_helpers
 | 
						|
from gajim import gui_menu_builder
 | 
						|
from gajim.common import passwords
 | 
						|
from gajim import config
 | 
						|
from gajim.common import helpers
 | 
						|
from gajim.common import ged
 | 
						|
from gajim.common.connection import Connection
 | 
						|
from gajim.common.zeroconf.connection_zeroconf import ConnectionZeroconf
 | 
						|
from gajim.options_dialog import OptionsDialog, OptionsBox
 | 
						|
from gajim.common.const import Option, OptionKind, OptionType
 | 
						|
from gajim.gtk import ConfirmationDialog
 | 
						|
from gajim.gtk import YesNoDialog
 | 
						|
 | 
						|
 | 
						|
class AccountsWindow(Gtk.ApplicationWindow):
 | 
						|
    def __init__(self):
 | 
						|
        Gtk.ApplicationWindow.__init__(self)
 | 
						|
        self.set_application(app.app)
 | 
						|
        self.set_position(Gtk.WindowPosition.CENTER)
 | 
						|
        self.set_show_menubar(False)
 | 
						|
        self.set_name('AccountsWindow')
 | 
						|
        self.set_default_size(700, 550)
 | 
						|
        self.set_resizable(False)
 | 
						|
        self.set_title(_('Accounts'))
 | 
						|
        self.need_relogin = {}
 | 
						|
 | 
						|
        glade_objects = ['stack', 'box', 'account_list']
 | 
						|
        self.builder = gtkgui_helpers.get_gtk_builder('accounts_window.ui')
 | 
						|
        for obj in glade_objects:
 | 
						|
            setattr(self, obj, self.builder.get_object(obj))
 | 
						|
 | 
						|
        self.account_list.add(Preferences(self))
 | 
						|
        account_item = AddAccount()
 | 
						|
        self.account_list.add(account_item)
 | 
						|
        account_item.set_activatable()
 | 
						|
 | 
						|
        accounts = app.config.get_per('accounts')
 | 
						|
        accounts.sort()
 | 
						|
        for account in accounts:
 | 
						|
            self.need_relogin[account] = self.get_relogin_options(account)
 | 
						|
            account_item = Account(account, self)
 | 
						|
            self.account_list.add(account_item)
 | 
						|
            account_item.set_activatable()
 | 
						|
 | 
						|
        self.add(self.box)
 | 
						|
        self.builder.connect_signals(self)
 | 
						|
 | 
						|
        self.connect('destroy', self.on_destroy)
 | 
						|
        self.connect('key-press-event', self.on_key_press)
 | 
						|
 | 
						|
        self._activate_preferences_page()
 | 
						|
        self.show_all()
 | 
						|
 | 
						|
        app.ged.register_event_handler(
 | 
						|
            'our-show', ged.GUI2, self._nec_our_status)
 | 
						|
 | 
						|
    def _nec_our_status(self, event):
 | 
						|
        self.update_accounts()
 | 
						|
 | 
						|
    def _activate_preferences_page(self):
 | 
						|
        row = self.account_list.get_row_at_index(0)
 | 
						|
        self.account_list.select_row(row)
 | 
						|
        self.account_list.emit('row-activated', row)
 | 
						|
 | 
						|
    def on_key_press(self, widget, event):
 | 
						|
        if event.keyval == Gdk.KEY_Escape:
 | 
						|
            self.destroy()
 | 
						|
 | 
						|
    def on_destroy(self, *args):
 | 
						|
        self.check_relogin()
 | 
						|
        app.ged.remove_event_handler(
 | 
						|
            'our-show', ged.GUI2, self._nec_our_status)
 | 
						|
 | 
						|
    def on_child_visible(self, stack, *args):
 | 
						|
        page = stack.get_visible_child_name()
 | 
						|
        if page is None:
 | 
						|
            return
 | 
						|
        if page == 'account':
 | 
						|
            self.check_relogin()
 | 
						|
 | 
						|
    def update_accounts(self):
 | 
						|
        for row in self.account_list.get_children():
 | 
						|
            row.get_child().update()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def on_row_activated(listbox, row):
 | 
						|
        row.get_child().on_row_activated()
 | 
						|
 | 
						|
    def remove_all_pages(self):
 | 
						|
        for page in self.stack.get_children():
 | 
						|
            self.stack.remove(page)
 | 
						|
 | 
						|
    def set_page(self, page, name):
 | 
						|
        self.remove_all_pages()
 | 
						|
        self.stack.add_named(page, name)
 | 
						|
        page.update()
 | 
						|
        page.show_all()
 | 
						|
        self.stack.set_visible_child(page)
 | 
						|
 | 
						|
    def update_proxy_list(self):
 | 
						|
        page = self.stack.get_child_by_name('connection')
 | 
						|
        if page is None:
 | 
						|
            return
 | 
						|
        page.listbox.get_option('proxy').update_values()
 | 
						|
 | 
						|
    def check_relogin(self):
 | 
						|
        for account in self.need_relogin:
 | 
						|
            options = self.get_relogin_options(account)
 | 
						|
            active = app.config.get_per('accounts', account, 'active')
 | 
						|
            if options != self.need_relogin[account]:
 | 
						|
                self.need_relogin[account] = options
 | 
						|
                if active:
 | 
						|
                    self.relog(account)
 | 
						|
                break
 | 
						|
 | 
						|
    def relog(self, account):
 | 
						|
        if app.connections[account].connected == 0:
 | 
						|
            return
 | 
						|
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            app.connections[app.ZEROCONF_ACC_NAME].update_details()
 | 
						|
            return
 | 
						|
 | 
						|
        def login(account, show_before, status_before):
 | 
						|
            """
 | 
						|
            Login with previous status
 | 
						|
            """
 | 
						|
            # first make sure connection is really closed,
 | 
						|
            # 0.5 may not be enough
 | 
						|
            app.connections[account].disconnect(True)
 | 
						|
            app.interface.roster.send_status(
 | 
						|
                account, show_before, status_before)
 | 
						|
 | 
						|
        def relog(account):
 | 
						|
            show_before = app.SHOW_LIST[app.connections[account].connected]
 | 
						|
            status_before = app.connections[account].status
 | 
						|
            app.interface.roster.send_status(
 | 
						|
                account, 'offline', _('Be right back.'))
 | 
						|
            GLib.timeout_add(500, login, account, show_before, status_before)
 | 
						|
 | 
						|
        YesNoDialog(
 | 
						|
            _('Relogin now?'),
 | 
						|
            _('If you want all the changes to apply instantly, '
 | 
						|
              'you must relogin.'),
 | 
						|
            transient_for=self,
 | 
						|
            on_response_yes=lambda *args: relog(account))
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_relogin_options(account):
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            options = ['zeroconf_first_name', 'zeroconf_last_name',
 | 
						|
                       'zeroconf_jabber_id', 'zeroconf_email', 'keyid']
 | 
						|
        else:
 | 
						|
            options = ['client_cert', 'proxy', 'resource',
 | 
						|
                       'use_custom_host', 'custom_host', 'custom_port',
 | 
						|
                       'keyid']
 | 
						|
 | 
						|
        values = []
 | 
						|
        for option in options:
 | 
						|
            values.append(app.config.get_per('accounts', account, option))
 | 
						|
        return values
 | 
						|
 | 
						|
    def on_remove_account(self, button, account):
 | 
						|
        if app.events.get_events(account):
 | 
						|
            app.interface.raise_dialog('unread-events-on-remove-account')
 | 
						|
            return
 | 
						|
 | 
						|
        if app.config.get_per('accounts', account, 'is_zeroconf'):
 | 
						|
            # Should never happen as button is insensitive
 | 
						|
            return
 | 
						|
 | 
						|
        win_opened = False
 | 
						|
        if app.interface.msg_win_mgr.get_controls(acct=account):
 | 
						|
            win_opened = True
 | 
						|
        elif account in app.interface.instances:
 | 
						|
            for key in app.interface.instances[account]:
 | 
						|
                if (app.interface.instances[account][key] and
 | 
						|
                        key != 'remove_account'):
 | 
						|
                    win_opened = True
 | 
						|
                    break
 | 
						|
 | 
						|
        # Detect if we have opened windows for this account
 | 
						|
 | 
						|
        def remove(account):
 | 
						|
            if (account in app.interface.instances and
 | 
						|
                    'remove_account' in app.interface.instances[account]):
 | 
						|
                dialog = app.interface.instances[account]['remove_account']
 | 
						|
                dialog.window.present()
 | 
						|
            else:
 | 
						|
                if account not in app.interface.instances:
 | 
						|
                    app.interface.instances[account] = {}
 | 
						|
                app.interface.instances[account]['remove_account'] = \
 | 
						|
                    config.RemoveAccountWindow(account)
 | 
						|
        if win_opened:
 | 
						|
            ConfirmationDialog(
 | 
						|
                _('You have opened chat in account %s') % account,
 | 
						|
                _('All chat and groupchat windows will be closed. '
 | 
						|
                  'Do you want to continue?'),
 | 
						|
                on_response_ok=(remove, account),
 | 
						|
                transient_for=self)
 | 
						|
        else:
 | 
						|
            remove(account)
 | 
						|
 | 
						|
    def remove_account(self, account):
 | 
						|
        for row in self.account_list.get_children():
 | 
						|
            if row.get_child().account == account:
 | 
						|
                self.account_list.remove(row)
 | 
						|
                del self.need_relogin[account]
 | 
						|
                break
 | 
						|
        self._activate_preferences_page()
 | 
						|
 | 
						|
    def add_account(self, account):
 | 
						|
        account_item = Account(account, self)
 | 
						|
        self.account_list.add(account_item)
 | 
						|
        account_item.set_activatable()
 | 
						|
        self.account_list.show_all()
 | 
						|
        self.stack.show_all()
 | 
						|
        self.need_relogin[account] = self.get_relogin_options(account)
 | 
						|
 | 
						|
    def select_account(self, account):
 | 
						|
        for row in self.account_list.get_children():
 | 
						|
            if row.get_child().account == account:
 | 
						|
                self.account_list.select_row(row)
 | 
						|
                self.account_list.emit('row-activated', row)
 | 
						|
                break
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def enable_account(account):
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            app.connections[account] = ConnectionZeroconf(account)
 | 
						|
        else:
 | 
						|
            app.connections[account] = Connection(account)
 | 
						|
 | 
						|
        app.plugin_manager.register_modules_for_account(
 | 
						|
            app.connections[account])
 | 
						|
 | 
						|
        # update variables
 | 
						|
        app.interface.instances[account] = {
 | 
						|
            'infos': {}, 'disco': {}, 'gc_config': {}, 'search': {},
 | 
						|
            'online_dialog': {}, 'sub_request': {}}
 | 
						|
        app.interface.minimized_controls[account] = {}
 | 
						|
        app.connections[account].connected = 0
 | 
						|
        app.groups[account] = {}
 | 
						|
        app.contacts.add_account(account)
 | 
						|
        app.gc_connected[account] = {}
 | 
						|
        app.automatic_rooms[account] = {}
 | 
						|
        app.newly_added[account] = []
 | 
						|
        app.to_be_removed[account] = []
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            app.nicks[account] = app.ZEROCONF_ACC_NAME
 | 
						|
        else:
 | 
						|
            app.nicks[account] = app.config.get_per(
 | 
						|
                'accounts', account, 'name')
 | 
						|
        app.block_signed_in_notifications[account] = True
 | 
						|
        app.sleeper_state[account] = 'off'
 | 
						|
        app.encrypted_chats[account] = []
 | 
						|
        app.last_message_time[account] = {}
 | 
						|
        app.status_before_autoaway[account] = ''
 | 
						|
        app.transport_avatar[account] = {}
 | 
						|
        app.gajim_optional_features[account] = []
 | 
						|
        app.caps_hash[account] = ''
 | 
						|
        helpers.update_optional_features(account)
 | 
						|
        # refresh roster
 | 
						|
        if len(app.connections) >= 2:
 | 
						|
            # Do not merge accounts if only one exists
 | 
						|
            app.interface.roster.regroup = app.config.get('mergeaccounts')
 | 
						|
        else:
 | 
						|
            app.interface.roster.regroup = False
 | 
						|
        app.interface.roster.setup_and_draw_roster()
 | 
						|
        gui_menu_builder.build_accounts_menu()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def disable_account(account):
 | 
						|
        app.interface.roster.close_all(account)
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            app.connections[account].disable_account()
 | 
						|
        app.connections[account].cleanup()
 | 
						|
        del app.connections[account]
 | 
						|
        del app.interface.instances[account]
 | 
						|
        del app.interface.minimized_controls[account]
 | 
						|
        del app.nicks[account]
 | 
						|
        del app.block_signed_in_notifications[account]
 | 
						|
        del app.groups[account]
 | 
						|
        app.contacts.remove_account(account)
 | 
						|
        del app.gc_connected[account]
 | 
						|
        del app.automatic_rooms[account]
 | 
						|
        del app.to_be_removed[account]
 | 
						|
        del app.newly_added[account]
 | 
						|
        del app.sleeper_state[account]
 | 
						|
        del app.encrypted_chats[account]
 | 
						|
        del app.last_message_time[account]
 | 
						|
        del app.status_before_autoaway[account]
 | 
						|
        del app.transport_avatar[account]
 | 
						|
        del app.gajim_optional_features[account]
 | 
						|
        del app.caps_hash[account]
 | 
						|
        if len(app.connections) >= 2:
 | 
						|
            # Do not merge accounts if only one exists
 | 
						|
            app.interface.roster.regroup = app.config.get('mergeaccounts')
 | 
						|
        else:
 | 
						|
            app.interface.roster.regroup = False
 | 
						|
        app.config.set_per(
 | 
						|
            'accounts', account, 'roster_version', '')
 | 
						|
        app.interface.roster.setup_and_draw_roster()
 | 
						|
        gui_menu_builder.build_accounts_menu()
 | 
						|
 | 
						|
 | 
						|
class AddAccount(Gtk.Box):
 | 
						|
    def __init__(self):
 | 
						|
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
 | 
						|
                         spacing=12)
 | 
						|
 | 
						|
        self.account = None
 | 
						|
 | 
						|
        self.label = Gtk.Label(label=_('Add Account…'))
 | 
						|
        self.label.set_halign(Gtk.Align.START)
 | 
						|
        self.label.set_hexpand(True)
 | 
						|
 | 
						|
        self.image = Gtk.Image.new_from_icon_name(
 | 
						|
            'list-add-symbolic', Gtk.IconSize.MENU)
 | 
						|
 | 
						|
        self.add(self.image)
 | 
						|
        self.add(self.label)
 | 
						|
 | 
						|
    def set_activatable(self):
 | 
						|
        self.get_parent().set_selectable(False)
 | 
						|
 | 
						|
    def on_row_activated(self):
 | 
						|
        app.app.activate_action('add-account')
 | 
						|
 | 
						|
    def update(self):
 | 
						|
        pass
 | 
						|
 | 
						|
 | 
						|
class Preferences(Gtk.Box):
 | 
						|
    def __init__(self, parent):
 | 
						|
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
 | 
						|
                         spacing=12)
 | 
						|
 | 
						|
        self.options = PreferencesPage()
 | 
						|
        self.parent = parent
 | 
						|
        self.account = None
 | 
						|
 | 
						|
        self.label = Gtk.Label(label=_('Preferences'))
 | 
						|
        self.label.set_halign(Gtk.Align.START)
 | 
						|
        self.label.set_hexpand(True)
 | 
						|
 | 
						|
        self.image = Gtk.Image.new_from_icon_name(
 | 
						|
            'system-run-symbolic', Gtk.IconSize.MENU)
 | 
						|
 | 
						|
        self.add(self.image)
 | 
						|
        self.add(self.label)
 | 
						|
 | 
						|
    def set_activatable(self):
 | 
						|
        pass
 | 
						|
 | 
						|
    def on_row_activated(self):
 | 
						|
        self.options.update_states()
 | 
						|
        self.parent.set_page(self.options, 'pref')
 | 
						|
 | 
						|
    def update(self):
 | 
						|
        pass
 | 
						|
 | 
						|
 | 
						|
class Account(Gtk.Box):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
 | 
						|
                         spacing=12)
 | 
						|
        self.account = account
 | 
						|
        if account == app.ZEROCONF_ACC_NAME:
 | 
						|
            self.options = ZeroConfPage(account, parent)
 | 
						|
        else:
 | 
						|
            self.options = AccountPage(account, parent)
 | 
						|
        self.parent = parent
 | 
						|
 | 
						|
        account_label = app.config.get_per('accounts', account, 'account_label')
 | 
						|
        self.label = Gtk.Label(label=account_label or account)
 | 
						|
        self.label.set_halign(Gtk.Align.START)
 | 
						|
        self.label.set_hexpand(True)
 | 
						|
 | 
						|
        self.image = Gtk.Image()
 | 
						|
        self._update_image()
 | 
						|
 | 
						|
        self.add(self.image)
 | 
						|
        self.add(self.label)
 | 
						|
 | 
						|
    def set_activatable(self):
 | 
						|
        if self.account == app.ZEROCONF_ACC_NAME:
 | 
						|
            zeroconf = app.is_installed('ZEROCONF')
 | 
						|
            self.get_parent().set_activatable(zeroconf)
 | 
						|
            self.get_parent().set_sensitive(zeroconf)
 | 
						|
            if not zeroconf:
 | 
						|
                self.get_parent().set_tooltip_text(
 | 
						|
                    _('Please check if Avahi or Bonjour is installed.'))
 | 
						|
 | 
						|
    def on_row_activated(self):
 | 
						|
        self.options.update_states()
 | 
						|
        self.parent.set_page(self.options, 'account')
 | 
						|
 | 
						|
    def update(self):
 | 
						|
        account_label = app.config.get_per(
 | 
						|
            'accounts', self.account, 'account_label')
 | 
						|
        self.label.set_text(account_label or self.account)
 | 
						|
        self._update_image()
 | 
						|
 | 
						|
    def _update_image(self):
 | 
						|
        show = helpers.get_current_show(self.account)
 | 
						|
        icon = gtkgui_helpers.get_iconset_name_for(show)
 | 
						|
        self.image.set_from_icon_name(icon, Gtk.IconSize.MENU)
 | 
						|
 | 
						|
 | 
						|
class GenericOptionPage(Gtk.Box):
 | 
						|
    def __init__(self, account, parent, options):
 | 
						|
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=12)
 | 
						|
        self.account = account
 | 
						|
        self.parent = parent
 | 
						|
 | 
						|
        button = Gtk.Button.new_from_icon_name(
 | 
						|
            'go-previous-symbolic', Gtk.IconSize.MENU)
 | 
						|
        button.set_halign(Gtk.Align.START)
 | 
						|
        button.connect('clicked', self._on_back_button)
 | 
						|
        if not isinstance(self, (AccountPage, PreferencesPage, ZeroConfPage)):
 | 
						|
            self.pack_start(button, False, True, 0)
 | 
						|
 | 
						|
        self.listbox = OptionsBox(account)
 | 
						|
        self.listbox.set_selection_mode(Gtk.SelectionMode.NONE)
 | 
						|
        self.listbox.set_vexpand(False)
 | 
						|
        self.listbox.set_valign(Gtk.Align.END)
 | 
						|
 | 
						|
        for option in options:
 | 
						|
            self.listbox.add_option(option)
 | 
						|
        self.listbox.update_states()
 | 
						|
 | 
						|
        self.pack_end(self.listbox, True, True, 0)
 | 
						|
 | 
						|
        self.listbox.connect('row-activated', self.on_row_activated)
 | 
						|
 | 
						|
    def _on_back_button(self, *args):
 | 
						|
        account_window = self.get_toplevel()
 | 
						|
        child = account_window.stack.get_visible_child()
 | 
						|
        account_window.remove_all_pages()
 | 
						|
        account_window.stack.add_named(child.parent, 'account')
 | 
						|
        account_window.stack.set_visible_child_name('account')
 | 
						|
 | 
						|
    def update_states(self):
 | 
						|
        self.listbox.update_states()
 | 
						|
 | 
						|
    def on_row_activated(self, listbox, row):
 | 
						|
        row.get_child().on_row_activated()
 | 
						|
 | 
						|
    def set_entry_text(self, toggle, update=False):
 | 
						|
        account_label = app.config.get_per(
 | 
						|
            'accounts', self.account, 'account_label')
 | 
						|
        if update:
 | 
						|
            self.entry.set_text(account_label or self.account)
 | 
						|
            return
 | 
						|
        if toggle.get_active():
 | 
						|
            self.entry.set_sensitive(True)
 | 
						|
            self.entry.grab_focus()
 | 
						|
        else:
 | 
						|
            self.entry.set_sensitive(False)
 | 
						|
            value = self.entry.get_text()
 | 
						|
            if not value:
 | 
						|
                value = account_label or self.account
 | 
						|
            app.config.set_per('accounts', self.account,
 | 
						|
                               'account_label', value or self.account)
 | 
						|
            if app.config.get_per('accounts', self.account, 'active'):
 | 
						|
                app.interface.roster.draw_account(self.account)
 | 
						|
                gui_menu_builder.build_accounts_menu()
 | 
						|
 | 
						|
    def update(self):
 | 
						|
        pass
 | 
						|
 | 
						|
    def set_page(self, options, name):
 | 
						|
        options.update_states()
 | 
						|
        self.get_toplevel().set_page(options, name)
 | 
						|
 | 
						|
    def _add_top_buttons(self, parent):
 | 
						|
        # This adds the Account enable switch and the back button
 | 
						|
        box = Gtk.Box()
 | 
						|
        box.set_hexpand(True)
 | 
						|
        box.set_halign(Gtk.Align.FILL)
 | 
						|
        switch = Gtk.Switch()
 | 
						|
        switch.set_active(app.config.get_per('accounts', self.account, 'active'))
 | 
						|
        switch.set_vexpand(False)
 | 
						|
        switch.set_valign(Gtk.Align.CENTER)
 | 
						|
        switch.set_halign(Gtk.Align.END)
 | 
						|
        if self.account == app.ZEROCONF_ACC_NAME and not app.is_installed('ZEROCONF'):
 | 
						|
            switch.set_sensitive(False)
 | 
						|
            switch.set_active(False)
 | 
						|
 | 
						|
        switch.connect('notify::active', self._on_enable_switch, self.account)
 | 
						|
        box.pack_start(switch, False, False, 0)
 | 
						|
        if self.account != app.ZEROCONF_ACC_NAME:
 | 
						|
            button = Gtk.Button(label=_('Remove'))
 | 
						|
            button.connect(
 | 
						|
                'clicked', parent.on_remove_account, self.account)
 | 
						|
            button.get_style_context().add_class('destructive-action')
 | 
						|
            button.set_halign(Gtk.Align.END)
 | 
						|
            switch.set_vexpand(False)
 | 
						|
            box.pack_end(button, False, False, 0)
 | 
						|
        self.pack_start(box, True, True, 0)
 | 
						|
 | 
						|
    def _on_enable_switch(self, switch, param, account):
 | 
						|
        old_state = app.config.get_per('accounts', account, 'active')
 | 
						|
        state = switch.get_active()
 | 
						|
        if old_state == state:
 | 
						|
            return
 | 
						|
 | 
						|
        if (account in app.connections and
 | 
						|
                app.connections[account].connected > 0):
 | 
						|
            # connecting or connected
 | 
						|
            app.interface.raise_dialog('connected-on-disable-account')
 | 
						|
            switch.set_active(not state)
 | 
						|
            return
 | 
						|
        if state:
 | 
						|
            self.parent.enable_account(account)
 | 
						|
        else:
 | 
						|
            self.parent.disable_account(account)
 | 
						|
        app.config.set_per('accounts', account, 'active', state)
 | 
						|
 | 
						|
 | 
						|
class PreferencesPage(GenericOptionPage):
 | 
						|
    def __init__(self):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.SWITCH, _('Merge Accounts'),
 | 
						|
                   OptionType.ACTION, 'merge'),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Use PGP Agent'),
 | 
						|
                   OptionType.ACTION, 'agent'),
 | 
						|
            ]
 | 
						|
 | 
						|
        GenericOptionPage.__init__(self, None, None, options)
 | 
						|
 | 
						|
 | 
						|
class AccountPage(GenericOptionPage):
 | 
						|
    def __init__(self, account, parent=None):
 | 
						|
 | 
						|
        general = partial(
 | 
						|
            self.set_page, GeneralPage(account, self), 'general')
 | 
						|
        connection = partial(
 | 
						|
            self.set_page, ConnectionPage(account, self), 'connection')
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.ENTRY, _('Label'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'account_label',
 | 
						|
                   callback=self._on_account_name_change),
 | 
						|
 | 
						|
            Option(OptionKind.LOGIN, _('Login'), OptionType.DIALOG,
 | 
						|
                   props={'dialog': LoginDialog}),
 | 
						|
 | 
						|
            Option(OptionKind.ACTION, _('Profile'), OptionType.ACTION,
 | 
						|
                   '-profile', props={'action_args': account}),
 | 
						|
 | 
						|
            Option(OptionKind.CALLBACK, _('General'),
 | 
						|
                   name='general', props={'callback': general}),
 | 
						|
 | 
						|
            Option(OptionKind.CALLBACK, _('Connection'),
 | 
						|
                   name='connection', props={'callback': connection}),
 | 
						|
 | 
						|
            Option(OptionKind.ACTION, _('Import Contacts'), OptionType.ACTION,
 | 
						|
                   '-import-contacts', props={'action_args': account}),
 | 
						|
 | 
						|
            Option(OptionKind.DIALOG, _('Client Certificate'),
 | 
						|
                   OptionType.DIALOG, props={'dialog': CertificateDialog}),
 | 
						|
 | 
						|
            Option(OptionKind.GPG, _('OpenPGP Key'), OptionType.DIALOG,
 | 
						|
                   props={'dialog': None}),
 | 
						|
            ]
 | 
						|
 | 
						|
        GenericOptionPage.__init__(self, account, parent, options)
 | 
						|
        self._add_top_buttons(parent)
 | 
						|
 | 
						|
    def _on_account_name_change(self, account_name, *args):
 | 
						|
        self.parent.update_accounts()
 | 
						|
 | 
						|
 | 
						|
class GeneralPage(GenericOptionPage):
 | 
						|
    def __init__(self, account, parent=None):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.SWITCH, _('Connect on startup'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'autoconnect'),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Reconnect when connection is lost'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'autoreconnect'),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Save conversations for all contacts'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'no_log_for',
 | 
						|
                   desc=_('Store conversations on the harddrive')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Server Message Archive'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'sync_logs_with_server',
 | 
						|
                   desc=_('Messages get stored on the server.\n'
 | 
						|
                          'The archive is used to sync messages\n'
 | 
						|
                          'between multiple devices.\n'
 | 
						|
                          'XEP-0313')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Global Status'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'sync_with_global_status',
 | 
						|
                   desc=_('Synchronise the status of all accounts')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Message Carbons'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'enable_message_carbons',
 | 
						|
                   desc=_('All your other online devices get copies\n'
 | 
						|
                          'of sent and received messages.\n'
 | 
						|
                          'XEP-0280')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Use file transfer proxies'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'use_ft_proxies'),
 | 
						|
            ]
 | 
						|
        GenericOptionPage.__init__(self, account, parent, options)
 | 
						|
 | 
						|
 | 
						|
class ConnectionPage(GenericOptionPage):
 | 
						|
    def __init__(self, account, parent=None):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.SWITCH, 'HTTP_PROXY',
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'use_env_http_proxy',
 | 
						|
                   desc=_('Use environment variable')),
 | 
						|
 | 
						|
            Option(OptionKind.PROXY, _('Proxy'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'proxy', name='proxy'),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Warn on insecure connection'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG,
 | 
						|
                   'warn_when_insecure_ssl_connection'),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Send keep-alive packets'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'keep_alives_enabled'),
 | 
						|
 | 
						|
            Option(OptionKind.HOSTNAME, _('Hostname'), OptionType.DIALOG,
 | 
						|
                   desc=_('Manually set the hostname for the server'),
 | 
						|
                   props={'dialog': CutstomHostnameDialog}),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Resource'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'resource'),
 | 
						|
 | 
						|
            Option(OptionKind.PRIORITY, _('Priority'),
 | 
						|
                   OptionType.DIALOG, props={'dialog': PriorityDialog}),
 | 
						|
            ]
 | 
						|
 | 
						|
        GenericOptionPage.__init__(self, account, parent, options)
 | 
						|
 | 
						|
 | 
						|
class ZeroConfPage(GenericOptionPage):
 | 
						|
    def __init__(self, account, parent=None):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.DIALOG, _('Profile'),
 | 
						|
                   OptionType.DIALOG, props={'dialog': ZeroconfProfileDialog}),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Connect on startup'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'autoconnect',
 | 
						|
                   desc=_('Use environment variable')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Save conversations for all contacts'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'no_log_for',
 | 
						|
                   desc=_('Store conversations on the harddrive')),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Global Status'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'sync_with_global_status',
 | 
						|
                   desc=_('Synchronize the status of all accounts')),
 | 
						|
 | 
						|
            Option(OptionKind.GPG, _('OpenPGP Key'),
 | 
						|
                   OptionType.DIALOG, props={'dialog': None}),
 | 
						|
            ]
 | 
						|
 | 
						|
        GenericOptionPage.__init__(self, account, parent, options)
 | 
						|
        self._add_top_buttons(None)
 | 
						|
 | 
						|
 | 
						|
class ZeroconfProfileDialog(OptionsDialog):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.ENTRY, _('First Name'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'zeroconf_first_name'),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Last Name'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'zeroconf_last_name'),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Jabber ID'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'zeroconf_jabber_id'),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Email'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'zeroconf_email'),
 | 
						|
            ]
 | 
						|
 | 
						|
        OptionsDialog.__init__(self, parent, _('Profile'),
 | 
						|
                               Gtk.DialogFlags.MODAL, options, account)
 | 
						|
 | 
						|
 | 
						|
class PriorityDialog(OptionsDialog):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
 | 
						|
        neg_priority = app.config.get('enable_negative_priority')
 | 
						|
        if neg_priority:
 | 
						|
            range_ = (-128, 127)
 | 
						|
        else:
 | 
						|
            range_ = (0, 127)
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.SWITCH, _('Adjust to status'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'adjust_priority_with_status',
 | 
						|
                   'adjust'),
 | 
						|
 | 
						|
            Option(OptionKind.SPIN, _('Priority'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'priority',
 | 
						|
                   enabledif=('adjust', False), props={'range_': range_}),
 | 
						|
            ]
 | 
						|
 | 
						|
        OptionsDialog.__init__(self, parent, _('Priority'),
 | 
						|
                               Gtk.DialogFlags.MODAL, options, account)
 | 
						|
 | 
						|
        self.connect('destroy', self.on_destroy)
 | 
						|
 | 
						|
    def on_destroy(self, *args):
 | 
						|
        # Update priority
 | 
						|
        if self.account not in app.connections:
 | 
						|
            return
 | 
						|
        show = app.SHOW_LIST[app.connections[self.account].connected]
 | 
						|
        status = app.connections[self.account].status
 | 
						|
        app.connections[self.account].change_status(show, status)
 | 
						|
 | 
						|
 | 
						|
class CutstomHostnameDialog(OptionsDialog):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.SWITCH, _('Enable'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'use_custom_host', name='custom'),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Hostname'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'custom_host',
 | 
						|
                   enabledif=('custom', True)),
 | 
						|
 | 
						|
            Option(OptionKind.ENTRY, _('Port'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'custom_port',
 | 
						|
                   enabledif=('custom', True)),
 | 
						|
            ]
 | 
						|
 | 
						|
        OptionsDialog.__init__(self, parent, _('Connection Options'),
 | 
						|
                               Gtk.DialogFlags.MODAL, options, account)
 | 
						|
 | 
						|
 | 
						|
class CertificateDialog(OptionsDialog):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.FILECHOOSER, _('Client Certificate'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'client_cert',
 | 
						|
                   props={'filefilter': (_('PKCS12 Files'), '*.p12')}),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Encrypted Certificate'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'client_cert_encrypted'),
 | 
						|
            ]
 | 
						|
 | 
						|
        OptionsDialog.__init__(self, parent, _('Certificate Options'),
 | 
						|
                               Gtk.DialogFlags.MODAL, options, account)
 | 
						|
 | 
						|
 | 
						|
class LoginDialog(OptionsDialog):
 | 
						|
    def __init__(self, account, parent):
 | 
						|
 | 
						|
        options = [
 | 
						|
            Option(OptionKind.ENTRY, _('Password'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'password', name='password',
 | 
						|
                   enabledif=('savepass', True)),
 | 
						|
 | 
						|
            Option(OptionKind.SWITCH, _('Save Password'),
 | 
						|
                   OptionType.ACCOUNT_CONFIG, 'savepass', name='savepass'),
 | 
						|
 | 
						|
            Option(OptionKind.CHANGEPASSWORD, _('Change Password'),
 | 
						|
                   OptionType.DIALOG, callback=self.on_password_change,
 | 
						|
                   props={'dialog': None}),
 | 
						|
            ]
 | 
						|
 | 
						|
        OptionsDialog.__init__(self, parent, _('Login Options'),
 | 
						|
                               Gtk.DialogFlags.MODAL, options, account)
 | 
						|
 | 
						|
        self.connect('destroy', self.on_destroy)
 | 
						|
 | 
						|
    def on_password_change(self, new_password, data):
 | 
						|
        passwords.save_password(self.account, new_password)
 | 
						|
 | 
						|
    def on_destroy(self, *args):
 | 
						|
        savepass = app.config.get_per('accounts', self.account, 'savepass')
 | 
						|
        if not savepass:
 | 
						|
            passwords.save_password(self.account, '')
 |