# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

import configparser
import gettext
import logging
import os
import re
import shutil
import tempfile
import threading

from gi.repository import GLib, GObject, Gtk

import tryton.common as common
import tryton.rpc as rpc
from tryton import __version__
from tryton.common.underline import set_underline
from tryton.config import CONFIG, PIXMAPS_DIR, TRYTON_ICON, get_config_dir

_ = gettext.gettext
logger = logging.getLogger(__name__)
DEMO_HOSTNAME = re.compile(r"demo\d+\.\d+\.tryton\.org")


class DBListEditor(object):

    def __init__(self, parent, profile_store, profiles, callback):
        self.profiles = profiles
        self.current_database = None
        self.old_profile, self.current_profile = None, None
        self.db_cache = None
        self.updating_db = False

        # GTK Stuffs
        self.parent = parent
        self.dialog = Gtk.Dialog(
            title=_('Profile Editor'), transient_for=parent,
            modal=True, destroy_with_parent=True)
        self.ok_button = self.dialog.add_button(
            set_underline(_("Close")), Gtk.ResponseType.CLOSE)
        self.dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.dialog.set_icon(TRYTON_ICON)
        common.setup_window(self.dialog)

        tooltips = common.Tooltips()

        hpaned = Gtk.HPaned()
        vbox_profiles = Gtk.VBox(homogeneous=False, spacing=6)
        self.cell = Gtk.CellRendererText()
        self.cell.set_property('editable', True)
        self.cell.connect('editing-started', self.edit_started)
        self.profile_tree = Gtk.TreeView()
        self.profile_tree.set_model(profile_store)
        self.profile_tree.insert_column_with_attributes(-1, _('Profile'),
            self.cell, text=0)
        self.profile_tree.connect('cursor-changed', self.profile_selected)
        scroll = Gtk.ScrolledWindow()
        scroll.set_policy(
            Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scroll.add(self.profile_tree)
        self.add_button = Gtk.Button()
        self.add_button.set_image(common.IconFactory.get_image(
                'tryton-add', Gtk.IconSize.BUTTON))
        tooltips.set_tip(self.add_button, _("Add new profile"))
        self.add_button.connect('clicked', self.profile_create)
        self.remove_button = Gtk.Button()
        self.remove_button.set_image(common.IconFactory.get_image(
                'tryton-remove', Gtk.IconSize.BUTTON))
        tooltips.set_tip(self.remove_button, _("Remove selected profile"))
        self.remove_button.get_style_context().add_class(
            Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION)
        self.remove_button.connect('clicked', self.profile_delete)
        bbox = Gtk.ButtonBox()
        bbox.pack_start(self.remove_button, expand=True, fill=True, padding=0)
        bbox.pack_start(self.add_button, expand=True, fill=True, padding=0)
        vbox_profiles.pack_start(scroll, expand=True, fill=True, padding=0)
        vbox_profiles.pack_start(bbox, expand=False, fill=True, padding=0)
        hpaned.add1(vbox_profiles)

        grid = Gtk.Grid(column_spacing=3, row_spacing=3)
        host = Gtk.Label(
            label=set_underline(_('Host:')),
            use_underline=True, halign=Gtk.Align.END)
        self.host_entry = Gtk.Entry(hexpand=True)
        self.host_entry.connect('focus-out-event', self.display_dbwidget)
        self.host_entry.connect('changed', self.update_profiles, 'host')
        self.host_entry.set_activates_default(True)
        host.set_mnemonic_widget(self.host_entry)
        grid.attach(host, 0, 1, 1, 1)
        grid.attach(self.host_entry, 1, 1, 1, 1)
        database = Gtk.Label(
            label=set_underline(_('Database:')),
            use_underline=True, halign=Gtk.Align.END)
        self.database_entry = Gtk.Entry()
        self.database_entry.connect('changed', self.dbentry_changed)
        self.database_entry.connect('changed', self.update_profiles,
            'database')
        self.database_entry.set_activates_default(True)
        self.database_label = Gtk.Label(valign=Gtk.Align.START)
        self.database_label.set_use_markup(True)
        self.database_combo = Gtk.ComboBoxText()
        self.database_combo.connect('changed', self.dbcombo_changed)
        self.database_progressbar = Gtk.ProgressBar()
        self.database_progressbar.set_text(_('Fetching databases list'))
        db_box = Gtk.VBox(homogeneous=True, hexpand=True)
        db_box.pack_start(
            self.database_entry, expand=True, fill=True, padding=0)
        db_box.pack_start(
            self.database_combo, expand=True, fill=True, padding=0)
        db_box.pack_start(
            self.database_label, expand=True, fill=True, padding=0)
        db_box.pack_start(
            self.database_progressbar, expand=True, fill=True, padding=0)
        # Compute size_request of box in order to prevent "form jumping"
        width, height = 0, 0
        for child in db_box.get_children():
            request = child.get_preferred_size()[0]
            width = max(width, request.width)
            height = max(height, request.height)
        db_box.set_size_request(width, height)
        grid.attach(database, 0, 2, 1, 1)
        grid.attach(db_box, 1, 2, 1, 1)
        username = Gtk.Label(
            label=set_underline(_('Username:')),
            use_underline=True, halign=Gtk.Align.END)
        self.username_entry = Gtk.Entry(hexpand=True)
        self.username_entry.connect('changed', self.update_profiles,
            'username')
        username.set_mnemonic_widget(self.username_entry)
        self.username_entry.set_activates_default(True)
        grid.attach(username, 0, 3, 1, 1)
        grid.attach(self.username_entry, 1, 3, 1, 1)
        hpaned.add2(grid)
        hpaned.set_position(250)

        self.dialog.vbox.pack_start(hpaned, expand=True, fill=True, padding=0)
        self.dialog.set_default_size(640, 350)
        self.dialog.set_default_response(Gtk.ResponseType.CLOSE)

        self.dialog.connect('close', lambda *a: False)
        self.dialog.connect('response', self.response)
        self.callback = callback

    def response(self, widget, response):
        if self.callback:
            self.callback(self.current_profile['name'])
        self.parent.present()
        self.dialog.destroy()

    def run(self, profile_name):
        self.clear_entries()  # must be done before show_all for windows
        self.dialog.show_all()
        model = self.profile_tree.get_model()
        if model:
            for i, row in enumerate(model):
                if row[0] == profile_name:
                    break
            else:
                i = 0
            self.profile_tree.get_selection().select_path((i,))
            self.profile_selected(self.profile_tree)

    def _current_profile(self):
        model, selection = self.profile_tree.get_selection().get_selected()
        if not selection:
            return {'name': None, 'iter': None}
        return {'name': model[selection][0], 'iter': selection}

    def clear_entries(self):
        for entryname in ('host', 'database', 'username'):
            entry = getattr(self, '%s_entry' % entryname)
            entry.handler_block_by_func(self.update_profiles)
            entry.set_text('')
            entry.handler_unblock_by_func(self.update_profiles)
        self.current_database = None
        self.database_combo.set_active(-1)
        self.database_combo.get_model().clear()
        self.hide_database_info()

    def hide_database_info(self):
        self.database_entry.hide()
        self.database_combo.hide()
        self.database_label.hide()
        self.database_progressbar.hide()

    def profile_create(self, button):
        self.clear_entries()
        model = self.profile_tree.get_model()
        model.append(['', False])
        column = self.profile_tree.get_column(0)
        self.profile_tree.set_cursor(len(model) - 1, column,
            start_editing=True)
        self.db_cache = None

    def profile_delete(self, button):
        self.clear_entries()
        model, selection = self.profile_tree.get_selection().get_selected()
        if not selection:
            return
        profile_name = model[selection][0]
        self.profiles.remove_section(profile_name)
        del model[selection]

    def profile_selected(self, treeview):
        self.old_profile = self.current_profile
        self.current_profile = self._current_profile()
        if not self.current_profile['name']:
            return
        if self.updating_db:
            self.current_profile = self.old_profile
            selection = treeview.get_selection()
            selection.select_iter(self.old_profile['iter'])
            return
        fields = ('host', 'database', 'username')
        for field in fields:
            entry = getattr(self, '%s_entry' % field)
            try:
                entry_value = self.profiles.get(self.current_profile['name'],
                    field)
            except configparser.NoOptionError:
                entry_value = ''
            entry.set_text(entry_value)
            if field == 'database':
                self.current_database = entry_value

        self.display_dbwidget(None, None)

    def edit_started(self, renderer, editable, path):
        if isinstance(editable, Gtk.Entry):
            editable.connect('focus-out-event', self.edit_profilename,
                renderer, path)

    def edit_profilename(self, editable, event, renderer, path):
        newtext = editable.get_text()
        model = self.profile_tree.get_model()
        try:
            oldname = model[path][0]
        except IndexError:
            return
        if oldname == newtext == '':
            del model[path]
            return
        elif oldname == newtext or newtext == '':
            return
        elif newtext in self.profiles.sections():
            if not oldname:
                del model[path]
            return
        elif oldname in self.profiles.sections():
            self.profiles.add_section(newtext)
            for itemname, value in self.profiles.items(oldname):
                self.profiles.set(newtext, itemname, value)
            self.profiles.remove_section(oldname)
            model[path][0] = newtext
        else:
            model[path][0] = newtext
            self.profiles.add_section(newtext)
        self.current_profile = self._current_profile()
        self.host_entry.grab_focus()

    def update_profiles(self, editable, entryname):
        new_value = editable.get_text()
        if not new_value:
            return
        section = self._current_profile()['name']
        self.profiles.set(section, entryname, new_value)
        self.validate_profile(section)

    def validate_profile(self, profile_name):
        model, selection = self.profile_tree.get_selection().get_selected()
        if not selection:
            return
        active = all(self.profiles.has_option(profile_name, option)
            for option in ('host', 'database'))
        model[selection][1] = active

    @classmethod
    def test_server_version(cls, host, port):
        '''
        Tests if the server version is compatible with the client version
        It returns None if no information on server version is available.
        '''
        version = rpc.server_version(host, port)
        if not version:
            return None
        return version.split('.')[:2] == __version__.split('.')[:2]

    def refresh_databases(self, host, port):
        self.dbs_updated = threading.Event()
        if CONFIG['thread']:
            threading.Thread(target=self.refresh_databases_start,
                args=(host, port)).start()
            GLib.timeout_add(100, self.refresh_databases_end, host, port)
        else:
            self.refresh_databases_start(host, port)
            self.refresh_databases_end(host, port)

    def refresh_databases_start(self, host, port):
        dbs = None
        try:
            dbs = rpc.db_list(host, port)
        except Exception:
            pass
        finally:
            self.dbs = dbs
            self.dbs_updated.set()

    def refresh_databases_end(self, host, port):
        if not self.dbs_updated.isSet():
            self.database_progressbar.show()
            self.database_progressbar.pulse()
            return True
        self.database_progressbar.hide()
        dbs = self.dbs

        label = None
        if self.test_server_version(host, port) is False:
            label = _('Incompatible version of the server.')
        elif dbs is None:
            label = _('Could not connect to the server.')
        if label:
            self.database_label.set_label(
                '<b>%s</b>' % GLib.markup_escape_text(label))
            self.database_label.show()
        else:
            self.database_combo.remove_all()
            index = -1
            for db_num, db_name in enumerate(dbs):
                self.database_combo.append_text(db_name)
                if self.current_database and db_name == self.current_database:
                    index = db_num
            if index == -1:
                index = 0
            self.database_combo.set_active(index)
            self.database_entry.set_text(self.current_database
                if self.current_database else '')
            if dbs:
                self.database_combo.show()
            else:
                self.database_entry.show()
        self.db_cache = (host, port, self.current_profile['name'])

        self.add_button.set_sensitive(True)
        self.remove_button.set_sensitive(True)
        self.ok_button.set_sensitive(True)
        self.cell.set_property('editable', True)
        self.host_entry.set_sensitive(True)
        self.updating_db = False
        return False

    def display_dbwidget(self, entry, event):
        netloc = self.host_entry.get_text()
        host = common.get_hostname(netloc)
        if not host:
            return
        port = common.get_port(netloc)
        if (host, port, self.current_profile['name']) == self.db_cache:
            return
        if self.updating_db:
            return

        self.hide_database_info()
        self.add_button.set_sensitive(False)
        self.remove_button.set_sensitive(False)
        self.ok_button.set_sensitive(False)
        self.cell.set_property('editable', False)
        self.host_entry.set_sensitive(False)
        self.updating_db = True
        self.refresh_databases(host, port)

    def dbcombo_changed(self, combobox):
        dbname = combobox.get_active_text()
        if dbname:
            self.current_database = dbname
            self.profiles.set(self.current_profile['name'], 'database', dbname)
            self.validate_profile(self.current_profile['name'])

    def dbentry_changed(self, entry):
        dbname = entry.get_text()
        if dbname:
            self.current_database = dbname
            self.profiles.set(self.current_profile['name'], 'database', dbname)
            self.validate_profile(self.current_profile['name'])

    def insert_text_port(self, entry, new_text, new_text_length, position):
        value = entry.get_text()
        position = entry.get_position()
        new_value = value[:position] + new_text + value[position:]
        try:
            int(new_value)
        except ValueError:
            entry.stop_emission_by_name('insert-text')


class DBLogin(object):
    def __init__(self):
        # Fake windows to avoid warning about Dialog without transient
        self._window = Gtk.Window()
        self.dialog = Gtk.Dialog(title="Tryton - " + _('Login'), modal=True)
        self.dialog.set_transient_for(self._window)
        self.dialog.set_icon(TRYTON_ICON)
        self.dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        self.dialog.set_resizable(False)
        common.setup_window(self.dialog)

        tooltips = common.Tooltips()
        button_cancel = Gtk.Button(label=_('_Cancel'), use_underline=True)
        tooltips.set_tip(button_cancel,
            _('Cancel connection to the Tryton server'))
        self.dialog.add_action_widget(button_cancel, Gtk.ResponseType.CANCEL)
        self.button_connect = Gtk.Button(
            label=_('C_onnect'), use_underline=True)
        self.button_connect.get_style_context().add_class(
            Gtk.STYLE_CLASS_SUGGESTED_ACTION)
        self.button_connect.set_can_default(True)
        tooltips.set_tip(self.button_connect, _('Connect the Tryton server'))
        self.dialog.add_action_widget(self.button_connect, Gtk.ResponseType.OK)
        self.dialog.set_default_response(Gtk.ResponseType.OK)
        grid = Gtk.Grid(
            column_spacing=3, row_spacing=3, valign=Gtk.Align.START)
        self.dialog.vbox.pack_start(grid, expand=True, fill=True, padding=0)

        image = Gtk.Image()
        image.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.svg'))
        image.set_valign(Gtk.Align.START)
        overlay = Gtk.Overlay()
        overlay.add(image)
        label = Gtk.Label(
            label='<span color="white">%s</span>' % __version__,
            use_markup=True)
        label.props.halign = Gtk.Align.END
        label.props.valign = Gtk.Align.START
        label.props.margin_right = 10
        label.props.margin_top = 5
        overlay.add_overlay(label)
        grid.attach(overlay, 0, 0, 3, 1)

        self.profile_store = Gtk.ListStore(
            GObject.TYPE_STRING, GObject.TYPE_BOOLEAN)
        self.combo_profile = Gtk.ComboBox(hexpand=True)
        cell = Gtk.CellRendererText()
        self.combo_profile.pack_start(cell, expand=True)
        self.combo_profile.add_attribute(cell, 'text', 0)
        self.combo_profile.add_attribute(cell, 'sensitive', 1)
        self.combo_profile.set_model(self.profile_store)
        self.combo_profile.connect('changed', self.profile_changed)
        self.profile_label = Gtk.Label(
            label=set_underline(_('Profile:')),
            use_underline=True, halign=Gtk.Align.END)
        self.profile_label.set_mnemonic_widget(self.combo_profile)
        self.profile_button = Gtk.Button(
            label=set_underline(_('Manage...')), use_underline=True)
        self.profile_button.connect('clicked', self.profile_manage)
        grid.attach(self.profile_label, 0, 1, 1, 1)
        grid.attach(self.combo_profile, 1, 1, 1, 1)
        grid.attach(self.profile_button, 2, 1, 1, 1)
        self.expander = Gtk.Expander()
        self.expander.set_label(_('Host / Database information'))
        self.expander.connect('notify::expanded', self.expand_hostspec)
        grid.attach(self.expander, 0, 2, 3, 1)
        self.label_host = Gtk.Label(
            label=set_underline(_('Host:')),
            use_underline=True, halign=Gtk.Align.END)
        self.entry_host = Gtk.Entry(hexpand=True)
        self.entry_host.connect_after('focus-out-event',
            self.clear_profile_combo)
        self.entry_host.connect('focus-out-event', self.update_services)
        self.entry_host.set_activates_default(True)
        self.label_host.set_mnemonic_widget(self.entry_host)
        grid.attach(self.label_host, 0, 3, 1, 1)
        grid.attach(self.entry_host, 1, 3, 2, 1)
        self.label_database = Gtk.Label(
            label=set_underline(_('Database:')),
            use_underline=True, halign=Gtk.Align.END)
        self.entry_database = Gtk.Entry(hexpand=True)
        self.entry_database.connect_after('focus-out-event',
            self.clear_profile_combo)
        self.entry_database.set_activates_default(True)
        self.label_database.set_mnemonic_widget(self.entry_database)
        grid.attach(self.label_database, 0, 4, 1, 1)
        grid.attach(self.entry_database, 1, 4, 2, 1)
        self.entry_login = Gtk.Entry(hexpand=True)
        self.entry_login.set_activates_default(True)
        grid.attach(self.entry_login, 1, 5, 2, 1)
        label_username = Gtk.Label(
            label=set_underline(_("User name:")),
            use_underline=True, halign=Gtk.Align.END, margin=3)
        label_username.set_mnemonic_widget(self.entry_login)
        grid.attach(label_username, 0, 5, 1, 1)

        # Profile information
        config_dir = get_config_dir()
        self.profile_cfg = os.path.join(config_dir, 'profiles.cfg')
        self.profiles = configparser.ConfigParser()
        series = '.'.join(__version__.split('.', 2)[:2])
        current_demo = f"demo{series}.tryton.org"
        try:
            self.profiles.read(self.profile_cfg)
        except configparser.Error:
            # reset self.profiles as parsing errors may leave wrong data in
            # the parser
            self.profiles = configparser.ConfigParser()
            with tempfile.NamedTemporaryFile(
                    delete=False, prefix='profiles_', suffix='.cfg',
                    dir=config_dir) as temp_file:
                temp_name = temp_file.name
            shutil.copy(self.profile_cfg, temp_name)
            logger.error(
                f"Failed to parse {self.profiles_cfg}. "
                f"A backup can be found at {temp_name}",
                exc_info=True)
        if not self.profiles.sections():
            self.profiles.add_section(current_demo)
            self.profiles.set(current_demo, 'host', current_demo)
            self.profiles.set(current_demo, 'database', f'demo{series}')
            self.profiles.set(current_demo, 'username', 'demo')
        to_remove = []
        for section in self.profiles.sections():
            host = self.profiles.get(section, 'host', fallback='')
            if host and DEMO_HOSTNAME.match(host) and host != current_demo:
                to_remove.append(section)
                continue
            active = all(self.profiles.has_option(section, option)
                for option in ('host', 'database'))
            self.profile_store.append([section, active])
        for section in to_remove:
            self.profiles.remove_section(section)
        if to_remove and not self.profiles.has_section(current_demo):
            self.profiles.add_section(current_demo)
            self.profiles.set(current_demo, 'host', current_demo)
            self.profiles.set(current_demo, 'database', f'demo{series}')
            self.profiles.set(current_demo, 'username', 'demo')
            self.profile_store.append([current_demo, True])

        self.services = []
        self.service_base = ''
        self._services = {}

    def profile_manage(self, widget):
        def callback(profile_name):
            with open(self.profile_cfg, 'w') as configfile:
                self.profiles.write(configfile)

            for idx, row in enumerate(self.profile_store):
                if row[0] == profile_name and row[1]:
                    self.combo_profile.set_active(idx)
                    self.profile_changed(self.combo_profile)
                    break

        dia = DBListEditor(self.dialog, self.profile_store, self.profiles,
            callback)
        active_profile = self.combo_profile.get_active()
        profile_name = None
        if active_profile != -1:
            profile_name = self.profile_store[active_profile][0]
        dia.run(profile_name)

    def profile_changed(self, combobox):
        position = combobox.get_active()
        if position == -1:
            return
        profile = self.profile_store[position][0]
        try:
            username = self.profiles.get(profile, 'username')
        except configparser.NoOptionError:
            username = ''
        host = self.profiles.get(profile, 'host')
        self.entry_host.set_text('%s' % host)
        self.entry_database.set_text(self.profiles.get(profile, 'database'))
        if username:
            self.entry_login.set_text(username)
        else:
            self.entry_login.set_text('')
        self.update_services()

    def clear_profile_combo(self, *args):
        netloc = self.entry_host.get_text()
        host = common.get_hostname(netloc)
        port = common.get_port(netloc)
        database = self.entry_database.get_text().strip()
        login = self.entry_login.get_text()
        for idx, profile_info in enumerate(self.profile_store):
            if not profile_info[1]:
                continue
            profile = profile_info[0]
            try:
                profile_host = self.profiles.get(profile, 'host')
                profile_db = self.profiles.get(profile, 'database')
                profile_login = self.profiles.get(profile, 'username')
            except configparser.NoOptionError:
                continue
            if (host == common.get_hostname(profile_host)
                    and port == common.get_port(profile_host)
                    and database == profile_db
                    and (not login or login == profile_login)):
                break
        else:
            idx = -1
        self.combo_profile.set_active(idx)
        return False

    def expand_hostspec(self, expander, *args):
        visibility = expander.props.expanded
        self.entry_host.props.visible = visibility
        self.label_host.props.visible = visibility
        self.entry_database.props.visible = visibility
        self.label_database.props.visible = visibility

    def update_services(self, *args):
        host = self.entry_host.get_text()
        hostname = common.get_hostname(host)
        port = common.get_port(host)
        key = (hostname, port)
        for response_id, service in enumerate(self.services, 1):
            button = self.dialog.get_widget_for_response(response_id)
            button.get_parent().remove(button)
        self.services = []
        if key in self._services:
            self.services, self.service_base = self._services[key]
        elif hostname and port:
            self.service_base, self.services = rpc.authentication_services(
                hostname, port)
            self._services[key] = (self.services, self.service_base)
        for response_id, (name, url) in enumerate(self.services, 1):
            button = Gtk.Button(label=name)
            self.dialog.add_action_widget(button, response_id)
            button.show()

        # Re-add connect button to be last
        button_connect = self.dialog.get_widget_for_response(
            Gtk.ResponseType.OK)
        button_connect.get_parent().remove(button_connect)
        self.dialog.add_action_widget(button_connect, Gtk.ResponseType.OK)
        self.dialog.set_default_response(Gtk.ResponseType.OK)

    def run(self):
        profile_name = CONFIG['login.profile']
        can_use_profile = self.profiles.has_section(profile_name)
        if can_use_profile:
            for (configname, option) in [
                    ('login.host', 'host'),
                    ('login.db', 'database'),
                    ]:
                try:
                    value = self.profiles.get(profile_name, option)
                except configparser.NoOptionError:
                    value = None
                if value != CONFIG[configname]:
                    can_use_profile = False
                    break

        if can_use_profile:
            for idx, row in enumerate(self.profile_store):
                if row[0] == profile_name:
                    self.combo_profile.set_active(idx)
                    break
        else:
            self.combo_profile.set_active(-1)
            host = CONFIG['login.host'] if CONFIG['login.host'] else ''
            self.entry_host.set_text(host)
            db = CONFIG['login.db'] if CONFIG['login.db'] else ''
            self.entry_database.set_text(db)
            self.entry_login.set_text(CONFIG['login.login'])
            self.clear_profile_combo()
        self.update_services()
        self.dialog.show_all()

        self.entry_login.grab_focus()

        self.expander.set_expanded(CONFIG['login.expanded'])
        # The previous action did not called expand_hostspec
        self.expand_hostspec(self.expander)

        response, result = None, ('', '', '', '')
        while not all(result):
            response = self.dialog.run()
            if response != Gtk.ResponseType.OK and response <= 0:
                break
            self.clear_profile_combo()
            active_profile = self.combo_profile.get_active()
            if active_profile != -1:
                profile = self.profile_store[active_profile][0]
            else:
                profile = ''
            host = self.entry_host.get_text()
            hostname = common.get_hostname(host)
            port = common.get_port(host)
            test = DBListEditor.test_server_version(hostname, port)
            if not test:
                if test is False:
                    common.warning('',
                        _('Incompatible version of the server.'),
                        parent=self.dialog)
                else:
                    common.warning('',
                        _('Could not connect to the server.'),
                        parent=self.dialog)
                continue
            database = self.entry_database.get_text()
            CONFIG['login.profile'] = profile
            CONFIG['login.host'] = host
            CONFIG['login.db'] = database
            CONFIG['login.expanded'] = self.expander.props.expanded
            if response == Gtk.ResponseType.OK:
                authentication = self.entry_login.get_text()
                CONFIG['login.login'] = authentication
                CONFIG['login.service'] = ''
            else:
                authentication = self.services[response - 1][1]
                authentication = (
                    self.service_base + database + authentication)
                CONFIG['login.login'] = ''
                CONFIG['login.service'] = authentication
            result = (hostname, port, database, authentication)

        self.dialog.destroy()
        self._window.destroy()
        return response == Gtk.ResponseType.OK or response > 0
