Exemplo n.º 1
0
def get_dbowner_connection(procedure=None, dbo_password=None, dbo_account='gm-dbo'):
	if procedure is None:
		procedure = _('<restricted procedure>')

	# 1) get password for gm-dbo
	if dbo_password is None:
		dbo_password = wx.GetPasswordFromUser (
			message = _("""
 [%s]

This is a restricted procedure. We need the
current password for the GNUmed database owner.

Please enter the current password for <%s>:""") % (
				procedure,
				dbo_account
			),
			caption = procedure
		)
		if dbo_password == '':
			return None

	gmLog2.add_word2hide(dbo_password)

	# 2) connect as gm-dbo
	login = gmPG2.get_default_login()
	dsn = gmPG2.make_psycopg2_dsn (
		database = login.database,
		host = login.host,
		port = login.port,
		user = dbo_account,
		password = dbo_password
	)
	try:
		conn = gmPG2.get_connection (
			dsn = dsn,
			readonly = False,
			verbose = True,
			pooled = False
		)
	except:
		_log.exception('cannot connect')
		gmGuiHelpers.gm_show_error (
			aMessage = _('Cannot connect as the GNUmed database owner <%s>.') % dbo_account,
			aTitle = procedure
		)
		gmPG2.log_database_access(action = 'failed to connect as database owner for [%s]' % procedure)
		return None

	return conn
Exemplo n.º 2
0
def get_dbowner_connection(procedure=None,
                           dbo_password=None,
                           dbo_account='gm-dbo'):
    if procedure is None:
        procedure = _('<restricted procedure>')

    # 1) get password for gm-dbo
    if dbo_password is None:
        dbo_password = wx.GetPasswordFromUser(message=_("""
 [%s]

This is a restricted procedure. We need the
current password for the GNUmed database owner.

Please enter the current password for <%s>:""") % (procedure, dbo_account),
                                              caption=procedure)
        if dbo_password == '':
            return None

    gmLog2.add_word2hide(dbo_password)

    # 2) connect as gm-dbo
    login = gmPG2.get_default_login()
    dsn = gmPG2.make_psycopg2_dsn(database=login.database,
                                  host=login.host,
                                  port=login.port,
                                  user=dbo_account,
                                  password=dbo_password)
    try:
        conn = gmPG2.get_connection(dsn=dsn,
                                    readonly=False,
                                    verbose=True,
                                    pooled=False)
    except Exception:
        _log.exception('cannot connect')
        gmGuiHelpers.gm_show_error(
            aMessage=_('Cannot connect as the GNUmed database owner <%s>.') %
            dbo_account,
            aTitle=procedure)
        gmPG2.log_database_access(
            action='failed to connect as database owner for [%s]' % procedure)
        return None

    return conn
Exemplo n.º 3
0
def connect_to_database(login_info=None,
                        max_attempts=3,
                        expected_version=None,
                        require_version=True):
    """Display the login dialog and try to log into the backend.

	- up to max_attempts times
	- returns True/False
	"""
    # force programmer to set a valid expected_version
    expected_hash = gmPG2.known_schema_hashes[expected_version]
    client_version = _cfg.get(option=u'client_version')
    global current_db_name
    current_db_name = u'gnumed_v%s' % expected_version

    attempt = 0

    while attempt < max_attempts:

        _log.debug('login attempt %s of %s', (attempt + 1), max_attempts)

        connected = False

        login = login_info
        if login is None:
            _log.info("did not provide a login information")

        # try getting a connection to verify the DSN works
        dsn = gmPG2.make_psycopg2_dsn(database=login.database,
                                      host=login.host,
                                      port=login.port,
                                      user=login.user,
                                      password=login.password)
        try:
            conn = gmPG2.get_raw_connection(dsn=dsn,
                                            verbose=True,
                                            readonly=True)
            connected = True

        except gmPG2.cAuthenticationError, e:
            attempt += 1
            _log.error(u"login attempt failed: %s", e)
            if attempt < max_attempts:
                if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host='
                                                          not in (u'%s' % e)):
                    msg = _(
                        'Unable to connect to database:\n\n'
                        '%s\n\n'
                        "Are you sure you have got a local database installed ?\n"
                        '\n'
                        "Please retry with proper credentials or cancel.\n"
                        '\n'
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL')
                else:
                    msg = _(
                        "Unable to connect to database:\n\n"
                        "%s\n\n"
                        "Please retry with proper credentials or cancel.\n"
                        "\n"
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL')
                msg = msg % e
                msg = regex.sub(
                    r'password=[^\s]+',
                    u'password=%s' % gmTools.u_replacement_character, msg)
                gmGuiHelpersWeb.gm_show_error(msg, _('Connecting to backend'))
            del e
            continue

        except gmPG2.dbapi.OperationalError, e:
            _log.error(u"login attempt failed: %s", e)
            msg = _(
                "Unable to connect to database:\n\n"
                "%s\n\n"
                "Please retry another backend / user / password combination !\n"
            ) % gmPG2.extract_msg_from_pg_exception(e)
            msg = regex.sub(r'password=[^\s]+',
                            u'password=%s' % gmTools.u_replacement_character,
                            msg)
            gmGuiHelpersWeb.gm_show_error(msg, _('Connecting to backend'))
            del e
            continue
Exemplo n.º 4
0
def connect_to_database(max_attempts=3,
                        expected_version=None,
                        require_version=True):
    """Display the login dialog and try to log into the backend.

	- up to max_attempts times
	- returns True/False
	"""
    # force programmer to set a valid expected_version
    expected_hash = gmPG2.known_schema_hashes[expected_version]
    client_version = _cfg.get(option='client_version')
    global current_db_name
    current_db_name = 'gnumed_v%s' % expected_version

    attempt = 0

    dlg = cLoginDialog(None, -1, client_version=client_version)
    dlg.Centre(wx.BOTH)

    while attempt < max_attempts:

        _log.debug('login attempt %s of %s', (attempt + 1), max_attempts)

        connected = False

        dlg.ShowModal()
        login = dlg.panel.GetLoginInfo()
        if login is None:
            _log.info("user cancelled login dialog")
            break

        gmLog2.add_word2hide(login.password)

        # try getting a connection to verify the DSN works
        dsn = gmPG2.make_psycopg2_dsn(database=login.database,
                                      host=login.host,
                                      port=login.port,
                                      user=login.user,
                                      password=login.password)
        try:
            conn = gmPG2.get_raw_connection(dsn=dsn,
                                            verbose=True,
                                            readonly=True)
            connected = True

        except gmPG2.cAuthenticationError as e:
            attempt += 1
            _log.error("login attempt failed: %s", e)
            if attempt < max_attempts:
                if ('host=127.0.0.1' in ('%s' % e)) or ('host='
                                                        not in ('%s' % e)):
                    msg = _(
                        'Unable to connect to database:\n\n'
                        '%s\n\n'
                        "Are you sure you have got a local database installed ?\n"
                        '\n'
                        "Please retry with proper credentials or cancel.\n"
                        '\n'
                        ' (for the public and any new GNUmed data-\n'
                        '  bases the default user name and password\n'
                        '  are {any-doc, any-doc})\n'
                        '\n'
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL')
                else:
                    msg = _(
                        "Unable to connect to database:\n\n"
                        "%s\n\n"
                        "Please retry with proper credentials or cancel.\n"
                        "\n"
                        "For the public and any new GNUmed databases the\n"
                        "default user name and password are {any-doc, any-doc}.\n"
                        "\n"
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL')
                msg = msg % e
                msg = regex.sub(
                    r'password=[^\s]+',
                    'password=%s' % gmTools.u_replacement_character, msg)
                gmGuiHelpers.gm_show_error(msg, _('Connecting to backend'))
            del e
            continue

        except gmPG2.dbapi.OperationalError as exc:
            _log.exception('login attempt failed')
            gmPG2.log_pg_exception_details(exc)
            msg = _(
                "Unable to connect to database:\n\n"
                "%s\n\n"
                "Please retry another backend / user / password combination !\n"
                "\n"
                " (for the public and any new GNUmed databases\n"
                "  the default user name and password are\n"
                "  {any-doc, any-doc})\n"
                "\n") % exc
            msg = regex.sub(r'password=[^\s]+',
                            'password=%s' % gmTools.u_replacement_character,
                            msg)
            gmGuiHelpers.gm_show_error(msg, _('Connecting to backend'))
            del exc
            continue

        conn.close()

        # connect was successful
        gmPG2.set_default_login(login=login)
        gmPG2.set_default_client_encoding(
            encoding=dlg.panel.backend_profile.encoding)

        seems_bootstrapped = gmPG2.schema_exists(schema='gm')
        if not seems_bootstrapped:
            _log.error(
                'schema [gm] does not exist - database not bootstrapped ?')
            msg = _('The database you connected to does not seem\n'
                    'to have been boostrapped properly.\n'
                    '\n'
                    'Make sure you have run the GNUmed database\n'
                    'bootstrapper tool to create a new database.\n'
                    '\n'
                    'Further help can be found on the website at\n'
                    '\n'
                    '  http://wiki.gnumed.de\n'
                    '\n'
                    'or on the GNUmed mailing list.')
            gmGuiHelpers.gm_show_error(msg, _('Verifying database'))
            connected = False
            break

        compatible = gmPG2.database_schema_compatible(version=expected_version)
        if compatible or not require_version:
            dlg.panel.save_state()

        if not compatible:
            connected_db_version = gmPG2.get_schema_version()
            msg = msg_generic % (client_version, connected_db_version,
                                 expected_version,
                                 gmTools.coalesce(login.host, '<localhost>'),
                                 login.database, login.user)
            if require_version:
                gmGuiHelpers.gm_show_error(msg + msg_fail,
                                           _('Verifying database version'))
                connected = False
                continue
            gmGuiHelpers.gm_show_info(msg + msg_override,
                                      _('Verifying database version'))

        # FIXME: make configurable
        max_skew = 1  # minutes
        if _cfg.get(option='debug'):
            max_skew = 10
        if not gmPG2.sanity_check_time_skew(tolerance=(max_skew * 60)):
            if _cfg.get(option='debug'):
                gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew,
                                             _('Verifying database settings'))
            else:
                gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew,
                                           _('Verifying database settings'))
                connected = False
                continue

        sanity_level, message = gmPG2.sanity_check_database_settings()
        if sanity_level != 0:
            gmGuiHelpers.gm_show_error((msg_insanity % message),
                                       _('Verifying database settings'))
            if sanity_level == 2:
                connected = False
                continue

        gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
        gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)

        conn = gmPG2.get_connection(
            verbose=True,
            connection_name='GNUmed-[DbListenerThread]',
            pooled=False)
        listener = gmBackendListener.gmBackendListener(conn=conn)
        break

    dlg.DestroyLater()

    return connected
Exemplo n.º 5
0
def process_options():

    if _cfg.get(option='-h', source_order=[('cli', 'return')]):
        show_usage()
        sys.exit(0)

    if _cfg.get(option='-?', source_order=[('cli', 'return')]):
        show_usage()
        sys.exit(0)

    if _cfg.get(option='--help', source_order=[('cli', 'return')]):
        show_usage()
        sys.exit(0)

    file2import = _cfg.get(option='--file2import',
                           source_order=[('cli', 'return')])
    if file2import is None:
        exit_with_message('ERROR: option --file2import missing')
    if file2import is True:
        exit_with_message('ERROR: data file missing in option --file2import=')
    try:
        open(file2import).close()
    except IOError:
        _log.exception('cannot open data file')
        exit_with_message(
            'ERROR: cannot open data file in option --file2import=%s' %
            file2import)

    datatype = _cfg.get(option='--data-type', source_order=[('cli', 'return')])
    if datatype is None:
        exit_with_message('ERROR: option --data-type missing')
    if datatype is True:
        exit_with_message('ERROR: data type missing in option --data-type=')
    if datatype.strip() == '':
        exit_with_message(
            'ERROR: invalid data type in option --data-type=>>>%s<<<' %
            datatype)

    db_user = _cfg.get(option='--user', source_order=[('cli', 'return')])
    if db_user is None:
        exit_with_message('ERROR: option --user missing')
    if db_user is True:
        exit_with_message('ERROR: user name missing in option --user='******'':
        exit_with_message(
            'ERROR: invalid user name in option --user=>>>%s<<<' % db_user)

    db_host = _cfg.get(option='--host', source_order=[('cli', 'return')])
    if db_host is None:
        _log.debug(
            'option --host not set, using <UNIX domain socket> on <localhost>')
    elif db_host is True:
        exit_with_message('ERROR: host name missing in option --host=')
    elif db_host.strip() == '':
        _log.debug(
            'option --host set to "", using <UNIX domain socket> on <localhost>'
        )
        db_host = None

    db_port = _cfg.get(option='--port', source_order=[('cli', 'return')])
    if db_port is None:
        _log.debug(
            'option --port not set, using <UNIX domain socket> on <localhost>')
    elif db_port is True:
        exit_with_message('ERROR: port value missing in option --port=')
    elif db_port.strip() == '':
        _log.debug(
            'option --port set to "", using <UNIX domain socket> on <localhost>'
        )
        db_port = None
    else:
        converted, db_port = gmTools.input2int(initial=db_port,
                                               minval=1024,
                                               maxval=65535)
        if not converted:
            exit_with_message(
                'ERROR: invalid port in option --port=%s (must be 1024...65535)'
                % db_port)

    gmPG2.log_auth_environment()
    dsn = gmPG2.make_psycopg2_dsn(
        database=gmPG2.default_database,
        host=db_host,
        port=db_port,
        user=db_user,
        password=
        None  # None = force not-required (TRUST/IDENT/PEER) or use-.pgpass-or-$PGPASSFILE
    )
    gmPG2._default_dsn = dsn

    return datatype, file2import
Exemplo n.º 6
0
def process_options():

	if _cfg.get(option = '-h', source_order = [('cli', 'return')]):
		show_usage()
		sys.exit(0)

	if _cfg.get(option = '-?', source_order = [('cli', 'return')]):
		show_usage()
		sys.exit(0)

	if _cfg.get(option = '--help', source_order = [('cli', 'return')]):
		show_usage()
		sys.exit(0)

	file2import = _cfg.get(option = '--file2import', source_order = [('cli', 'return')])
	if file2import is None:
		exit_with_message('ERROR: option --file2import missing')
	if file2import is True:
		exit_with_message('ERROR: data file missing in option --file2import=')
	try:
		open(file2import).close()
	except IOError:
		_log.exception('cannot open data file')
		exit_with_message('ERROR: cannot open data file in option --file2import=%s' % file2import)

	datatype = _cfg.get(option = '--data-type', source_order = [('cli', 'return')])
	if datatype is None:
		exit_with_message('ERROR: option --data-type missing')
	if datatype is True:
		exit_with_message('ERROR: data type missing in option --data-type=')
	if datatype.strip() == '':
		exit_with_message('ERROR: invalid data type in option --data-type=>>>%s<<<' % datatype)

	db_user = _cfg.get(option = '--user', source_order = [('cli', 'return')])
	if db_user is None:
		exit_with_message('ERROR: option --user missing')
	if db_user is True:
		exit_with_message('ERROR: user name missing in option --user='******'':
		exit_with_message('ERROR: invalid user name in option --user=>>>%s<<<' % db_user)

	db_host = _cfg.get(option = '--host', source_order = [('cli', 'return')])
	if db_host is None:
		_log.debug('option --host not set, using <UNIX domain socket> on <localhost>')
	elif db_host is True:
		exit_with_message('ERROR: host name missing in option --host=')
	elif db_host.strip() == '':
		_log.debug('option --host set to "", using <UNIX domain socket> on <localhost>')
		db_host = None

	db_port = _cfg.get(option = '--port', source_order = [('cli', 'return')])
	if db_port is None:
		_log.debug('option --port not set, using <UNIX domain socket> on <localhost>')
	elif db_port is True:
		exit_with_message('ERROR: port value missing in option --port=')
	elif db_port.strip() == '':
		_log.debug('option --port set to "", using <UNIX domain socket> on <localhost>')
		db_port = None
	else:
		converted, db_port = gmTools.input2int(initial = db_port, minval = 1024, maxval = 65535)
		if not converted:
			exit_with_message('ERROR: invalid port in option --port=%s (must be 1024...65535)' % db_port)

	gmPG2.log_auth_environment()
	dsn = gmPG2.make_psycopg2_dsn (
		database = gmPG2.default_database,
		host = db_host,
		port = db_port,
		user = db_user,
		password = None			# None = force not-required (TRUST/IDENT/PEER) or use-.pgpass-or-$PGPASSFILE
	)
	gmPG2._default_dsn = dsn

	return datatype, file2import
Exemplo n.º 7
0
def connect_to_database(max_attempts=3, expected_version=None, require_version=True):
    """Display the login dialog and try to log into the backend.

	- up to max_attempts times
	- returns True/False
	"""
    # force programmer to set a valid expected_version
    expected_hash = gmPG2.known_schema_hashes[expected_version]
    client_version = _cfg.get(option=u"client_version")
    global current_db_name
    current_db_name = u"gnumed_v%s" % expected_version

    attempt = 0

    dlg = cLoginDialog(None, -1, client_version=client_version)
    dlg.Centre(wx.BOTH)

    while attempt < max_attempts:

        _log.debug("login attempt %s of %s", (attempt + 1), max_attempts)

        connected = False

        dlg.ShowModal()
        login = dlg.panel.GetLoginInfo()
        if login is None:
            _log.info("user cancelled login dialog")
            break

            # try getting a connection to verify the DSN works
        dsn = gmPG2.make_psycopg2_dsn(
            database=login.database, host=login.host, port=login.port, user=login.user, password=login.password
        )
        try:
            conn = gmPG2.get_raw_connection(dsn=dsn, verbose=True, readonly=True)
            connected = True

        except gmPG2.cAuthenticationError, e:
            attempt += 1
            _log.error(u"login attempt failed: %s", e)
            if attempt < max_attempts:
                if (u"host=127.0.0.1" in (u"%s" % e)) or (u"host=" not in (u"%s" % e)):
                    msg = _(
                        "Unable to connect to database:\n\n"
                        "%s\n\n"
                        "Are you sure you have got a local database installed ?\n"
                        "\n"
                        "Please retry with proper credentials or cancel.\n"
                        "\n"
                        " (for the public and any new GNUmed data-\n"
                        "  bases the default user name and password\n"
                        "  are {any-doc, any-doc})\n"
                        "\n"
                        "You may also need to check the PostgreSQL client\n"
                        "authentication configuration in pg_hba.conf. For\n"
                        "details see:\n"
                        "\n"
                        "wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL"
                    )
                else:
                    msg = _(
                        "Unable to connect to database:\n\n"
                        "%s\n\n"
                        "Please retry with proper credentials or cancel.\n"
                        "\n"
                        "For the public and any new GNUmed databases the\n"
                        "default user name and password are {any-doc, any-doc}.\n"
                        "\n"
                        "You may also need to check the PostgreSQL client\n"
                        "authentication configuration in pg_hba.conf. For\n"
                        "details see:\n"
                        "\n"
                        "wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL"
                    )
                msg = msg % e
                msg = regex.sub(r"password=[^\s]+", u"password=%s" % gmTools.u_replacement_character, msg)
                gmGuiHelpers.gm_show_error(msg, _("Connecting to backend"))
            del e
            continue

        except gmPG2.dbapi.OperationalError, exc:
            exc = gmPG2.make_pg_exception_fields_unicode(exc)
            _log.error(u"login attempt failed: %s", exc)
            msg = (
                _(
                    "Unable to connect to database:\n\n"
                    "%s\n\n"
                    "Please retry another backend / user / password combination !\n"
                    "\n"
                    " (for the public and any new GNUmed databases\n"
                    "  the default user name and password are\n"
                    "  {any-doc, any-doc})\n"
                    "\n"
                )
                % exc.u_pgerror
            )
            # 			) % gmPG2.extract_msg_from_pg_exception(e)
            msg = regex.sub(r"password=[^\s]+", u"password=%s" % gmTools.u_replacement_character, msg)
            gmGuiHelpers.gm_show_error(msg, _("Connecting to backend"))
            del exc
            continue
Exemplo n.º 8
0
def connect_to_database(login_info=None, max_attempts=3, expected_version=None, require_version=True):
    """Display the login dialog and try to log into the backend.

    - up to max_attempts times
    - returns True/False
    """
    from Gnumed.pycommon import gmPG2
    # force programmer to set a valid expected_version
    expected_hash = gmPG2.known_schema_hashes[expected_version]
    client_version = _cfg.get(option = u'client_version')
    global current_db_name
    current_db_name = u'gnumed_v%s' % expected_version

    attempt = 0

    while attempt < max_attempts:

        _log.debug('login attempt %s of %s', (attempt+1), max_attempts)

        connected = False

        login = login_info
        if login is None:
            _log.info("did not provide a login information")

        # try getting a connection to verify the DSN works
        dsn = gmPG2.make_psycopg2_dsn (
            database = login.database,
            host = login.host,
            port = login.port,
            user = login.user,
            password = login.password
        )
        try:
            #conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
            conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
            connected = True

        except gmPG2.cAuthenticationError, e:
            attempt += 1
            _log.error(u"login attempt failed: %s", e)
            if attempt < max_attempts:
                if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)):
                    msg = _(
                        'Unable to connect to database:\n\n'
                        '%s\n\n'
                        "Are you sure you have got a local database installed ?\n"
                        '\n'
                        "Please retry with proper credentials or cancel.\n"
                        '\n'
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
                    )
                else:
                    msg = _(
                        "Unable to connect to database:\n\n"
                        "%s\n\n"
                        "Please retry with proper credentials or cancel.\n"
                        "\n"
                        'You may also need to check the PostgreSQL client\n'
                        'authentication configuration in pg_hba.conf. For\n'
                        'details see:\n'
                        '\n'
                        'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
                    )
                msg = msg % e
                msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
                gmGuiHelpers.gm_show_error (
                    msg,
                    _('Connecting to backend')
                )
            del e
            continue

        except gmPG2.dbapi.OperationalError, e:
            _log.error(u"login attempt failed: %s", e)
            msg = _(
                "Unable to connect to database:\n\n"
                "%s\n\n"
                "Please retry another backend / user / password combination !\n"
            ) % gmPG2.extract_msg_from_pg_exception(e)
            msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
            gmGuiHelpers.gm_show_error (
                msg,
                _('Connecting to backend')
            )
            del e
            continue
Exemplo n.º 9
0
def connect_to_database(max_attempts=3, expected_version=None, require_version=True):
	"""Display the login dialog and try to log into the backend.

	- up to max_attempts times
	- returns True/False
	"""
	# force programmer to set a valid expected_version
	expected_hash = gmPG2.known_schema_hashes[expected_version]
	client_version = _cfg.get(option = 'client_version')
	global current_db_name
	current_db_name = 'gnumed_v%s' % expected_version

	attempt = 0

	dlg = cLoginDialog(None, -1, client_version = client_version)
	dlg.Centre(wx.BOTH)

	while attempt < max_attempts:

		_log.debug('login attempt %s of %s', (attempt+1), max_attempts)

		connected = False

		dlg.ShowModal()
		login = dlg.panel.GetLoginInfo()
		if login is None:
			_log.info("user cancelled login dialog")
			break

		gmLog2.add_word2hide(login.password)

		# try getting a connection to verify the DSN works
		dsn = gmPG2.make_psycopg2_dsn (
			database = login.database,
			host = login.host,
			port = login.port,
			user = login.user,
			password = login.password
		)
		try:
			conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
			connected = True

		except gmPG2.cAuthenticationError as e:
			attempt += 1
			_log.error("login attempt failed: %s", e)
			if attempt < max_attempts:
				if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)):
					msg = _(
						'Unable to connect to database:\n\n'
						'%s\n\n'
						"Are you sure you have got a local database installed ?\n"
						'\n'
						"Please retry with proper credentials or cancel.\n"
						'\n'
						' (for the public and any new GNUmed data-\n'
						'  bases the default user name and password\n'
						'  are {any-doc, any-doc})\n'
						'\n'
						'You may also need to check the PostgreSQL client\n'
						'authentication configuration in pg_hba.conf. For\n'
						'details see:\n'
						'\n'
						'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
					)
				else:
					msg = _(
						"Unable to connect to database:\n\n"
						"%s\n\n"
						"Please retry with proper credentials or cancel.\n"
						"\n"
						"For the public and any new GNUmed databases the\n"
						"default user name and password are {any-doc, any-doc}.\n"
						"\n"
						'You may also need to check the PostgreSQL client\n'
						'authentication configuration in pg_hba.conf. For\n'
						'details see:\n'
						'\n'
						'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
					)
				msg = msg % e
				msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg)
				gmGuiHelpers.gm_show_error (
					msg,
					_('Connecting to backend')
				)
			del e
			continue

		except gmPG2.dbapi.OperationalError as exc:
			_log.exception('login attempt failed')
			gmPG2.log_pg_exception_details(exc)
			msg = _(
				"Unable to connect to database:\n\n"
				"%s\n\n"
				"Please retry another backend / user / password combination !\n"
				"\n"
				" (for the public and any new GNUmed databases\n"
				"  the default user name and password are\n"
				"  {any-doc, any-doc})\n"
				"\n"
			) % exc
			msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg)
			gmGuiHelpers.gm_show_error(msg, _('Connecting to backend'))
			del exc
			continue

		conn.close()

		# connect was successful
		gmPG2.set_default_login(login = login)
		gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding)

		seems_bootstrapped = gmPG2.schema_exists(schema = 'gm')
		if not seems_bootstrapped:
			_log.error('schema [gm] does not exist - database not bootstrapped ?')
			msg = _(
				'The database you connected to does not seem\n'
				'to have been boostrapped properly.\n'
				'\n'
				'Make sure you have run the GNUmed database\n'
				'bootstrapper tool to create a new database.\n'
				'\n'
				'Further help can be found on the website at\n'
				'\n'
				'  http://wiki.gnumed.de\n'
				'\n'
				'or on the GNUmed mailing list.'
			)
			gmGuiHelpers.gm_show_error(msg, _('Verifying database'))
			connected = False
			break

		compatible = gmPG2.database_schema_compatible(version = expected_version)
		if compatible or not require_version:
			dlg.panel.save_state()

		if not compatible:
			connected_db_version = gmPG2.get_schema_version()
			msg = msg_generic % (
				client_version,
				connected_db_version,
				expected_version,
				gmTools.coalesce(login.host, '<localhost>'),
				login.database,
				login.user
			)
			if require_version:
				gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version'))
				connected = False
				continue
			gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version'))

		# FIXME: make configurable
		max_skew = 1		# minutes
		if _cfg.get(option = 'debug'):
			max_skew = 10
		if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)):
			if _cfg.get(option = 'debug'):
				gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings'))
			else:
				gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings'))
				connected = False
				continue

		sanity_level, message = gmPG2.sanity_check_database_settings()
		if sanity_level != 0:
			gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings'))
			if sanity_level == 2:
				connected = False
				continue

		gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
		gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)

		conn = gmPG2.get_connection(verbose = True, connection_name = 'GNUmed-[DbListenerThread]', pooled = False)
		listener = gmBackendListener.gmBackendListener(conn = conn)
		break

	dlg.DestroyLater()

	return connected