Skip to content
Snippets Groups Projects
accounts.py 30.8 KiB
Newer Older
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.

Philipp Hörist's avatar
Philipp Hörist committed
import sys
import locale
import logging
from collections import defaultdict
from gi.repository import Gtk
from gi.repository import Gdk
Philipp Hörist's avatar
Philipp Hörist committed
from gi.repository import Pango
from gi.repository import GObject
from gajim.common import app
from gajim.common import passwords
from gajim.common.i18n import _

from gajim.gtk.dialogs import DialogButton
from gajim.gtk.dialogs import NewConfirmationDialog
Philipp Hörist's avatar
Philipp Hörist committed
from gajim.gtk.const import Setting
from gajim.gtk.const import SettingKind
from gajim.gtk.const import SettingType
from gajim.gtk.settings import SettingsDialog
from gajim.gtk.settings import SettingsBox
from gajim.gtk.util import open_window
Philipp Hörist's avatar
Philipp Hörist committed
log = logging.getLogger('gajim.gtk.accounts')


Philipp Hörist's avatar
Philipp Hörist committed
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)
Philipp Hörist's avatar
Philipp Hörist committed
        self.set_resizable(True)
        self.set_title(_('Accounts'))
Philipp Hörist's avatar
Philipp Hörist committed
        self._need_relogin = {}
        self._accounts = {}
Philipp Hörist's avatar
Philipp Hörist committed
        self._menu = AccountMenu()
        self._settings = Settings()
Philipp Hörist's avatar
Philipp Hörist committed
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        box.add(self._menu)
        box.add(self._settings)
        self.add(box)
Philipp Hörist's avatar
Philipp Hörist committed
        for account in app.get_accounts_sorted():
            if account == 'Local':
                # Disable zeroconf support until its working again
                continue
Emmanuel Gil Peyrot's avatar
Emmanuel Gil Peyrot committed
            self.add_account(account, initial=True)
Philipp Hörist's avatar
Philipp Hörist committed
        self._menu.connect('menu-activated', self._on_menu_activated)
        self.connect('destroy', self._on_destroy)
        self.connect('key-press-event', self._on_key_press)
Philipp Hörist's avatar
Philipp Hörist committed
        self.show_all()

Philipp Hörist's avatar
Philipp Hörist committed
    def _on_menu_activated(self, _listbox, account, name):
        if name == 'back':
            self._settings.set_page('add-account')
            self._check_relogin()
        elif name == 'remove':
            self.on_remove_account(account)
        else:
            self._settings.set_page(name)
Philipp Hörist's avatar
Philipp Hörist committed
    def _on_key_press(self, _widget, event):
Philipp Hörist's avatar
Philipp Hörist committed
        if event.keyval == Gdk.KEY_Escape:
            self.destroy()

Philipp Hörist's avatar
Philipp Hörist committed
    def _on_destroy(self, *args):
        self._check_relogin()
Philipp Hörist's avatar
Philipp Hörist committed
    def update_account_label(self, account):
        self._accounts[account].update_account_label()
Philipp Hörist's avatar
Philipp Hörist committed

    def update_proxy_list(self):
Philipp Hörist's avatar
Philipp Hörist committed
        for account in self._accounts:
            self._settings.update_proxy_list(account)
Philipp Hörist's avatar
Philipp Hörist committed
    def _check_relogin(self):
        for account in self._need_relogin:
            settings = self._get_relogin_settings(account)
            active = app.settings.get_account_setting(account, 'active')
Philipp Hörist's avatar
Philipp Hörist committed
            if settings != self._need_relogin[account]:
                self._need_relogin[account] = settings
Philipp Hörist's avatar
Philipp Hörist committed
                if active:
Philipp Hörist's avatar
Philipp Hörist committed
                    self._relog(account)
Philipp Hörist's avatar
Philipp Hörist committed
                break

Philipp Hörist's avatar
Philipp Hörist committed
    def _relog(self, account):
        if not app.account_is_connected(account):
Philipp Hörist's avatar
Philipp Hörist committed
            return

        if account == app.ZEROCONF_ACC_NAME:
            app.connections[app.ZEROCONF_ACC_NAME].update_details()
            return

        def relog():
            app.connections[account].disconnect(gracefully=True,
                                                reconnect=True,
                                                destroy_client=True)
        NewConfirmationDialog(
            _('Re-Login'),
            _('Re-Login now?'),
            _('To apply all changes instantly, you have to re-login.'),
            [DialogButton.make('Cancel',
                               text=_('_Later')),
             DialogButton.make('Accept',
                               callback=relog)],
            transient_for=self).show()
Philipp Hörist's avatar
Philipp Hörist committed

    @staticmethod
Philipp Hörist's avatar
Philipp Hörist committed
    def _get_relogin_settings(account):
Philipp Hörist's avatar
Philipp Hörist committed
        if account == app.ZEROCONF_ACC_NAME:
Philipp Hörist's avatar
Philipp Hörist committed
            settings = ['zeroconf_first_name', 'zeroconf_last_name',
                        'zeroconf_jabber_id', 'zeroconf_email']
Philipp Hörist's avatar
Philipp Hörist committed
        else:
Philipp Hörist's avatar
Philipp Hörist committed
            settings = ['client_cert', 'proxy', 'resource',
                        'use_custom_host', 'custom_host', 'custom_port']
Philipp Hörist's avatar
Philipp Hörist committed

        values = []
Philipp Hörist's avatar
Philipp Hörist committed
        for setting in settings:
            values.append(app.settings.get_account_setting(account, setting))
Philipp Hörist's avatar
Philipp Hörist committed
        return values

    @staticmethod
    def on_remove_account(account):
Philipp Hörist's avatar
Philipp Hörist committed
        if app.events.get_events(account):
            app.interface.raise_dialog('unread-events-on-remove-account')
Philipp Hörist's avatar
Philipp Hörist committed
            return

        if app.settings.get_account_setting(account, 'is_zeroconf'):
Philipp Hörist's avatar
Philipp Hörist committed
            # Should never happen as button is insensitive
            return

        open_window('RemoveAccount', account=account)
Philipp Hörist's avatar
Philipp Hörist committed

    def remove_account(self, account):
Philipp Hörist's avatar
Philipp Hörist committed
        del self._need_relogin[account]
        self._accounts[account].remove()
Emmanuel Gil Peyrot's avatar
Emmanuel Gil Peyrot committed
    def add_account(self, account, initial=False):
Philipp Hörist's avatar
Philipp Hörist committed
        self._need_relogin[account] = self._get_relogin_settings(account)
        self._accounts[account] = Account(account, self._menu, self._settings)
Emmanuel Gil Peyrot's avatar
Emmanuel Gil Peyrot committed
        if not initial:
Philipp Hörist's avatar
Philipp Hörist committed
            self._accounts[account].show()
Philipp Hörist's avatar
Philipp Hörist committed

    def select_account(self, account):
Philipp Hörist's avatar
Philipp Hörist committed
        try:
            self._accounts[account].select()
        except KeyError:
            log.warning('select_account() failed, account %s not found',
                        account)
    def enable_account(self, account, state):
        self._accounts[account].enable_account(state)

Philipp Hörist's avatar
Philipp Hörist committed
class Settings(Gtk.ScrolledWindow):
    def __init__(self):
Philipp Hörist's avatar
Philipp Hörist committed
        Gtk.ScrolledWindow.__init__(self)
        self.set_hexpand(True)
        self.set_vexpand(True)
        self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        self._stack = Gtk.Stack()
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.add_named(AddNewAccountPage(), 'add-account')
        self.get_style_context().add_class('accounts-settings')

        self.add(self._stack)
        self._page_signal_ids = {}
        self._pages = defaultdict(list)

    def add_page(self, page):
        self._pages[page.account].append(page)
        self._stack.add_named(page, '%s-%s' % (page.account, page.name))
        self._page_signal_ids[page] = page.connect_signal(self._stack)

    def set_page(self, name):
        self._stack.set_visible_child_name(name)
Philipp Hörist's avatar
Philipp Hörist committed
    def remove_account(self, account):
        for page in self._pages[account]:
            signal_id = self._page_signal_ids[page]
            del self._page_signal_ids[page]
            self._stack.disconnect(signal_id)
            self._stack.remove(page)
            page.destroy()
        del self._pages[account]
Philipp Hörist's avatar
Philipp Hörist committed
    def update_proxy_list(self, account):
        for page in self._pages[account]:
            if page.name != 'connection':
                continue
            page.listbox.get_setting('proxy').update_values()
Philipp Hörist's avatar
Philipp Hörist committed
class AccountMenu(Gtk.Box):
Philipp Hörist's avatar
Philipp Hörist committed
    __gsignals__ = {
        'menu-activated': (GObject.SignalFlags.RUN_FIRST, None, (str, str)),
    }
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self):
        Gtk.Box.__init__(self)
        self.set_hexpand(False)
        self.set_size_request(160, -1)
Philipp Hörist's avatar
Philipp Hörist committed
        self.get_style_context().add_class('accounts-menu')
Philipp Hörist's avatar
Philipp Hörist committed
        self._stack = Gtk.Stack()
        self._stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
Philipp Hörist's avatar
Philipp Hörist committed
        self._accounts_listbox = Gtk.ListBox()
        self._accounts_listbox.set_sort_func(self._sort_func)
        self._accounts_listbox.get_style_context().add_class('settings-box')
        self._accounts_listbox.connect('row-activated',
                                       self._on_account_row_activated)
Philipp Hörist's avatar
Philipp Hörist committed
        scrolled = Gtk.ScrolledWindow()
        scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scrolled.add(self._accounts_listbox)
        self._stack.add_named(scrolled, 'accounts')
        self.add(self._stack)
Philipp Hörist's avatar
Philipp Hörist committed
    @staticmethod
    def _sort_func(row1, row2):
        if row1.label == 'Local':
            return -1
        return locale.strcoll(row1.label.lower(), row2.label.lower())

    def add_account(self, row):
        self._accounts_listbox.add(row)
        sub_menu = AccountSubMenu(row.account)
        self._stack.add_named(sub_menu, '%s-menu' % row.account)

        sub_menu.connect('row-activated', self._on_sub_menu_row_activated)

    def remove_account(self, row):
        if self._stack.get_visible_child_name() != 'accounts':
            # activate 'back' button
            self._stack.get_visible_child().get_row_at_index(1).emit('activate')
        self._accounts_listbox.remove(row)
        sub_menu = self._stack.get_child_by_name('%s-menu' % row.account)
        self._stack.remove(sub_menu)
        row.destroy()
        sub_menu.destroy()

    def _on_account_row_activated(self, _listbox, row):
        self._stack.set_visible_child_name('%s-menu' % row.account)
        self._stack.get_visible_child().get_row_at_index(2).emit('activate')

    def _on_sub_menu_row_activated(self, listbox, row):
        if row.name == 'back':
            self._stack.set_visible_child_full(
                'accounts', Gtk.StackTransitionType.OVER_RIGHT)

        if row.name in ('back', 'remove'):
            self.emit('menu-activated', listbox.account, row.name)

        else:
            self.emit('menu-activated',
                      listbox.account,
                      '%s-%s' % (listbox.account, row.name))
Philipp Hörist's avatar
Philipp Hörist committed
    def update_account_label(self, account):
        self._accounts_listbox.invalidate_sort()
        sub_menu = self._stack.get_child_by_name('%s-menu' % account)
        sub_menu.update()
Philipp Hörist's avatar
Philipp Hörist committed
class AccountSubMenu(Gtk.ListBox):

    __gsignals__ = {
        'update': (GObject.SignalFlags.RUN_FIRST, None, (str,))
    }

    def __init__(self, account):
        Gtk.ListBox.__init__(self)
        self.set_vexpand(True)
        self.set_hexpand(True)
        self.get_style_context().add_class('settings-box')
Philipp Hörist's avatar
Philipp Hörist committed
        self._account = account

        self.add(AccountLabelMenuItem(self, self._account))
        self.add(BackMenuItem())
        self.add(PageMenuItem('general', _('General')))
        if account != 'Local':
            self.add(PageMenuItem('privacy', _('Privacy')))
            self.add(PageMenuItem('connection', _('Connection')))
            self.add(PageMenuItem('advanced', _('Advanced')))
Philipp Hörist's avatar
Philipp Hörist committed
            self.add(RemoveMenuItem())

    @property
    def account(self):
        return self._account

    def update(self):
Philipp Hörist's avatar
Philipp Hörist committed
        self.emit('update', self._account)
Philipp Hörist's avatar
Philipp Hörist committed
class MenuItem(Gtk.ListBoxRow):
    def __init__(self, name):
        Gtk.ListBoxRow.__init__(self)
        self._name = name
        self._box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                            spacing=12)
        self._label = Gtk.Label()
Philipp Hörist's avatar
Philipp Hörist committed
        self.add(self._box)
Philipp Hörist's avatar
Philipp Hörist committed
    @property
    def name(self):
        return self._name
Philipp Hörist's avatar
Philipp Hörist committed
class RemoveMenuItem(MenuItem):
    def __init__(self):
        super().__init__('remove')
        self._label.set_text(_('Remove'))
        image = Gtk.Image.new_from_icon_name('user-trash-symbolic',
                                             Gtk.IconSize.MENU)
Philipp Hörist's avatar
Philipp Hörist committed
        self.set_selectable(False)
        image.get_style_context().add_class('error-color')
Philipp Hörist's avatar
Philipp Hörist committed
        self._box.add(image)
        self._box.add(self._label)
Philipp Hörist's avatar
Philipp Hörist committed
class AccountLabelMenuItem(MenuItem):
    def __init__(self, parent, account):
        super().__init__('account-label')
        self._update_account_label(parent, account)
Philipp Hörist's avatar
Philipp Hörist committed
        self.set_selectable(False)
        self.set_sensitive(False)
        self.set_activatable(False)
Philipp Hörist's avatar
Philipp Hörist committed
        image = Gtk.Image.new_from_icon_name('avatar-default-symbolic',
                                             Gtk.IconSize.MENU)
        image.get_style_context().add_class('insensitive-fg-color')
Philipp Hörist's avatar
Philipp Hörist committed
        self._label.get_style_context().add_class('accounts-label-row')
        self._label.set_ellipsize(Pango.EllipsizeMode.END)
        self._label.set_xalign(0)
Philipp Hörist's avatar
Philipp Hörist committed
        self._box.add(image)
        self._box.add(self._label)
Philipp Hörist's avatar
Philipp Hörist committed
        parent.connect('update', self._update_account_label)
Philipp Hörist's avatar
Philipp Hörist committed
    def _update_account_label(self, _listbox, account):
        account_label = app.get_account_label(account)
        self._label.set_text(account_label)
Philipp Hörist's avatar
Philipp Hörist committed
class BackMenuItem(MenuItem):
    def __init__(self):
        super().__init__('back')
        self.set_selectable(False)
Philipp Hörist's avatar
Philipp Hörist committed
        self._label.set_text(_('Back'))
Philipp Hörist's avatar
Philipp Hörist committed
        image = Gtk.Image.new_from_icon_name('go-previous-symbolic',
                                             Gtk.IconSize.MENU)
        image.get_style_context().add_class('insensitive-fg-color')

        self._box.add(image)
        self._box.add(self._label)


class PageMenuItem(MenuItem):
    def __init__(self, name, label):
        super().__init__(name)

        if name == 'general':
            icon = 'preferences-system-symbolic'
        elif name == 'privacy':
            icon = 'preferences-system-privacy-symbolic'
        elif name == 'connection':
            icon = 'preferences-system-network-symbolic'
        elif name == 'advanced':
            icon = 'preferences-other-symbolic'
Philipp Hörist's avatar
Philipp Hörist committed
        else:
Philipp Hörist's avatar
Philipp Hörist committed
            icon = 'dialog-error-symbolic'
Philipp Hörist's avatar
Philipp Hörist committed
        image = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU)
        self._label.set_text(label)

        self._box.add(image)
        self._box.add(self._label)


class Account:
    def __init__(self, account, menu, settings):
        self._account = account
        self._menu = menu
        self._settings = settings

        if account == app.ZEROCONF_ACC_NAME:
            self._settings.add_page(ZeroConfPage(account))
        else:
            self._settings.add_page(GeneralPage(account))
            self._settings.add_page(ConnectionPage(account))
            self._settings.add_page(PrivacyPage(account))
            self._settings.add_page(AdvancedPage(account))
Philipp Hörist's avatar
Philipp Hörist committed

        self._account_row = AccountRow(account)
        self._menu.add_account(self._account_row)

    def select(self):
        self._account_row.emit('activate')

    def show(self):
        self._menu.show_all()
        self._settings.show_all()
        self.select()

    def remove(self):
        self._menu.remove_account(self._account_row)
        self._settings.remove_account(self._account)

    def update_account_label(self):
        self._account_row.update_account_label()
        self._menu.update_account_label(self._account)

    def enable_account(self, state):
        self._account_row.enable_account(state)

Philipp Hörist's avatar
Philipp Hörist committed
    @property
    def menu(self):
        return self._menu
Philipp Hörist's avatar
Philipp Hörist committed
    @property
    def account(self):
        return self._account

    @property
    def settings(self):
        return self._account


class AccountRow(Gtk.ListBoxRow):
    def __init__(self, account):
        Gtk.ListBoxRow.__init__(self)
        self.set_selectable(False)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)

        self._account = account

        self._label = Gtk.Label(label=app.get_account_label(account))
        self._label.set_halign(Gtk.Align.START)
        self._label.set_hexpand(True)
        self._label.set_ellipsize(Pango.EllipsizeMode.END)
        self._label.set_xalign(0)
        self._label.set_width_chars(18)

        next_icon = Gtk.Image.new_from_icon_name('go-next-symbolic',
                                                 Gtk.IconSize.MENU)
        next_icon.get_style_context().add_class('insensitive-fg-color')
        self._switch = Gtk.Switch()
        self._switch.set_active(
            app.settings.get_account_setting(self._account, 'active'))
        self._switch.set_vexpand(False)
Philipp Hörist's avatar
Philipp Hörist committed

        if (self._account == app.ZEROCONF_ACC_NAME and
                not app.is_installed('ZEROCONF')):
            self._switch.set_active(False)
Philipp Hörist's avatar
Philipp Hörist committed
            self.set_activatable(False)
            self.set_sensitive(False)
            if sys.platform in ('win32', 'darwin'):
                tooltip = _('Please check if Bonjour is installed.')
            else:
                tooltip = _('Please check if Avahi is installed.')
            self.set_tooltip_text(tooltip)
        self._switch.connect(
            'state-set', self._on_enable_switch, self._account)
Philipp Hörist's avatar
Philipp Hörist committed
        box.add(self._label)
        box.add(next_icon)
        self.add(box)

    @property
    def account(self):
        return self._account

    @property
    def label(self):
        return self._label.get_text()

    def update_account_label(self):
        self._label.set_text(app.get_account_label(self._account))
    def enable_account(self, state):
        self._switch.set_state(state)

    def _on_enable_switch(self, switch, state, account):
        def _disable():
            app.connections[account].change_status('offline', 'offline')
            app.interface.disable_account(account)
        old_state = app.settings.get_account_setting(account, 'active')
        if old_state == state:
Philipp Hörist's avatar
Philipp Hörist committed
            return Gdk.EVENT_PROPAGATE

        if (account in app.connections and
                not app.connections[account].state.is_disconnected):
            # Connecting or connected
            NewConfirmationDialog(
                _('Disable Account'),
                _('Account %s is still connected') % account,
                _('All chat and group chat windows will be closed.'),
                [DialogButton.make('Cancel',
                                   callback=lambda: switch.set_active(True)),
                 DialogButton.make('Remove',
                                   text=_('_Disable Account'),
Philipp Hörist's avatar
Philipp Hörist committed
                transient_for=self.get_toplevel()).show()
        if state:
            app.interface.enable_account(account)
            app.interface.disable_account(account)
Philipp Hörist's avatar
Philipp Hörist committed
        return Gdk.EVENT_PROPAGATE

Philipp Hörist's avatar
Philipp Hörist committed
class AddNewAccountPage(Gtk.Box):
    def __init__(self):
Philipp Hörist's avatar
Philipp Hörist committed
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
        self.set_vexpand(True)
        self.set_hexpand(True)
        button = Gtk.Button(label=_('Add Account'))
Philipp Hörist's avatar
Philipp Hörist committed
        button.get_style_context().add_class('suggested-action')
        button.set_action_name('app.add-account')
        button.set_halign(Gtk.Align.CENTER)
        button.set_valign(Gtk.Align.CENTER)
        self.add(button)
Philipp Hörist's avatar
Philipp Hörist committed
class GenericSettingPage(Gtk.Box):
    def __init__(self, account, settings):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.set_valign(Gtk.Align.START)
        self.set_vexpand(True)
        self.account = account

        self.listbox = SettingsBox(account)
        self.listbox.get_style_context().add_class('accounts-settings-border')
        self.listbox.set_selection_mode(Gtk.SelectionMode.NONE)
        self.listbox.set_vexpand(False)
        self.listbox.set_valign(Gtk.Align.END)

        for setting in settings:
            self.listbox.add_setting(setting)
        self.listbox.update_states()
Philipp Hörist's avatar
Philipp Hörist committed
        self.pack_end(self.listbox, True, True, 0)
Philipp Hörist's avatar
Philipp Hörist committed
    def connect_signal(self, stack):
        return stack.connect('notify::visible-child',
                             self._on_visible_child_changed)
    def _on_visible_child_changed(self, stack, _param):
Philipp Hörist's avatar
Philipp Hörist committed
        if self == stack.get_visible_child():
            self.listbox.update_states()
Philipp Hörist's avatar
Philipp Hörist committed

class GeneralPage(GenericSettingPage):

    name = 'general'

    def __init__(self, account):
Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.ENTRY, _('Label'),
                    SettingType.ACCOUNT_CONFIG, 'account_label',
                    callback=self._on_account_name_change),
            Setting(SettingKind.COLOR, _('Color'),
                    SettingType.ACCOUNT_CONFIG, 'account_color',
                    desc=_('Recognize your account by color')),

Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.LOGIN, _('Login'), SettingType.DIALOG,
                    props={'dialog': LoginDialog}),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ACTION, _('Import Contacts'),
                    SettingType.ACTION, '-import-contacts',
                    props={'account': account}),
            # Currently not supported by nbxmpp
            #
            # Setting(SettingKind.DIALOG, _('Client Certificate'),
            #         SettingType.DIALOG, props={'dialog': CertificateDialog}),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Connect on startup'),
                    SettingType.ACCOUNT_CONFIG, 'autoconnect'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH,
                    _('Save conversations for all contacts'),
Philipp Hörist's avatar
Philipp Hörist committed
                    SettingType.ACCOUNT_CONFIG, 'no_log_for',
                    desc=_('Store conversations on the harddrive')),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Global Status'),
                    SettingType.ACCOUNT_CONFIG, 'sync_with_global_status',
                    desc=_('Synchronise the status of all accounts')),
            Setting(SettingKind.SWITCH, _('Remember Last Status'),
                    SettingType.ACCOUNT_CONFIG, 'restore_last_status',
                    desc=_('Restore status and status message of your '
                           'last session')),

Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Use file transfer proxies'),
                    SettingType.ACCOUNT_CONFIG, 'use_ft_proxies'),
Philipp Hörist's avatar
Philipp Hörist committed
        ]
        GenericSettingPage.__init__(self, account, settings)

    def _on_account_name_change(self, *args):
        self.get_toplevel().update_account_label(self.account)
class PrivacyPage(GenericSettingPage):
Philipp Hörist's avatar
Philipp Hörist committed

    name = 'privacy'

    def __init__(self, account):

        settings = [
            Setting(SettingKind.SWITCH, _('Idle Time'),
                    SettingType.ACCOUNT_CONFIG, 'send_idle_time',
                    desc=_('Disclose the time of your last activity')),

            Setting(SettingKind.SWITCH, _('Local System Time'),
                    SettingType.ACCOUNT_CONFIG, 'send_time_info',
                    desc=_('Disclose the local system time of the '
                           'device Gajim runs on')),

            Setting(SettingKind.SWITCH, _('Client / Operating System'),
                    SettingType.ACCOUNT_CONFIG, 'send_os_info',
Emmanuel Gil Peyrot's avatar
Emmanuel Gil Peyrot committed
                    desc=_('Disclose information about the client '
                           'and operating system you currently use')),

            Setting(SettingKind.SWITCH, _('Ignore Unknown Contacts'),
                    SettingType.ACCOUNT_CONFIG, 'ignore_unknown_contacts',
                    desc=_('Ignore everything from contacts not in your '
                           'Roster')),

            Setting(SettingKind.SWITCH, _('Send Message Receipts'),
                    SettingType.ACCOUNT_CONFIG, 'answer_receipts',
                    desc=_('Tell your contacts if you received a message')),

Philipp Hörist's avatar
Philipp Hörist committed
        GenericSettingPage.__init__(self, account, settings)
Philipp Hörist's avatar
Philipp Hörist committed
class ConnectionPage(GenericSettingPage):
Philipp Hörist's avatar
Philipp Hörist committed

    name = 'connection'

    def __init__(self, account):
Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.PROXY, _('Proxy'),
                    SettingType.ACCOUNT_CONFIG, 'proxy', name='proxy'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.HOSTNAME, _('Hostname'), SettingType.DIALOG,
                    desc=_('Manually set the hostname for the server'),
                    props={'dialog': CutstomHostnameDialog}),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ENTRY, _('Resource'),
                    SettingType.ACCOUNT_CONFIG, 'resource'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.PRIORITY, _('Priority'),
                    SettingType.DIALOG, props={'dialog': PriorityDialog}),

            Setting(SettingKind.SWITCH, _('Use Unencrypted Connection'),
                    SettingType.ACCOUNT_CONFIG, 'use_plain_connection',
                    desc=_('Use an unencrypted connection to the server')),

            Setting(SettingKind.SWITCH, _('Confirm Unencrypted Connection'),
                    SettingType.ACCOUNT_CONFIG,
                    'confirm_unencrypted_connection',
                    desc=_('Show a confirmation dialog before connecting '
                           'unencrypted')),
Philipp Hörist's avatar
Philipp Hörist committed
            ]
        GenericSettingPage.__init__(self, account, settings)


class AdvancedPage(GenericSettingPage):
    name = 'advanced'

    def __init__(self, account):

        settings = [
            Setting(SettingKind.SWITCH, _('Contact Information'),
                    SettingType.ACCOUNT_CONFIG, 'request_user_data',
                    desc=_('Request contact information '
                           '(Mood, Activity, Tune, Location)')),

            Setting(SettingKind.SWITCH, _('Accept all Contact Requests'),
                    SettingType.ACCOUNT_CONFIG, 'autoauth',
                    desc=_('Automatically accept all contact requests')),

            Setting(SettingKind.POPOVER, _('Filetransfer Preference'),
                    SettingType.ACCOUNT_CONFIG, 'filetransfer_preference',
                    props={'entries': {'httpupload': _('Upload Files'),
                                       'jingle': _('Send Files Directly')}},
                    desc=_('Preferred file transfer mechanism for '
                           'file drag&drop on a chat window'))
            ]
Philipp Hörist's avatar
Philipp Hörist committed
        GenericSettingPage.__init__(self, account, settings)
Philipp Hörist's avatar
Philipp Hörist committed
class ZeroConfPage(GenericSettingPage):
Philipp Hörist's avatar
Philipp Hörist committed

    name = 'general'

    def __init__(self, account):
Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.DIALOG, _('Profile'),
Philipp Hörist's avatar
Philipp Hörist committed
                    SettingType.DIALOG,
                    props={'dialog': ZeroconfProfileDialog}),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Connect on startup'),
                    SettingType.ACCOUNT_CONFIG, 'autoconnect',
                    desc=_('Use environment variable')),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH,
                    _('Save conversations for all contacts'),
Philipp Hörist's avatar
Philipp Hörist committed
                    SettingType.ACCOUNT_CONFIG, 'no_log_for',
                    desc=_('Store conversations on the harddrive')),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Global Status'),
                    SettingType.ACCOUNT_CONFIG, 'sync_with_global_status',
                    desc=_('Synchronize the status of all accounts')),
Philipp Hörist's avatar
Philipp Hörist committed
        GenericSettingPage.__init__(self, account, settings)
Philipp Hörist's avatar
Philipp Hörist committed
class ZeroconfProfileDialog(SettingsDialog):
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self, account, parent):

Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.ENTRY, _('First Name'),
                    SettingType.ACCOUNT_CONFIG, 'zeroconf_first_name'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ENTRY, _('Last Name'),
                    SettingType.ACCOUNT_CONFIG, 'zeroconf_last_name'),
            Setting(SettingKind.ENTRY, _('XMPP Address'),
Philipp Hörist's avatar
Philipp Hörist committed
                    SettingType.ACCOUNT_CONFIG, 'zeroconf_jabber_id'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ENTRY, _('Email'),
                    SettingType.ACCOUNT_CONFIG, 'zeroconf_email'),
Philipp Hörist's avatar
Philipp Hörist committed
        SettingsDialog.__init__(self, parent, _('Profile'),
Philipp Hörist's avatar
Philipp Hörist committed
                                Gtk.DialogFlags.MODAL, settings, account)
Philipp Hörist's avatar
Philipp Hörist committed
class PriorityDialog(SettingsDialog):
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self, account, parent):

        neg_priority = app.settings.get('enable_negative_priority')
Philipp Hörist's avatar
Philipp Hörist committed
        if neg_priority:
            range_ = (-128, 127)
        else:
            range_ = (0, 127)

Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.SWITCH, _('Adjust to status'),
                    SettingType.ACCOUNT_CONFIG, 'adjust_priority_with_status',
                    'adjust'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SPIN, _('Priority'),
                    SettingType.ACCOUNT_CONFIG, 'priority',
                    enabledif=('adjust', False), props={'range_': range_}),
Philipp Hörist's avatar
Philipp Hörist committed
        SettingsDialog.__init__(self, parent, _('Priority'),
Philipp Hörist's avatar
Philipp Hörist committed
                                Gtk.DialogFlags.MODAL, settings, account)
Philipp Hörist's avatar
Philipp Hörist committed

        self.connect('destroy', self.on_destroy)

    def on_destroy(self, *args):
        # Update priority
        if self.account not in app.connections:
            return
        show = app.connections[self.account].status
        status = app.connections[self.account].status_message
Philipp Hörist's avatar
Philipp Hörist committed
        app.connections[self.account].change_status(show, status)


Philipp Hörist's avatar
Philipp Hörist committed
class CutstomHostnameDialog(SettingsDialog):
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self, account, parent):

        type_values = ('START TLS', 'DIRECT TLS', 'PLAIN')

Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.SWITCH, _('Enable'),
Philipp Hörist's avatar
Philipp Hörist committed
                    SettingType.ACCOUNT_CONFIG,
                    'use_custom_host', name='custom'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ENTRY, _('Hostname'),
                    SettingType.ACCOUNT_CONFIG, 'custom_host',
                    enabledif=('custom', True)),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.ENTRY, _('Port'),
                    SettingType.ACCOUNT_CONFIG, 'custom_port',
                    enabledif=('custom', True)),

            Setting(SettingKind.COMBO, _('Type'),
                    SettingType.ACCOUNT_CONFIG, 'custom_type',
                    enabledif=('custom', True),
                    props={'combo_items': type_values}),
Philipp Hörist's avatar
Philipp Hörist committed
        SettingsDialog.__init__(self, parent, _('Connection Settings'),
Philipp Hörist's avatar
Philipp Hörist committed
                                Gtk.DialogFlags.MODAL, settings, account)
Philipp Hörist's avatar
Philipp Hörist committed
class CertificateDialog(SettingsDialog):
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self, account, parent):

Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.FILECHOOSER, _('Client Certificate'),
                    SettingType.ACCOUNT_CONFIG, 'client_cert',
                    props={'filefilter': (_('PKCS12 Files'), '*.p12')}),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Encrypted Certificate'),
                    SettingType.ACCOUNT_CONFIG, 'client_cert_encrypted'),
Philipp Hörist's avatar
Philipp Hörist committed
        SettingsDialog.__init__(self, parent, _('Certificate Settings'),
Philipp Hörist's avatar
Philipp Hörist committed
                                Gtk.DialogFlags.MODAL, settings, account)
Philipp Hörist's avatar
Philipp Hörist committed
class LoginDialog(SettingsDialog):
Philipp Hörist's avatar
Philipp Hörist committed
    def __init__(self, account, parent):

Philipp Hörist's avatar
Philipp Hörist committed
        settings = [
            Setting(SettingKind.ENTRY, _('Password'),
                    SettingType.ACCOUNT_CONFIG, 'password', name='password',
                    enabledif=('savepass', True)),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.SWITCH, _('Save Password'),
                    SettingType.ACCOUNT_CONFIG, 'savepass', name='savepass'),
Philipp Hörist's avatar
Philipp Hörist committed
            Setting(SettingKind.CHANGEPASSWORD, _('Change Password'),
                    SettingType.DIALOG, callback=self.on_password_change,
                    props={'dialog': None}),
Philipp Hörist's avatar
Philipp Hörist committed
        SettingsDialog.__init__(self, parent, _('Login Settings'),
Philipp Hörist's avatar
Philipp Hörist committed
                                Gtk.DialogFlags.MODAL, settings, account)
Philipp Hörist's avatar
Philipp Hörist committed

        self.connect('destroy', self.on_destroy)

Philipp Hörist's avatar
Philipp Hörist committed
    def on_password_change(self, new_password, _data):
        passwords.save_password(self.account, new_password)
Philipp Hörist's avatar
Philipp Hörist committed

    def on_destroy(self, *args):
        savepass = app.settings.get_account_setting(self.account, 'savepass')
Philipp Hörist's avatar
Philipp Hörist committed
        if not savepass:
            passwords.delete_password(self.account)