Merge branch 'master' of git://gitorious.org/radicale/radicale
Conflicts: radicale/__init__.py
This commit is contained in:
commit
f8137315c0
9
NEWS
9
NEWS
@ -6,10 +6,17 @@
|
||||
NEWS
|
||||
------
|
||||
|
||||
0.5 - *Not released yet*
|
||||
0.6 - *Not released yet*
|
||||
========================
|
||||
|
||||
* IPv6 support
|
||||
|
||||
|
||||
0.5 - Historical Artifacts
|
||||
==========================
|
||||
|
||||
* Calendar depth
|
||||
* iPhone support
|
||||
* MacOS and Windows support
|
||||
* HEAD requests management
|
||||
* htpasswd user from calendar path
|
||||
|
7
TODO
7
TODO
@ -6,17 +6,12 @@
|
||||
TODO
|
||||
------
|
||||
|
||||
0.5
|
||||
===
|
||||
|
||||
* iCal and iPhone support
|
||||
|
||||
|
||||
0.6
|
||||
===
|
||||
|
||||
* [IN PROGRESS] Group calendars
|
||||
* [IN PROGRESS] LDAP and databases auth support
|
||||
* [IN PROGRESS] Smart, verbose and configurable logs
|
||||
* CalDAV rights
|
||||
* Read-only access for foreign users
|
||||
|
||||
|
9
config
9
config
@ -6,10 +6,11 @@
|
||||
# The current values are the default ones
|
||||
|
||||
[server]
|
||||
# CalDAV server hostname, empty for all hostnames
|
||||
host =
|
||||
# CalDAV server port
|
||||
port = 5232
|
||||
# CalDAV server hostnames separated by a comma
|
||||
# IPv4 syntax: address:port
|
||||
# IPv6 syntax: [address]:port
|
||||
# IPv6 adresses are configured to only allow IPv6 connections
|
||||
hosts = 0.0.0.0:5232
|
||||
# Daemon flag
|
||||
daemon = False
|
||||
# SSL flag, enable HTTPS protocol
|
||||
|
78
radicale.py
78
radicale.py
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Radicale Server - Calendar Server
|
||||
@ -26,10 +26,9 @@
|
||||
# pylint: disable-msg=W0406
|
||||
|
||||
"""
|
||||
Radicale Server entry point.
|
||||
Radicale CalDAV Server.
|
||||
|
||||
Launch the Radicale Server according to configuration and command-line
|
||||
arguments.
|
||||
Launch the server according to configuration and command-line options.
|
||||
|
||||
"""
|
||||
|
||||
@ -38,15 +37,13 @@ arguments.
|
||||
import os
|
||||
import sys
|
||||
import optparse
|
||||
import signal
|
||||
import threading
|
||||
|
||||
import radicale
|
||||
|
||||
# Get command-line options
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option(
|
||||
"-v", "--version", action="store_true",
|
||||
default=False,
|
||||
help="show version and exit")
|
||||
parser = optparse.OptionParser(version=radicale.VERSION)
|
||||
parser.add_option(
|
||||
"-d", "--daemon", action="store_true",
|
||||
default=radicale.config.getboolean("server", "daemon"),
|
||||
@ -55,13 +52,9 @@ parser.add_option(
|
||||
"-f", "--foreground", action="store_false", dest="daemon",
|
||||
help="launch in foreground (opposite of --daemon)")
|
||||
parser.add_option(
|
||||
"-H", "--host",
|
||||
default=radicale.config.get("server", "host"),
|
||||
help="set server hostname")
|
||||
parser.add_option(
|
||||
"-p", "--port", type="int",
|
||||
default=radicale.config.getint("server", "port"),
|
||||
help="set server port")
|
||||
"-H", "--hosts",
|
||||
default=radicale.config.get("server", "hosts"),
|
||||
help="set server hostnames and ports")
|
||||
parser.add_option(
|
||||
"-s", "--ssl", action="store_true",
|
||||
default=radicale.config.getboolean("server", "ssl"),
|
||||
@ -72,11 +65,11 @@ parser.add_option(
|
||||
parser.add_option(
|
||||
"-k", "--key",
|
||||
default=radicale.config.get("server", "key"),
|
||||
help="private key file ")
|
||||
help="set private key file")
|
||||
parser.add_option(
|
||||
"-c", "--certificate",
|
||||
default=radicale.config.get("server", "certificate"),
|
||||
help="certificate file ")
|
||||
help="set certificate file")
|
||||
options = parser.parse_args()[0]
|
||||
|
||||
# Update Radicale configuration according to options
|
||||
@ -86,19 +79,52 @@ for option in parser.option_list:
|
||||
value = getattr(options, key)
|
||||
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
|
||||
if options.daemon:
|
||||
if os.fork():
|
||||
sys.exit()
|
||||
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 = server_class(
|
||||
(options.host, options.port), radicale.CalendarHTTPHandler)
|
||||
shutdown_program = threading.Event()
|
||||
|
||||
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()
|
||||
|
@ -88,10 +88,26 @@ class HTTPServer(server.HTTPServer):
|
||||
|
||||
# Maybe a Pylint bug, ``__init__`` calls ``server.HTTPServer.__init__``
|
||||
# pylint: disable=W0231
|
||||
def __init__(self, address, handler):
|
||||
def __init__(self, address, handler, bind_and_activate=True):
|
||||
"""Create server."""
|
||||
log.log(10, "Create HTTP server.")
|
||||
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()
|
||||
# pylint: enable=W0231
|
||||
|
||||
@ -100,7 +116,7 @@ class HTTPSServer(HTTPServer):
|
||||
"""HTTPS server."""
|
||||
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."""
|
||||
log.log(10, "Create server by wrapping HTTP socket in an SSL socket.")
|
||||
# Fails with Python 2.5, import if needed
|
||||
@ -108,13 +124,15 @@ class HTTPSServer(HTTPServer):
|
||||
import ssl
|
||||
# pylint: enable=F0401
|
||||
|
||||
HTTPServer.__init__(self, address, handler)
|
||||
HTTPServer.__init__(self, address, handler, False)
|
||||
self.socket = ssl.wrap_socket(
|
||||
socket.socket(self.address_family, self.socket_type),
|
||||
self.socket,
|
||||
server_side=True,
|
||||
certfile=config.get("server", "certificate"),
|
||||
keyfile=config.get("server", "key"),
|
||||
ssl_version=ssl.PROTOCOL_SSLv23)
|
||||
|
||||
if bind_and_activate:
|
||||
self.server_bind()
|
||||
self.server_activate()
|
||||
|
||||
|
@ -39,8 +39,7 @@ except ImportError:
|
||||
# Default configuration
|
||||
INITIAL_CONFIG = {
|
||||
"server": {
|
||||
"host": "",
|
||||
"port": "5232",
|
||||
"hosts": "0.0.0.0:5232",
|
||||
"daemon": "False",
|
||||
"ssl": "False",
|
||||
"certificate": "/etc/apache2/ssl/server.crt",
|
||||
|
5
setup.py
5
setup.py
@ -27,8 +27,8 @@ it requires few software dependances and is pre-configured to work
|
||||
out-of-the-box.
|
||||
|
||||
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+
|
||||
and Sunbird 0.9+. It is free and open-source software, released under GPL
|
||||
MacOS X) and Windows. It is known to work with Evolution, Lightning, iPhone
|
||||
and Android clients. It is free and open-source software, released under GPL
|
||||
version 3.
|
||||
|
||||
For further information, please visit the `Radicale Website
|
||||
@ -91,4 +91,5 @@ setup(
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.0",
|
||||
"Programming Language :: Python :: 3.1",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
"Topic :: Office/Business :: Groupware"])
|
||||
|
Loading…
Reference in New Issue
Block a user