Merge branch 'master' of git://gitorious.org/radicale/radicale

Conflicts:
	radicale/__init__.py
This commit is contained in:
Corentin Le Bail 2011-04-10 09:35:01 +02:00
commit f8137315c0
7 changed files with 95 additions and 48 deletions

9
NEWS
View File

@ -6,10 +6,17 @@
NEWS NEWS
------ ------
0.5 - *Not released yet* 0.6 - *Not released yet*
======================== ========================
* IPv6 support
0.5 - Historical Artifacts
==========================
* Calendar depth * Calendar depth
* iPhone support
* MacOS and Windows support * MacOS and Windows support
* HEAD requests management * HEAD requests management
* htpasswd user from calendar path * htpasswd user from calendar path

7
TODO
View File

@ -6,17 +6,12 @@
TODO TODO
------ ------
0.5
===
* iCal and iPhone support
0.6 0.6
=== ===
* [IN PROGRESS] Group calendars * [IN PROGRESS] Group calendars
* [IN PROGRESS] LDAP and databases auth support * [IN PROGRESS] LDAP and databases auth support
* [IN PROGRESS] Smart, verbose and configurable logs
* CalDAV rights * CalDAV rights
* Read-only access for foreign users * Read-only access for foreign users

9
config
View File

@ -6,10 +6,11 @@
# The current values are the default ones # The current values are the default ones
[server] [server]
# CalDAV server hostname, empty for all hostnames # CalDAV server hostnames separated by a comma
host = # IPv4 syntax: address:port
# CalDAV server port # IPv6 syntax: [address]:port
port = 5232 # IPv6 adresses are configured to only allow IPv6 connections
hosts = 0.0.0.0:5232
# Daemon flag # Daemon flag
daemon = False daemon = False
# SSL flag, enable HTTPS protocol # SSL flag, enable HTTPS protocol

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# This file is part of Radicale Server - Calendar Server # This file is part of Radicale Server - Calendar Server
@ -26,10 +26,9 @@
# pylint: disable-msg=W0406 # pylint: disable-msg=W0406
""" """
Radicale Server entry point. Radicale CalDAV Server.
Launch the Radicale Server according to configuration and command-line Launch the server according to configuration and command-line options.
arguments.
""" """
@ -38,15 +37,13 @@ arguments.
import os import os
import sys import sys
import optparse import optparse
import signal
import threading
import radicale import radicale
# Get command-line options # Get command-line options
parser = optparse.OptionParser() parser = optparse.OptionParser(version=radicale.VERSION)
parser.add_option(
"-v", "--version", action="store_true",
default=False,
help="show version and exit")
parser.add_option( parser.add_option(
"-d", "--daemon", action="store_true", "-d", "--daemon", action="store_true",
default=radicale.config.getboolean("server", "daemon"), default=radicale.config.getboolean("server", "daemon"),
@ -55,13 +52,9 @@ parser.add_option(
"-f", "--foreground", action="store_false", dest="daemon", "-f", "--foreground", action="store_false", dest="daemon",
help="launch in foreground (opposite of --daemon)") help="launch in foreground (opposite of --daemon)")
parser.add_option( parser.add_option(
"-H", "--host", "-H", "--hosts",
default=radicale.config.get("server", "host"), default=radicale.config.get("server", "hosts"),
help="set server hostname") help="set server hostnames and ports")
parser.add_option(
"-p", "--port", type="int",
default=radicale.config.getint("server", "port"),
help="set server port")
parser.add_option( parser.add_option(
"-s", "--ssl", action="store_true", "-s", "--ssl", action="store_true",
default=radicale.config.getboolean("server", "ssl"), default=radicale.config.getboolean("server", "ssl"),
@ -72,11 +65,11 @@ parser.add_option(
parser.add_option( parser.add_option(
"-k", "--key", "-k", "--key",
default=radicale.config.get("server", "key"), default=radicale.config.get("server", "key"),
help="private key file ") help="set private key file")
parser.add_option( parser.add_option(
"-c", "--certificate", "-c", "--certificate",
default=radicale.config.get("server", "certificate"), default=radicale.config.get("server", "certificate"),
help="certificate file ") help="set certificate file")
options = parser.parse_args()[0] options = parser.parse_args()[0]
# Update Radicale configuration according to options # Update Radicale configuration according to options
@ -86,19 +79,52 @@ for option in parser.option_list:
value = getattr(options, key) value = getattr(options, key)
radicale.config.set("server", key, value) radicale.config.set("server", key, value)
# Print version and exit if the option is given
if options.version:
print(radicale.VERSION)
sys.exit()
# Fork if Radicale is launched as daemon # Fork if Radicale is launched as daemon
if options.daemon: if options.daemon:
if os.fork(): if os.fork():
sys.exit() sys.exit()
sys.stdout = sys.stderr = open(os.devnull, "w") sys.stdout = sys.stderr = open(os.devnull, "w")
# Launch calendar server # Create calendar servers
servers = []
server_class = radicale.HTTPSServer if options.ssl else radicale.HTTPServer server_class = radicale.HTTPSServer if options.ssl else radicale.HTTPServer
server = server_class( shutdown_program = threading.Event()
(options.host, options.port), radicale.CalendarHTTPHandler)
server.serve_forever() for host in options.hosts.split(','):
address, port = host.strip().rsplit(':', 1)
address, port = address.strip('[] '), int(port)
servers.append(server_class((address, port), radicale.CalendarHTTPHandler))
# SIGTERM and SIGINT (aka KeyboardInterrupt) should just mark this for shutdown
signal.signal(signal.SIGTERM, lambda *_: shutdown_program.set())
signal.signal(signal.SIGINT, lambda *_: shutdown_program.set())
def serve_forever(server):
"""Serve a server forever, cleanly shutdown when things go wrong."""
try:
server.serve_forever()
finally:
shutdown_program.set()
# Start the servers in a different loop to avoid possible race-conditions, when
# a server exists but another server is added to the list at the same time
for server in servers:
threading.Thread(target=serve_forever, args=(server,)).start()
# Main loop: wait until all servers are exited
try:
# We must do the busy-waiting here, as all ``.join()`` calls completly
# block the thread, such that signals are not received
while True:
# The number is irrelevant, it only needs to be greater than 0.05 due
# to python implementing its own busy-waiting logic
shutdown_program.wait(5.0)
if shutdown_program.is_set():
break
finally:
# Ignore signals, so that they cannot interfere
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
for server in servers:
server.shutdown()

View File

@ -88,10 +88,26 @@ class HTTPServer(server.HTTPServer):
# Maybe a Pylint bug, ``__init__`` calls ``server.HTTPServer.__init__`` # Maybe a Pylint bug, ``__init__`` calls ``server.HTTPServer.__init__``
# pylint: disable=W0231 # pylint: disable=W0231
def __init__(self, address, handler): def __init__(self, address, handler, bind_and_activate=True):
"""Create server.""" """Create server."""
log.log(10, "Create HTTP server.") log.log(10, "Create HTTP server.")
server.HTTPServer.__init__(self, address, handler) server.HTTPServer.__init__(self, address, handler)
ipv6 = ":" in address[0]
if ipv6:
self.address_family = socket.AF_INET6
# Do not bind and activate, as we might change socketopts
server.HTTPServer.__init__(self, address, handler, False)
if ipv6:
# Only allow IPv6 connections to the IPv6 socket
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
if bind_and_activate:
self.server_bind()
self.server_activate()
self.acl = acl.load() self.acl = acl.load()
# pylint: enable=W0231 # pylint: enable=W0231
@ -100,7 +116,7 @@ class HTTPSServer(HTTPServer):
"""HTTPS server.""" """HTTPS server."""
PROTOCOL = "https" PROTOCOL = "https"
def __init__(self, address, handler): def __init__(self, address, handler, bind_and_activate=True):
"""Create server by wrapping HTTP socket in an SSL socket.""" """Create server by wrapping HTTP socket in an SSL socket."""
log.log(10, "Create server by wrapping HTTP socket in an SSL socket.") log.log(10, "Create server by wrapping HTTP socket in an SSL socket.")
# Fails with Python 2.5, import if needed # Fails with Python 2.5, import if needed
@ -108,13 +124,15 @@ class HTTPSServer(HTTPServer):
import ssl import ssl
# pylint: enable=F0401 # pylint: enable=F0401
HTTPServer.__init__(self, address, handler) HTTPServer.__init__(self, address, handler, False)
self.socket = ssl.wrap_socket( self.socket = ssl.wrap_socket(
socket.socket(self.address_family, self.socket_type), self.socket,
server_side=True, server_side=True,
certfile=config.get("server", "certificate"), certfile=config.get("server", "certificate"),
keyfile=config.get("server", "key"), keyfile=config.get("server", "key"),
ssl_version=ssl.PROTOCOL_SSLv23) ssl_version=ssl.PROTOCOL_SSLv23)
if bind_and_activate:
self.server_bind() self.server_bind()
self.server_activate() self.server_activate()

View File

@ -39,8 +39,7 @@ except ImportError:
# Default configuration # Default configuration
INITIAL_CONFIG = { INITIAL_CONFIG = {
"server": { "server": {
"host": "", "hosts": "0.0.0.0:5232",
"port": "5232",
"daemon": "False", "daemon": "False",
"ssl": "False", "ssl": "False",
"certificate": "/etc/apache2/ssl/server.crt", "certificate": "/etc/apache2/ssl/server.crt",

View File

@ -27,8 +27,8 @@ it requires few software dependances and is pre-configured to work
out-of-the-box. out-of-the-box.
The Radicale Project runs on most of the UNIX-like platforms (Linux, BSD, The Radicale Project runs on most of the UNIX-like platforms (Linux, BSD,
MacOS X) and Windows. It is known to work with Evolution 2.30+, Lightning 0.9+ MacOS X) and Windows. It is known to work with Evolution, Lightning, iPhone
and Sunbird 0.9+. It is free and open-source software, released under GPL and Android clients. It is free and open-source software, released under GPL
version 3. version 3.
For further information, please visit the `Radicale Website For further information, please visit the `Radicale Website
@ -91,4 +91,5 @@ setup(
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.0", "Programming Language :: Python :: 3.0",
"Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.1",
"Programming Language :: Python :: 3.2",
"Topic :: Office/Business :: Groupware"]) "Topic :: Office/Business :: Groupware"])