Python 3 support and minor fixes.
This commit is contained in:
parent
4a0d3936e8
commit
4ee09cf817
@ -30,13 +30,10 @@ Radicale Server entry point.
|
|||||||
Launch the Radicale Serve according to the configuration.
|
Launch the Radicale Serve according to the configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
import BaseHTTPServer
|
|
||||||
|
|
||||||
import radicale
|
import radicale
|
||||||
|
|
||||||
if radicale.config.get("server", "type") == "http":
|
if radicale.config.get("server", "type") == "http":
|
||||||
server = BaseHTTPServer.HTTPServer(
|
server = radicale.server.HTTPServer(
|
||||||
("", radicale.config.getint("server", "port")),
|
("", radicale.config.getint("server", "port")),
|
||||||
radicale.CalendarHandler)
|
radicale.CalendarHandler)
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
|
@ -21,25 +21,21 @@
|
|||||||
# TODO: Manage errors (see xmlutils)
|
# TODO: Manage errors (see xmlutils)
|
||||||
|
|
||||||
import posixpath
|
import posixpath
|
||||||
import httplib
|
try:
|
||||||
import BaseHTTPServer
|
from http import client, server
|
||||||
|
except ImportError:
|
||||||
|
import httplib as client
|
||||||
|
import BaseHTTPServer as server
|
||||||
|
|
||||||
import config
|
from radicale import config, support, xmlutils
|
||||||
import support
|
|
||||||
import acl
|
|
||||||
import xmlutils
|
|
||||||
import calendar
|
|
||||||
|
|
||||||
_users = acl.users()
|
class CalendarHandler(server.BaseHTTPRequestHandler):
|
||||||
_calendars = support.calendars()
|
|
||||||
|
|
||||||
class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
||||||
"""HTTP requests handler for calendars."""
|
"""HTTP requests handler for calendars."""
|
||||||
def _parse_path(self):
|
def _parse_path(self):
|
||||||
path = self.path.strip("/").split("/")
|
path = self.path.strip("/").split("/")
|
||||||
if len(path) >= 2:
|
if len(path) >= 2:
|
||||||
cal = "%s/%s" % (path[0], path[1])
|
cal = "%s/%s" % (path[0], path[1])
|
||||||
self.calendar = calendar.Calendar(_users[0], cal)
|
self.calendar = calendar.Calendar("radicale", cal)
|
||||||
|
|
||||||
def do_DELETE(self):
|
def do_DELETE(self):
|
||||||
"""Manage DELETE ``request``."""
|
"""Manage DELETE ``request``."""
|
||||||
@ -47,14 +43,14 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
obj = self.headers.get("if-match", None)
|
obj = self.headers.get("if-match", None)
|
||||||
answer = xmlutils.delete(obj, self.calendar, self.path)
|
answer = xmlutils.delete(obj, self.calendar, self.path)
|
||||||
|
|
||||||
self.send_response(httplib.NO_CONTENT)
|
self.send_response(client.NO_CONTENT)
|
||||||
self.send_header("Content-Length", len(answer))
|
self.send_header("Content-Length", len(answer))
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(answer)
|
self.wfile.write(answer)
|
||||||
|
|
||||||
def do_OPTIONS(self):
|
def do_OPTIONS(self):
|
||||||
"""Manage OPTIONS ``request``."""
|
"""Manage OPTIONS ``request``."""
|
||||||
self.send_response(httplib.OK)
|
self.send_response(client.OK)
|
||||||
self.send_header("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
|
self.send_header("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
|
||||||
self.send_header("DAV", "1, calendar-access")
|
self.send_header("DAV", "1, calendar-access")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@ -65,7 +61,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
xml_request = self.rfile.read(int(self.headers["Content-Length"]))
|
xml_request = self.rfile.read(int(self.headers["Content-Length"]))
|
||||||
answer = xmlutils.propfind(xml_request, self.calendar, self.path)
|
answer = xmlutils.propfind(xml_request, self.calendar, self.path)
|
||||||
|
|
||||||
self.send_response(httplib.MULTI_STATUS)
|
self.send_response(client.MULTI_STATUS)
|
||||||
self.send_header("DAV", "1, calendar-access")
|
self.send_header("DAV", "1, calendar-access")
|
||||||
self.send_header("Content-Length", len(answer))
|
self.send_header("Content-Length", len(answer))
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@ -84,7 +80,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
obj = self.headers.get("if-match", None)
|
obj = self.headers.get("if-match", None)
|
||||||
xmlutils.put(ical_request, self.calendar, self.path, obj)
|
xmlutils.put(ical_request, self.calendar, self.path, obj)
|
||||||
|
|
||||||
self.send_response(httplib.CREATED)
|
self.send_response(client.CREATED)
|
||||||
|
|
||||||
def do_REPORT(self):
|
def do_REPORT(self):
|
||||||
"""Manage REPORT ``request``."""
|
"""Manage REPORT ``request``."""
|
||||||
@ -92,7 +88,7 @@ class CalendarHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
xml_request = self.rfile.read(int(self.headers["Content-Length"]))
|
xml_request = self.rfile.read(int(self.headers["Content-Length"]))
|
||||||
answer = xmlutils.report(xml_request, self.calendar, self.path)
|
answer = xmlutils.report(xml_request, self.calendar, self.path)
|
||||||
|
|
||||||
self.send_response(httplib.MULTI_STATUS)
|
self.send_response(client.MULTI_STATUS)
|
||||||
self.send_header("Content-Length", len(answer))
|
self.send_header("Content-Length", len(answer))
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(answer)
|
self.wfile.write(answer)
|
||||||
|
@ -25,7 +25,7 @@ This module loads a list of users with access rights, according to the acl
|
|||||||
configuration.
|
configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .. import config
|
from radicale import config
|
||||||
|
|
||||||
_acl = __import__(config.get("acl", "type"), locals(), globals())
|
_acl = __import__(config.get("acl", "type"), locals(), globals())
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ Fake ACL.
|
|||||||
Just load the default user set in configuration, with no rights management.
|
Just load the default user set in configuration, with no rights management.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .. import config
|
from radicale import config
|
||||||
|
|
||||||
def users():
|
def users():
|
||||||
"""Get the list of all users."""
|
"""Get the list of all users."""
|
||||||
|
@ -26,7 +26,7 @@ Load the list of users according to the htpasswd configuration.
|
|||||||
|
|
||||||
# TODO: Manage rights
|
# TODO: Manage rights
|
||||||
|
|
||||||
from .. import config
|
from radicale import config
|
||||||
|
|
||||||
def users():
|
def users():
|
||||||
"""Get the list of all users."""
|
"""Get the list of all users."""
|
||||||
|
@ -24,7 +24,7 @@ Radicale calendar classes.
|
|||||||
Define the main classes of a calendar as seen from the server.
|
Define the main classes of a calendar as seen from the server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import support
|
from radicale import support
|
||||||
|
|
||||||
hash_tag = lambda vcalendar: str(hash(vcalendar))
|
hash_tag = lambda vcalendar: str(hash(vcalendar))
|
||||||
|
|
||||||
@ -33,8 +33,9 @@ class Calendar(object):
|
|||||||
def __init__(self, user, cal):
|
def __init__(self, user, cal):
|
||||||
"""Initialize the calendar with ``cal`` and ``user`` parameters."""
|
"""Initialize the calendar with ``cal`` and ``user`` parameters."""
|
||||||
# TODO: Use properties from the calendar configuration
|
# TODO: Use properties from the calendar configuration
|
||||||
|
self.support = support.load()
|
||||||
self.encoding = "utf-8"
|
self.encoding = "utf-8"
|
||||||
self.owner = "lize"
|
self.owner = "radicale"
|
||||||
self.user = user
|
self.user = user
|
||||||
self.cal = cal
|
self.cal = cal
|
||||||
self.version = "2.0"
|
self.version = "2.0"
|
||||||
@ -43,22 +44,22 @@ class Calendar(object):
|
|||||||
def append(self, vcalendar):
|
def append(self, vcalendar):
|
||||||
"""Append vcalendar to the calendar."""
|
"""Append vcalendar to the calendar."""
|
||||||
self.ctag = hash_tag(self.vcalendar())
|
self.ctag = hash_tag(self.vcalendar())
|
||||||
support.append(self.cal, vcalendar)
|
self.support.append(self.cal, vcalendar)
|
||||||
|
|
||||||
def remove(self, uid):
|
def remove(self, uid):
|
||||||
"""Remove object named ``uid`` from the calendar."""
|
"""Remove object named ``uid`` from the calendar."""
|
||||||
self.ctag = hash_tag(self.vcalendar())
|
self.ctag = hash_tag(self.vcalendar())
|
||||||
support.remove(self.cal, uid)
|
self.support.remove(self.cal, uid)
|
||||||
|
|
||||||
def replace(self, uid, vcalendar):
|
def replace(self, uid, vcalendar):
|
||||||
"""Replace objet named ``uid`` by ``vcalendar`` in the calendar."""
|
"""Replace objet named ``uid`` by ``vcalendar`` in the calendar."""
|
||||||
self.ctag = hash_tag(self.vcalendar())
|
self.ctag = hash_tag(self.vcalendar())
|
||||||
support.remove(self.cal, uid)
|
self.support.remove(self.cal, uid)
|
||||||
support.append(self.cal, vcalendar)
|
self.support.append(self.cal, vcalendar)
|
||||||
|
|
||||||
def vcalendar(self):
|
def vcalendar(self):
|
||||||
"""Return unicode calendar from the calendar."""
|
"""Return unicode calendar from the calendar."""
|
||||||
return unicode(support.read(self.cal), self.encoding)
|
return self.support.read(self.cal)
|
||||||
|
|
||||||
def etag(self):
|
def etag(self):
|
||||||
"""Return etag from calendar."""
|
"""Return etag from calendar."""
|
||||||
|
@ -24,7 +24,10 @@ Radicale configuration module.
|
|||||||
Give a configparser-like interface to read and write configuration.
|
Give a configparser-like interface to read and write configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ConfigParser import RawConfigParser as ConfigParser
|
try:
|
||||||
|
from configparser import RawConfigParser as ConfigParser
|
||||||
|
except ImportError:
|
||||||
|
from ConfigParser import RawConfigParser as ConfigParser
|
||||||
|
|
||||||
_config = ConfigParser()
|
_config = ConfigParser()
|
||||||
get = _config.get
|
get = _config.get
|
||||||
@ -68,9 +71,9 @@ _initial = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for section, values in _initial.iteritems():
|
for section, values in _initial.items():
|
||||||
_config.add_section(section)
|
_config.add_section(section)
|
||||||
for key, value in values.iteritems():
|
for key, value in values.items():
|
||||||
_config.set(section, key, value)
|
_config.set(section, key, value)
|
||||||
|
|
||||||
# TODO: Use abstract filename for other platforms
|
# TODO: Use abstract filename for other platforms
|
||||||
|
@ -24,7 +24,7 @@ iCal parsing functions.
|
|||||||
|
|
||||||
# TODO: Manage filters (see xmlutils)
|
# TODO: Manage filters (see xmlutils)
|
||||||
|
|
||||||
import calendar
|
from radicale import calendar
|
||||||
|
|
||||||
def write_calendar(headers=[
|
def write_calendar(headers=[
|
||||||
calendar.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"),
|
calendar.Header("PRODID:-//Radicale//NONSGML Radicale Server//EN"),
|
||||||
@ -32,14 +32,14 @@ def write_calendar(headers=[
|
|||||||
timezones=[], todos=[], events=[]):
|
timezones=[], todos=[], events=[]):
|
||||||
"""Create calendar from ``headers``, ``timezones``, ``todos``, ``events``."""
|
"""Create calendar from ``headers``, ``timezones``, ``todos``, ``events``."""
|
||||||
# TODO: Manage encoding and EOL
|
# TODO: Manage encoding and EOL
|
||||||
cal = u"\n".join((
|
cal = "\n".join((
|
||||||
u"BEGIN:VCALENDAR",
|
"BEGIN:VCALENDAR",
|
||||||
u"\n".join([header.text for header in headers]),
|
"\n".join([header.text for header in headers]),
|
||||||
u"\n".join([timezone.text for timezone in timezones]),
|
"\n".join([timezone.text for timezone in timezones]),
|
||||||
u"\n".join([todo.text for todo in todos]),
|
"\n".join([todo.text for todo in todos]),
|
||||||
u"\n".join([event.text for event in events]),
|
"\n".join([event.text for event in events]),
|
||||||
u"END:VCALENDAR"))
|
"END:VCALENDAR"))
|
||||||
return u"\n".join([line for line in cal.splitlines() if line])
|
return "\n".join([line for line in cal.splitlines() if line])
|
||||||
|
|
||||||
def headers(vcalendar):
|
def headers(vcalendar):
|
||||||
"""Find Headers items in ``vcalendar``."""
|
"""Find Headers items in ``vcalendar``."""
|
||||||
|
@ -22,12 +22,9 @@
|
|||||||
Calendar storage support configuration.
|
Calendar storage support configuration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .. import config
|
from radicale import config
|
||||||
|
|
||||||
_support = __import__(config.get("support", "type"), locals(), globals())
|
def load():
|
||||||
|
module = __import__("radicale.support", globals(), locals(),
|
||||||
append = _support.append
|
[config.get("support", "type")])
|
||||||
calendars =_support.calendars
|
return getattr(module, config.get("support", "type"))
|
||||||
mkcalendar =_support.mkcalendar
|
|
||||||
read = _support.read
|
|
||||||
remove = _support.remove
|
|
||||||
|
@ -24,12 +24,15 @@ Plain text storage.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
|
import codecs
|
||||||
|
|
||||||
from .. import ical
|
from radicale import config, ical
|
||||||
from .. import config
|
|
||||||
|
|
||||||
_folder = os.path.expanduser(config.get("support", "folder"))
|
_folder = os.path.expanduser(config.get("support", "folder"))
|
||||||
|
|
||||||
|
def _open(path, mode="r"):
|
||||||
|
return codecs.open(path, mode, config.get("encoding", "stock"))
|
||||||
|
|
||||||
def calendars():
|
def calendars():
|
||||||
"""List available calendars paths."""
|
"""List available calendars paths."""
|
||||||
calendars = []
|
calendars = []
|
||||||
@ -45,17 +48,17 @@ def mkcalendar(name):
|
|||||||
user, cal = name.split(posixpath.sep)
|
user, cal = name.split(posixpath.sep)
|
||||||
if not os.path.exists(os.path.join(_folder, user)):
|
if not os.path.exists(os.path.join(_folder, user)):
|
||||||
os.makedirs(os.path.join(_folder, user))
|
os.makedirs(os.path.join(_folder, user))
|
||||||
fd = open(os.path.join(_folder, user, cal), "w")
|
fd = _open(os.path.join(_folder, user, cal), "w")
|
||||||
fd.write(ical.write_calendar().encode(config.get("encoding", "stock")))
|
fd.write(ical.write_calendar())
|
||||||
|
|
||||||
def read(cal):
|
def read(cal):
|
||||||
"""Read calendar ``cal``."""
|
"""Read calendar ``cal``."""
|
||||||
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
||||||
return open(path).read()
|
return _open(path).read()
|
||||||
|
|
||||||
def append(cal, vcalendar):
|
def append(cal, vcalendar):
|
||||||
"""Append ``vcalendar`` to ``cal``."""
|
"""Append ``vcalendar`` to ``cal``."""
|
||||||
old_calendar = unicode(read(cal), config.get("encoding", "stock"))
|
old_calendar = read(cal)
|
||||||
old_tzs = [tz.tzid for tz in ical.timezones(old_calendar)]
|
old_tzs = [tz.tzid for tz in ical.timezones(old_calendar)]
|
||||||
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
||||||
|
|
||||||
@ -69,29 +72,29 @@ def append(cal, vcalendar):
|
|||||||
|
|
||||||
for tz in ical.timezones(vcalendar):
|
for tz in ical.timezones(vcalendar):
|
||||||
if tz.tzid not in old_tzs:
|
if tz.tzid not in old_tzs:
|
||||||
# TODO: Manage position, encoding and EOL
|
# TODO: Manage position and EOL
|
||||||
fd = open(path)
|
fd = _open(path)
|
||||||
lines = [line for line in fd.readlines() if line]
|
lines = [line for line in fd.readlines() if line]
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
for i,line in enumerate(tz.text.splitlines()):
|
for i,line in enumerate(tz.text.splitlines()):
|
||||||
lines.insert(2+i, line.encode(config.get("encoding", "stock"))+"\n")
|
lines.insert(2 + i, line + "\n")
|
||||||
|
|
||||||
fd = open(path, "w")
|
fd = _open(path, "w")
|
||||||
fd.writelines(lines)
|
fd.writelines(lines)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj.etag() not in old_objects:
|
if obj.etag() not in old_objects:
|
||||||
# TODO: Manage position, encoding and EOL
|
# TODO: Manage position and EOL
|
||||||
fd = open(path)
|
fd = _open(path)
|
||||||
lines = [line for line in fd.readlines() if line]
|
lines = [line for line in fd.readlines() if line]
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
for line in obj.text.splitlines():
|
for line in obj.text.splitlines():
|
||||||
lines.insert(-1, line.encode(config.get("encoding", "stock"))+"\n")
|
lines.insert(-1, line + "\n")
|
||||||
|
|
||||||
fd = open(path, "w")
|
fd = _open(path, "w")
|
||||||
fd.writelines(lines)
|
fd.writelines(lines)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
@ -99,15 +102,15 @@ def remove(cal, etag):
|
|||||||
"""Remove object named ``etag`` from ``cal``."""
|
"""Remove object named ``etag`` from ``cal``."""
|
||||||
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
path = os.path.join(_folder, cal.replace(posixpath.sep, os.path.sep))
|
||||||
|
|
||||||
cal = unicode(read(cal), config.get("encoding", "stock"))
|
cal = read(cal)
|
||||||
|
|
||||||
headers = ical.headers(cal)
|
headers = ical.headers(cal)
|
||||||
timezones = ical.timezones(cal)
|
timezones = ical.timezones(cal)
|
||||||
todos = [todo for todo in ical.todos(cal) if todo.etag() != etag]
|
todos = [todo for todo in ical.todos(cal) if todo.etag() != etag]
|
||||||
events = [event for event in ical.events(cal) if event.etag() != etag]
|
events = [event for event in ical.events(cal) if event.etag() != etag]
|
||||||
|
|
||||||
fd = open(path, "w")
|
fd = _open(path, "w")
|
||||||
fd.write(ical.write_calendar(headers, timezones, todos, events).encode(config.get("encoding", "stock")))
|
fd.write(ical.write_calendar(headers, timezones, todos, events))
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
if config.get("support", "calendar"):
|
if config.get("support", "calendar"):
|
||||||
|
@ -31,8 +31,7 @@ in them for XML requests (all but PUT).
|
|||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
import config
|
from radicale import config, ical
|
||||||
import ical
|
|
||||||
|
|
||||||
# TODO: This is a well-known and accepted hack for ET to avoid ET from renaming
|
# TODO: This is a well-known and accepted hack for ET to avoid ET from renaming
|
||||||
# namespaces, which is accepted in XML norm but often not in XML
|
# namespaces, which is accepted in XML norm but often not in XML
|
||||||
|
Loading…
Reference in New Issue
Block a user