#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention Management Console
#  handles UMC requests for a specified UMC module
#
# Like what you see? Join us!
# https://www.univention.com/about-us/careers/vacancies/
#
# Copyright 2006-2023 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

import locale
import os
import os.path
import signal
import sys
from argparse import ArgumentParser

import notifier
import notifier.log as nflog
from daemon.daemon import DaemonContext

# don't import univention.management.console.{modules,protocol} here as the locale is not yet set!
from univention.lib.i18n import Locale, Translation
from univention.management.console.config import MODULE_DEBUG_LEVEL, ucr
from univention.management.console.log import MODULE, log_init, log_reopen


if __name__ == '__main__':
    if os.getuid() != 0:
        sys.stderr.write('%s must be started as root\n' % os.path.basename(sys.argv[0]))
        sys.exit(1)

    parser = ArgumentParser(usage="usage: %(prog)s [options]")
    parser.add_argument('-s', '--socket', action='store', dest='socket', help='defines the socket to bind to')
    parser.add_argument('-l', '--language', action='store', dest='language', default='C', help='defines the language to use')
    parser.add_argument('-m', '--module', action='store', dest='module', help='set the UMC daemon module to load')
    parser.add_argument('-n', '--notifier', action='store', dest='notifier', default='generic', help='defines the notifier implementation to use')

    default_debug = MODULE_DEBUG_LEVEL
    parser.add_argument('-d', '--debug', action='store', type=int, dest='debug', default=default_debug, help='if given then debugging is activated and set to the specified level [default: %(default)s]')
    parser.add_argument('-L', '--log-file', action='store', dest='logfile', default='management-console-module-%(module)s', help='specifies an alternative log file [default: %(default)s.log]')
    parser.add_argument('-f', '--foreground', action='store_true', dest='foreground', default=False, help='do not daemonize the process')

    options = parser.parse_args()

    if not options.foreground:
        daemon = DaemonContext(detach_process=False, prevent_core=False, umask=0o077, files_preserve=[x.stream.fileno() for x in nflog.instance.handlers])
        daemon.signal_map = {
            signal.SIGHUP: lambda signal, frame: log_reopen(),
        }
        daemon.open()

    # MUST be called after initializing the daemon
    if options.notifier.lower() == 'generic':
        notifier.init(notifier.GENERIC)
    elif options.notifier.lower() == 'qt':
        import PyQt4.Qt as qt
        qApp = qt.QCoreApplication(sys.argv)
        notifier.init(notifier.QT)

    # init logging
    debug_fd = log_init(options.logfile % {'module': options.module}, options.debug)

    # no notifier logging
    for handler in nflog.instance.handlers[:]:
        nflog.instance.removeHandler(handler)
    # to activate notifier logging
    # nflog.set_level(nflog.DEBUG)
    # nflog.open()

    try:
        locale_obj = Locale(options.language)
        locale.setlocale(locale.LC_MESSAGES, str(locale_obj))
        translation = Translation('univention-management-console')
        translation.set_language(options.language)
    except Exception:
        MODULE.error('The specified locale %r is not available' % (options.language,))

    # this import must be done after the locale is set!
    import univention.management.console.protocol as umcp

    if not options.socket:
        raise SystemError('socket name is missing')

    # make sure the directory where to place socket files exists
    if not os.path.exists('/run/univention-management-console'):
        os.mkdir('/run/univention-management-console')

    # get the timeout
    session_timeout = 300
    try:
        session_timeout = int(ucr.get('umc/module/timeout', 300))
    except (TypeError, ValueError):
        MODULE.warn('Failed to read module timeout from UCR variable umc/module/timeout. Using default of 300 seconds')

    try:
        with umcp.ModuleServer(options.socket, options.module, check_acls=False, timeout=session_timeout):
            notifier.loop()
    except (SystemExit, KeyboardInterrupt):
        raise
    except BaseException:
        import traceback
        MODULE.error(traceback.format_exc())
        raise
