#!/usr/bin/python2

import os
import os.path
import sys
import signal
import getopt
import pyzor
import pyzor.server
import ConfigParser

_author__   = pyzor.__author__
__version__  = pyzor.__version__
__revision__ = "$Id: pyzord,v 1.20 2002-09-08 03:33:44 ftobin Exp $"

default_anonymous_allows = map(pyzor.Opname, ['check', 'report', 'ping',
                                              'info'])

def cleanup_server_handler(signum, frame):
    pyzor.server.DBHandle().cleanup()

def reopen_log_handler(signum, frame):
    server.replace_log(pyzor.server.Log(open(log_fn, 'a')))


def usage():
    sys.stderr.write("usage: %s [-d] [--homedir dir]\n" % sys.argv[0])
    sys.exit(1)


def load_access_file(access_fn, server):
    server.acl = pyzor.server.ACL()
    if os.path.exists(access_fn):
        pyzor.server.AccessFile(open(access_fn)).feed_into(server.acl)
    else:
        output.warn("%s does not exist; using default ACL; allowing anonymous to do %s"
                    % (access_fn, default_anonymous_allows))
        for op in default_anonymous_allows:
            server.acl.add_entry(pyzor.server.ACLEntry((pyzor.anonymous_user,
                                                        op,
                                                        True)))

                                 
def load_passwd_file(access_fn, server):
    server.passwd = pyzor.server.Passwd()
    if os.path.exists(passwd_fn):
        for user, key in pyzor.server.PasswdFile(open(passwd_fn)):
            server.passwd[user] = key


########################################################################
# functions above, run below

debug = 0
(options, args) = getopt.getopt(sys.argv[1:], 'dh:', ['homedir='])
if len(args) != 0:
    usage()

specified_homedir = None

for (o, v) in options:
    if o == '-d':
        debug = 1
    elif o == '-h':
        usage()
    elif o == '--homedir':
        specified_homedir = v

homedir = pyzor.get_homedir(specified_homedir)

if not os.path.exists(homedir):
    os.mkdir(homedir)

defaults = {'port':          '24441',
            'listenaddress': '0.0.0.0',
            'logfile':       'pyzord.log',
            'pidfile':       'pyzord.pid',
            'digestdb':      'pyzord.db',
            'passwdfile':    'pyzord.passwd',
            'accessfile':    'pyzord.access',
            'CleanupAge':    "%d" % pyzor.server.DBHandle.max_age,
            }

config = pyzor.Config(homedir)
config.add_section('server')

for k, v in defaults.items():
    config.set('server', k, v)

config.read(os.path.join(homedir, 'config'))

port       = config.getint('server', 'port')
listen_adr = config.get('server', 'ListenAddress')

log_fn    = config.get_filename('server', 'logfile')
pid_fn    = config.get_filename('server', 'pidfile')
dbfile    = config.get_filename('server', 'DigestDB')
passwd_fn = config.get_filename('server', 'passwdfile')
access_fn = config.get_filename('server', 'accessfile')
pyzor.server.DBHandle.max_age = config.getint('server', 'CleanupAge')

output = pyzor.Output(debug=debug)

logfile = open(log_fn, 'a')
pyzor.server.DBHandle.initialize(dbfile, 'c')

server = pyzor.server.Server((listen_adr, port),
                             pyzor.server.Log(logfile))


load_passwd_file(passwd_fn, server)
load_access_file(access_fn, server)

if not debug:
    # This step is required so that the new process is guaranteed
    # not to be a process group leader. The next step, setsid(),
    # fails if you're a process group leader.
    pid = os.fork()
    if pid != 0:
        os._exit(0)

    # setsid() to become a process group and session group leader.
    # Since a controlling terminal is associated with a session,
    # and this new session has not yet acquired a controlling
    # terminal our process now has no controlling terminal,
    # which is a Good Thing for daemons.
    os.setsid()
        
    pid = os.fork()
    if pid != 0:
        os._exit(0)

    sys.stdin  = sys.__stdin__  = open('/dev/null')
    sys.stdout = sys.__stdout__ = open('/dev/null', 'a')
    #sys.stderr = sys.__stderr__ = open('/dev/null', 'a')

if pid_fn is not None:
    f = open(pid_fn, 'w')
    f.write("%d\n" % os.getpid())
    f.close()

# we shouldn't chdir because that prevents the re-opening
# of logfiles and the database if they are relative paths
##os.chdir("/")

signal.signal(signal.SIGUSR1, cleanup_server_handler)
signal.signal(signal.SIGHUP,  reopen_log_handler)
server.serve_forever()
