Kozea / Radicale

A simple CalDAV (calendar) and CardDAV (contact) server.
https://radicale.org
GNU General Public License v3.0
3.39k stars 445 forks source link

Support free-busy-related requests #34

Open liZe opened 11 years ago

lpirl commented 10 years ago

+1

mike-perdide commented 10 years ago

For future reference: http://tools.ietf.org/html/rfc4791#section-6.1.1

I am very new to the CalDAV protocol, but it looks like it could be something that can be dealt with in the rights management: you'd have R access, W access, and free-busy access. Apparently it's a privilege that allows reading on some fields.

WhyNotHugo commented 9 years ago

@mike-perdide is right, free-busy access level isn't implemented, but it seems that the report isn't implemented either: I'm getting a 500 even with rw access.

Here's my test script (the request is literally copy-pasted from rfc4791#7.10.1):

#!/usr/bin/env python3

from base64 import b64encode
from http.client import HTTPSConnection

body = """<?xml version="1.0" encoding="utf-8" ?>
        <C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">
            <C:time-range start="20060104T140000Z" end="20060105T220000Z"/>
        </C:free-busy-query>
"""
user_and_pass = b64encode(b'hugo:MYPASSWORD').decode('ascii')
headers = {'Authorization': 'Basic %s' % user_and_pass}

conn = HTTPSConnection('calendar.barrera.io')
req = conn.request('REPORT', '/hugo/work/', body, headers=headers)
resp = conn.getresponse()

print(resp.status)
print(resp.reason)
print(resp.getheaders())
print(resp.read())

Output:

$ python freebusy.py
500
Internal Server Error
[('Server', 'nginx/1.7.10'), ('Date', 'Sat, 09 May 2015 17:55:51 GMT'), ('Content-Type', 'text/plain'), ('Content-Length', '59'), ('Connection', 'keep-alive')]
b'A server error occurred.  Please contact the administrator.'

Server log:

REPORT request at /hugo/work/ received
Request headers:
{'CONTENT_LENGTH': '213',
 'CONTENT_TYPE': 'text/plain',
 'GATEWAY_INTERFACE': 'CGI/1.1',
 'HTTP_ACCEPT_ENCODING': 'identity',
 'HTTP_AUTHORIZATION': 'Basic REDACTED',
 'HTTP_CONNECTION': 'close',
 'HTTP_HOST': 'localhost:5232',
 'PATH_INFO': '/hugo/work/',
 'QUERY_STRING': '',
 'REMOTE_ADDR': '127.0.0.1',
 'REMOTE_HOST': 'localhost',
 'REQUEST_METHOD': 'REPORT',
 'SCRIPT_NAME': '',
 'SERVER_NAME': 'elysion.barrera.io',
 'SERVER_PORT': '5232',
 'SERVER_PROTOCOL': 'HTTP/1.0',
 'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.7.9',
 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x74635da1e0>,
 'wsgi.file_wrapper': <class wsgiref.util.FileWrapper at 0x741f62fb48>,
 'wsgi.input': <socket._fileobject object at 0x74790cac50>,
 'wsgi.multiprocess': False,
 'wsgi.multithread': True,
 'wsgi.run_once': False,
 'wsgi.url_scheme': 'http',
 'wsgi.version': (1, 0)}
Sanitized path: /hugo/work/
Request content:
<?xml version="1.0" encoding="utf-8" ?>
        <C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">
            <C:time-range start="20060104T140000Z" end="20060105T220000Z"/>
        </C:free-busy-query>

Rights type 'owner_only'
Test if 'hugo:hugo/work' matches against '.+:^hugo(/.*)?$' from section 'rw'
Section 'rw' matches
hugo has read access to collection hugo/work/
Rights type 'owner_only'
Test if 'hugo:hugo/work' matches against '.+:^hugo(/.*)?$' from section 'rw'
Section 'rw' matches
hugo has write access to collection hugo/work/
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/wsgiref/handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "/usr/local/lib/python2.7/site-packages/radicale/__init__.py", line 306, in __call__
    user)
  File "/usr/local/lib/python2.7/site-packages/radicale/__init__.py", line 583, in report
    answer = xmlutils.report(environ["PATH_INFO"], content, collection)
  File "/usr/local/lib/python2.7/site-packages/radicale/xmlutils.py", line 470, in report
    props = [prop.tag for prop in prop_element]
TypeError: 'NoneType' object is not iterable
Jaikant commented 9 years ago

The report method is implemented, I tried your script with an http connection and default authorization (none) and the method executed.

WhyNotHugo commented 9 years ago

@Jaikant Are you sure about this? It failed for me, so I assumed it was not implemented.

I also took a quick glance at the source and it doesn't even seem to contain the term "free-busy" [1].

Did you get the expected results client-side?

Jaikant commented 9 years ago

@hobarrera A basic report method is implemented in init.py. It is able to query the VEVENT. The filters for free-busy query is not implemented yet is my guess. I can work on this, but need some guidance as I am new to python. Anyone?

WhyNotHugo commented 9 years ago

@Jaikant: That's exactly what I originally said, and the almost opposite of what you replied:

The report method is implemented, I tried your script with an http connection and default authorization (none) and the method executed.

Strictly speaking, yes. The script runs. It'll always run if you have python installed. I meant the script did not run successfully. The method did execute, but returned 500. I think my original point was clear enough, especially with all the included output: The script does not run successfully, and the server did not return the expected response.

However, the free-busy report is not implemented, which is what matters.

Jaikant commented 9 years ago

@hobarrera I got a 200 OK with the script. As I said there is an implementation for the report method. Look at the end of the xmlutils.py file for the details of what is implemented. And like I said earlier, maybe I was not clear. the implementation does not cover the full rfc.

WhyNotHugo commented 9 years ago

As I said there is an implementation for the report method. Look at the end of the xmlutils.py file for the details of what is implemented.

The free-busy report is not implemented. other reports are implemented, but that's really out-of-scope in this discussing. Stop trying to confuse people! This is not being productive at all, and is merely adding noise to this issue.

Jaikant commented 9 years ago

I think it was your test report which was incorrect. Glad to know that you realize what is and is not more clearly now. You want to help getting the free-busy implemented?

WhyNotHugo commented 9 years ago

You want to help getting the free-busy implemented?

Having some busy time with exams, and a few other things, but when time allows, I'd be willing to jump in on this (probably in two or three weeks time). I actually really need this feature. :)

Unrud commented 8 years ago

The Davical wiki states that free-busy-query is not supported by any client.

"Scheduling Extensions to CalDAV" seems to be the favoured method. The relevant RFC are 6638 and 5546. For support for scheduling across different servers 6047 is also required.

Additional a mapping between users and email addresses would be required in Radicale. Scheduling messages are addressed by email.

liZe commented 8 years ago

"Scheduling Extensions to CalDAV" seems to be the favoured method. The relevant RFC are 6638 and 5546. For support for scheduling across different servers 6047 is also required.

That's huge. Let's keep this feature for later then…

vinayguptagit commented 7 years ago

does radicale support free-busy feature now.

Thanks in advance

liZe commented 7 years ago

does radicale support free-busy feature now.

No.

srepmub commented 7 years ago

hi,

I've been reading a bit into this, and I'm not sure that it would require a huge effort, really.. the sabredav implementation here seems to be only about 840 SLOC:

https://github.com/fruux/sabre-dav/tree/master/lib/CalDAV/Schedule

most is in Plugin.php, so that's for both the scheduling and freebusy stuff. I'm tempted to try and add this myself, though I'm sure one of you guys could do a much better/faster job.

Unrud commented 7 years ago

As mentioned before, this is not (widely) supported by clients.

srepmub commented 7 years ago

for us at least (kopano.com), Apple iCalendar is an important client, and it seems to require this as of Yosemite..

Unrud commented 7 years ago

Apple iCalendar is an important client

What doesn't work with iCalendar?

srepmub commented 7 years ago

as of yosemite, it seems to assume that RFC6638 is in place, whether or not 'calendar-auto-schedule' is supported by the server:

https://discussions.apple.com/thread/6663683?start=0&tstart=0

Unrud commented 7 years ago

I think that RFC 6638 is out of scope. It seems like a major hassle for little gain.

nlincke commented 6 years ago

+1 Anyway, i think this feature would be appreciated by a lot of people....

ThomasChiroux commented 6 years ago

The python-caldav project support free-busy request and as i'm porting this project into aiohttp for async support: aiocaldav, i'm interrested in adding this feature to radicale.

I think we can add the feature without a lot of pain: without RFC 6638 (which I agree is out of scope), i think free/busy is kind of a subset of the calendar-query REPORT with only some changes in the query and return values.

If you're ok, i'll look into this.

kfred commented 6 years ago

@ThomasChiroux I have been trying to make a free-busy request with python-caldav unsuccessfully. Have you been able to successfully make make a free-busy request with python-caldav?

ThomasChiroux commented 6 years ago

I've not tried extensively python-caldav before porting it to asyncio. But i've rewritten some tests in aiocaldav with free-busy requests. They work against davical. You can have a look here for some samples, eaysily adaptable to python-caldav: https://github.com/ThomasChiroux/aiocaldav/blob/master/tests/test_freebusy.py

kfred commented 6 years ago

@ThomasChiroux Thanks, I took a look. I'm not sure why, but I keep getting the following error when trying to use python-caldav's freebusy_request() method:

caldav.lib.error.ReportError: 406 Not Acceptable

I know it's not permission based because I am able to successfully get a response when manually making an HTTPSConnection request using an xml free-busy-query payload.

<?xml version='1.0' encoding='utf-8'?>
<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV">
    <C:time-range start="20180711T140000Z" end="20180712T220000Z"/>
</C:free-busy-query>

I guess I will continue to construct these freebusy requests myself for now. I've opened an issue in the python-caldav project but don't have time to troubleshoot the library myself.

wepanx commented 5 years ago

Any news on this?

tobixen commented 3 years ago

I've opened an issue in the python-caldav project but don't have time to troubleshoot the library myself.

What is the issue number? I must have overlooked that one (I'm the primary maintainer of the library). The RFC states that free-busy requests MUST be supported by the server, yet the caldav client library test fails at several servers. I've always thought it was a problem at the server side, but I should probably look more into it.

EDIT: found it - https://github.com/python-caldav/caldav/issues/31 - closed due to lack of feedback. I will reopen it.

tobixen commented 3 years ago

Radicale 3.0.6 is in use, so the newest released version.

Here is from the debug logs (I realize I should put some efforts into better debugging output from caldav):

caldav: DEBUG: sending request - method=REPORT, url=http://localhost:5232/user1/pythoncaldav-test/, headers={'User-Agent': 'Mozilla/5.0', 'Content-Type': 'application/xml; charset="utf-8"', 'Accept': 'text/xml, text/calendar', 'Depth': '1'}
body:
<?xml version='1.0' encoding='utf-8'?>
<C:free-busy-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"><C:time-range start="20070713T150000Z" end="20070715T150000Z"/></C:free-busy-query>
radicale: INFO: REPORT request for '/user1/pythoncaldav-test/' with depth '1' received from ::1 using 'Mozilla/5.0'
radicale: DEBUG: Sanitized script name: ''
radicale: DEBUG: Sanitized path: '/user1/pythoncaldav-test/'
radicale: INFO: Successful login: 'user1'
radicale: DEBUG: Request content:
<?xml version="1.0"?>
<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">
  <C:time-range start="20070713T150000Z" end="20070715T150000Z" />
</C:free-busy-query>

radicale: DEBUG: Response content:
<?xml version="1.0"?>
<multistatus xmlns="DAV:">
  <response>
    <href>/user1/pythoncaldav-test/20010712T182145Z-123401%40example.com.ics</href>
  </response>
</multistatus>

There is an example at https://tools.ietf.org/html/rfc4791#section-7.10.1 ... my request is quite similar to the example code there. The response is quite far off from the example (the response should be icalendar, not xml). It seems to me radicale is recognizing the request not as a freebusy-request, but as a report-request towards the calendar.

The RFC states ...

The CALDAV:free-busy-query REPORT request can only be run against a collection (either a regular collection or a calendar collection). An attempt to run the report on a calendar object resource MUST fail and return a 403 (Forbidden) status value.

I'm doing a REPORT towards a calendar collection here, so it seems correct to me.

The RFC states ...

The response body for a successful request MUST be an iCalendar object that contains exactly one VFREEBUSY component that describes the busy time intervals for the calendar object resources containing VEVENT, or VFREEBUSY components that satisfy the Depth value and for which the current user is at least granted the CALDAV:read-free-busy privilege. If no calendar object resources are found to satisfy these conditions, a VFREEBUSY component with no FREEBUSY property MUST be returned

And the response from Radicale clearly breaks with that.

So it seems to me that Radicale is doing something wrong while I'm doing something right. I actually hope that I'm wrong - because support for free-busy-requests is mandatory according to the RFC, but freebusy-requests sent through my library works towards quite few calendar implementations. It would be nice if I could just fix the bug on my side, rather than realizing that very few caldav-servers supports the caldav-standard...

OdinVex commented 1 year ago

Very anxious to get this working, too. :)