Skip to content

Commit b1591ae

Browse files
author
(no author)
committed
Files added
git-svn-id: http://svn.32rwr.info/radicale/trunk@2 74e4794c-479d-4a33-9dda-c6c359d70f12
1 parent 1308ca0 commit b1591ae

10 files changed

+872
-0
lines changed

main.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8; indent-tabs-mode: nil; -*-
3+
#
4+
# This file is part of Radicale Server - Calendar Server
5+
# Copyright © 2008 The Radicale Team
6+
#
7+
# This library is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# This library is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
19+
20+
# TODO: Manage depth and calendars/collections (see xmlutils)
21+
# TODO: Manage smart and configurable logs
22+
# TODO: Manage authentication
23+
24+
# TODO: remove this hack
25+
import sys
26+
sys.path.append("/usr/local/lib/python2.5/site-packages")
27+
28+
from OpenSSL import SSL
29+
from twisted.web import server
30+
from twisted.internet import reactor
31+
from twisted.python import log
32+
33+
import radicale
34+
35+
class ServerContextFactory(object):
36+
"""
37+
SSL context factory
38+
"""
39+
def getContext(self):
40+
"""
41+
Get SSL context for the HTTP server
42+
"""
43+
ctx = SSL.Context(SSL.SSLv23_METHOD)
44+
ctx.use_certificate_file(radicale.config.get("server", "certificate"))
45+
ctx.use_privatekey_file(radicale.config.get("server", "privatekey"))
46+
return ctx
47+
48+
log.startLogging(sys.stdout)
49+
log.startLogging(open(radicale.config.get("server", "log"), "w"))
50+
factory = server.Site(radicale.HttpResource())
51+
reactor.listenSSL(radicale.config.getint("server", "port"), factory, ServerContextFactory())
52+
reactor.run()

radicale/__init__.py

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# -*- coding: utf-8; indent-tabs-mode: nil; -*-
2+
#
3+
# This file is part of Radicale Server - Calendar Server
4+
# Copyright © 2008 The Radicale Team
5+
#
6+
# This library is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
18+
19+
# TODO: Manage errors (see xmlutils)
20+
21+
from twisted.web.resource import Resource
22+
from twisted.web import http
23+
import posixpath
24+
25+
import config
26+
27+
import support
28+
import acl
29+
30+
import xmlutils
31+
import calendar
32+
33+
_users = acl.users()
34+
_calendars = support.calendars()
35+
36+
class CalendarResource(Resource):
37+
"""
38+
Twisted resource for requests at calendar depth (/user/calendar)
39+
"""
40+
isLeaf = True
41+
42+
def __init__(self, user, cal):
43+
"""
44+
Initialize resource creating a calendar object corresponding
45+
to the stocked calendar named user/cal
46+
"""
47+
Resource.__init__(self)
48+
self.calendar = calendar.Calendar(user, cal)
49+
50+
def render_DELETE(self, request):
51+
"""
52+
Manage DELETE requests
53+
"""
54+
obj = request.getHeader("if-match")
55+
answer = xmlutils.delete(obj, self.calendar, str(request.URLPath()))
56+
request.setResponseCode(http.NO_CONTENT)
57+
return answer
58+
59+
def render_OPTIONS(self, request):
60+
"""
61+
Manage OPTIONS requests
62+
"""
63+
request.setHeader("Allow", "DELETE, OPTIONS, PROPFIND, PUT, REPORT")
64+
request.setHeader("DAV", "1, calendar-access")
65+
request.setResponseCode(http.OK)
66+
return ""
67+
68+
def render_PROPFIND(self, request):
69+
"""
70+
Manage PROPFIND requests
71+
"""
72+
xmlRequest = request.content.read()
73+
answer = xmlutils.propfind(xmlRequest, self.calendar, str(request.URLPath()))
74+
request.setResponseCode(http.MULTI_STATUS)
75+
return answer
76+
77+
def render_PUT(self, request):
78+
"""
79+
Manage PUT requests
80+
"""
81+
# TODO: Improve charset detection
82+
contentType = request.getHeader("content-type")
83+
if contentType and "charset=" in contentType:
84+
charset = contentType.split("charset=")[1].strip()
85+
else:
86+
charset = config.get("encoding", "request")
87+
icalRequest = unicode(request.content.read(), charset)
88+
obj = request.getHeader("if-match")
89+
xmlutils.put(icalRequest, self.calendar, str(request.URLPath()), obj)
90+
request.setResponseCode(http.CREATED)
91+
return ""
92+
93+
def render_REPORT(self, request):
94+
"""
95+
Manage REPORT requests
96+
"""
97+
xmlRequest = request.content.read()
98+
answer = xmlutils.report(xmlRequest, self.calendar, str(request.URLPath()))
99+
request.setResponseCode(http.MULTI_STATUS)
100+
return answer
101+
102+
class UserResource(Resource):
103+
"""
104+
Twisted resource for requests at user depth (/user)
105+
"""
106+
def __init__(self, user):
107+
"""
108+
Initialize resource by connecting children requests to
109+
the user calendars resources
110+
"""
111+
Resource.__init__(self)
112+
for cal in _calendars:
113+
if cal.startswith("%s%s"%(user, posixpath.sep)):
114+
calName = cal.split(posixpath.sep)[1]
115+
self.putChild(calName, CalendarResource(user, cal))
116+
117+
def getChild(self, cal, request):
118+
"""
119+
Get calendar resource if user exists
120+
"""
121+
if cal in _calendars:
122+
return Resource.getChild(self, cal, request)
123+
else:
124+
return self
125+
126+
class HttpResource(Resource):
127+
"""
128+
Twisted resource for requests at root depth (/)
129+
"""
130+
def __init__(self):
131+
"""
132+
Initialize resource by connecting children requests to
133+
the users resources
134+
"""
135+
Resource.__init__(self)
136+
for user in _users:
137+
self.putChild(user, UserResource(user))
138+
139+
def getChild(self, user, request):
140+
"""
141+
Get user resource if user exists
142+
"""
143+
if user in _users:
144+
return Resource.getChild(self, user, request)
145+
else:
146+
return self

radicale/acl/__init__.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# -*- coding: utf-8; indent-tabs-mode: nil; -*-
2+
#
3+
# This file is part of Radicale Server - Calendar Server
4+
# Copyright © 2008 The Radicale Team
5+
#
6+
# This library is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
18+
19+
from .. import config
20+
21+
_acl = __import__(config.get("acl", "type"), locals(), globals())
22+
23+
users = _acl.users

radicale/acl/htpasswd.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# -*- coding: utf-8; indent-tabs-mode: nil; -*-
2+
#
3+
# This file is part of Radicale Server - Calendar Server
4+
# Copyright © 2008 The Radicale Team
5+
#
6+
# This library is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
18+
19+
from .. import config
20+
21+
def users():
22+
"""
23+
Get the List of all Users
24+
"""
25+
return [line.split(":")[0] for line in open(config.get("acl", "filename")).readlines()]

radicale/calendar.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# -*- coding: utf-8; indent-tabs-mode: nil; -*-
2+
#
3+
# This file is part of Radicale Server - Calendar Server
4+
# Copyright © 2008 The Radicale Team
5+
#
6+
# This library is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
18+
19+
# TODO: Manage inheritance for classes
20+
21+
from time import time
22+
23+
import support
24+
25+
class Calendar(object):
26+
"""
27+
Internal Calendar Class
28+
"""
29+
def __init__(self, user, cal):
30+
# TODO: Use properties from the calendar
31+
self.encoding = "utf-8"
32+
self.owner = "lize"
33+
self.user = user
34+
self.cal = cal
35+
self.version = "2.0"
36+
self.ctag = str(hash(self.vcalendar()))
37+
38+
def append(self, vcalendar):
39+
"""
40+
Append vcalendar
41+
"""
42+
self.ctag = str(hash(self.vcalendar()))
43+
support.append(self.cal, vcalendar)
44+
45+
def remove(self, uid):
46+
"""
47+
Remove Object Named uid
48+
"""
49+
self.ctag = str(hash(self.vcalendar()))
50+
support.remove(self.cal, uid)
51+
52+
def replace(self, uid, vcalendar):
53+
"""
54+
Replace Objet Named uid by vcalendar
55+
"""
56+
self.ctag = str(hash(self.vcalendar()))
57+
support.remove(self.cal, uid)
58+
support.append(self.cal, vcalendar)
59+
60+
def vcalendar(self):
61+
return unicode(support.read(self.cal), self.encoding)
62+
63+
class Event(object):
64+
"""
65+
Internal Event Class
66+
"""
67+
# TODO: Fix the behaviour if no UID is given
68+
def __init__(self, vcalendar):
69+
self.text = vcalendar
70+
71+
def etag(self):
72+
return str(hash(self.text))
73+
74+
class Header(object):
75+
"""
76+
Internal Headers Class
77+
"""
78+
def __init__(self, vcalendar):
79+
self.text = vcalendar
80+
81+
class Timezone(object):
82+
"""
83+
Internal Timezone Class
84+
"""
85+
def __init__(self, vcalendar):
86+
lines = vcalendar.splitlines()
87+
for line in lines:
88+
if line.startswith("TZID:"):
89+
self.tzid = line.lstrip("TZID:")
90+
break
91+
92+
self.text = vcalendar
93+
94+
class Todo(object):
95+
"""
96+
Internal Todo Class
97+
"""
98+
# TODO: Fix the behaviour if no UID is given
99+
def __init__(self, vcalendar):
100+
self.text = vcalendar
101+
102+
def etag(self):
103+
return str(hash(self.text))

0 commit comments

Comments
 (0)