Merge branch 'master' of git://gitorious.org/radicale/radicale
Conflicts: radicale/__init__.py
This commit is contained in:
commit
08b145e5ca
9
NEWS
9
NEWS
@ -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
7
TODO
@ -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
9
config
@ -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
|
||||||
|
68
radicale.py
68
radicale.py
@ -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,42 @@ 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
|
# Launch 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(
|
|
||||||
(options.host, options.port), radicale.CalendarHTTPHandler)
|
def exit():
|
||||||
|
"""Cleanly shutdown servers."""
|
||||||
|
while servers:
|
||||||
|
servers.pop().shutdown()
|
||||||
|
|
||||||
|
def serve_forever(server):
|
||||||
|
"""Serve a server forever with no traceback on keyboard interrupts."""
|
||||||
|
try:
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
# No unwanted traceback
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
exit()
|
||||||
|
|
||||||
|
# Clean exit on SIGTERM
|
||||||
|
signal.signal(signal.SIGTERM, lambda *_: exit())
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
for server in servers[:-1]:
|
||||||
|
# More servers to come, launch a new thread
|
||||||
|
threading.Thread(target=serve_forever, args=(server,)).start()
|
||||||
|
|
||||||
|
# Last server, no more thread
|
||||||
|
serve_forever(servers[-1])
|
||||||
|
@ -88,10 +88,25 @@ 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)
|
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 +115,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 +123,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()
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
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.
|
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"])
|
||||||
|
Loading…
Reference in New Issue
Block a user