From 208c869b6b17e2355aba56279b4afea93e2acdbf Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Mon, 13 Dec 2021 21:48:13 +0000 Subject: [PATCH] Generate documentation --- master.html | 474 +++++++++++++++++----------------- v1.html | 720 ++++++++++++++++++++++++++-------------------------- v2.html | 508 ++++++++++++++++++------------------ v3.html | 474 +++++++++++++++++----------------- 4 files changed, 1088 insertions(+), 1088 deletions(-) diff --git a/master.html b/master.html index 98f727a2..53706922 100644 --- a/master.html +++ b/master.html @@ -248,7 +248,7 @@

Installation

Radicale is really easy to install and works out-of-the-box.

$ python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz
-        $ python3 -m radicale --storage-filesystem-folder=~/.var/lib/radicale/collections
+$ python3 -m radicale --storage-filesystem-folder=~/.var/lib/radicale/collections

When the server is launched, open http://localhost:5232/ in your browser! You can login with any username and password.

Want more? Check the tutorials and the documentation.

@@ -269,9 +269,9 @@

First, make sure that python 3.5 or later (python ≥ 3.6 is recommended) and pip are installed. On most distributions it should be enough to install the package python3-pip.

Then open a console and type:

# Run the following command as root or
-        # add the --user argument to only install for the current user
-        $ python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz
-        $ python3 -m radicale --storage-filesystem-folder=~/.var/lib/radicale/collections
+# add the --user argument to only install for the current user +$ python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz +$ python3 -m radicale --storage-filesystem-folder=~/.var/lib/radicale/collections

Victory! Open http://localhost:5232/ in your browser! You can log in with any username and password.

@@ -279,7 +279,7 @@

The first step is to install Python. Go to python.org and download the latest version of Python 3. Then run the installer. On the first window of the installer, check the "Add Python to PATH" box and click on "Install now". Wait a couple of minutes, it's done!

Launch a command prompt and type:

C:\Users\User> python -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz
-        C:\Users\User> python -m radicale --storage-filesystem-folder=~/radicale/collections
+C:\Users\User> python -m radicale --storage-filesystem-folder=~/radicale/collections

Victory! Open http://localhost:5232/ in your browser! You can log in with any username and password.

@@ -297,44 +297,44 @@
The secure way

The users file can be created and managed with htpasswd:

# Create a new htpasswd file with the user "user1"
-        $ htpasswd -c /path/to/users user1
-        New password:
-        Re-type new password:
-        # Add another user
-        $ htpasswd /path/to/users user2
-        New password:
-        Re-type new password:
+$ htpasswd -c /path/to/users user1 +New password: +Re-type new password: +# Add another user +$ htpasswd /path/to/users user2 +New password: +Re-type new password:

Authentication can be enabled with the following configuration:

[auth]
-        type = htpasswd
-        htpasswd_filename = /path/to/users
-        # encryption method used in the htpasswd file
-        htpasswd_encryption = md5
+type = htpasswd +htpasswd_filename = /path/to/users +# encryption method used in the htpasswd file +htpasswd_encryption = md5
The simple but insecure way

Create the users file by hand with lines containing the user name and password separated by :. Example:

user1:password1
-        user2:password2
+user2:password2

Authentication can be enabled with the following configuration:

[auth]
-        type = htpasswd
-        htpasswd_filename = /path/to/users
-        # encryption method used in the htpasswd file
-        htpasswd_encryption = plain
+type = htpasswd +htpasswd_filename = /path/to/users +# encryption method used in the htpasswd file +htpasswd_encryption = plain

Addresses

The default configuration binds the server to localhost. It can't be reached from other computers. This can be changed with the following configuration options (IPv4 and IPv6):

[server]
-        hosts = 0.0.0.0:5232, [::]:5232
+hosts = 0.0.0.0:5232, [::]:5232

Storage

Data is stored in the folder /var/lib/radicale/collections. The path can be changed with the following configuration:

[storage]
-        filesystem_folder = /path/to/storage
+filesystem_folder = /path/to/storage

Security: The storage folder should not be readable by unauthorized users. Otherwise, they can read the calendar data and lock the storage. You can find OS dependent instructions in the Running as a service section.

@@ -343,15 +343,15 @@

Limits

Radicale enforces limits on the maximum number of parallel connections, the maximum file size (important for contacts with big photos) and the rate of incorrect authentication attempts. Connections are terminated after a timeout. The default values should be fine for most scenarios.

[server]
-        max_connections = 20
-        # 100 Megabyte
-        max_content_length = 100000000
-        # 30 seconds
-        timeout = 30
-        
-        [auth]
-        # Average delay after failed login attempts in seconds
-        delay = 1
+max_connections = 20 +# 100 Megabyte +max_content_length = 100000000 +# 30 seconds +timeout = 30 + +[auth] +# Average delay after failed login attempts in seconds +delay = 1
@@ -365,62 +365,62 @@

Create the file /etc/systemd/system/radicale.service:

[Unit]
-        Description=A simple CalDAV (calendar) and CardDAV (contact) server
-        After=network.target
-        Requires=network.target
-        
-        [Service]
-        ExecStart=/usr/bin/env python3 -m radicale
-        Restart=on-failure
-        User=radicale
-        # Deny other users access to the calendar data
-        UMask=0027
-        # Optional security settings
-        PrivateTmp=true
-        ProtectSystem=strict
-        ProtectHome=true
-        PrivateDevices=true
-        ProtectKernelTunables=true
-        ProtectKernelModules=true
-        ProtectControlGroups=true
-        NoNewPrivileges=true
-        ReadWritePaths=/var/lib/radicale/collections
-        
-        [Install]
-        WantedBy=multi-user.target
+Description=A simple CalDAV (calendar) and CardDAV (contact) server +After=network.target +Requires=network.target + +[Service] +ExecStart=/usr/bin/env python3 -m radicale +Restart=on-failure +User=radicale +# Deny other users access to the calendar data +UMask=0027 +# Optional security settings +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +PrivateDevices=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +NoNewPrivileges=true +ReadWritePaths=/var/lib/radicale/collections + +[Install] +WantedBy=multi-user.target

Radicale will load the configuration file from /etc/radicale/config.

To enable and manage the service run:

# Enable the service
-        $ systemctl enable radicale
-        # Start the service
-        $ systemctl start radicale
-        # Check the status of the service
-        $ systemctl status radicale
-        # View all log messages
-        $ journalctl --unit radicale.service
+$ systemctl enable radicale +# Start the service +$ systemctl start radicale +# Check the status of the service +$ systemctl status radicale +# View all log messages +$ journalctl --unit radicale.service

Linux with systemd as a user

Create the file ~/.config/systemd/user/radicale.service:

[Unit]
-        Description=A simple CalDAV (calendar) and CardDAV (contact) server
-        
-        [Service]
-        ExecStart=/usr/bin/env python3 -m radicale
-        Restart=on-failure
-        
-        [Install]
-        WantedBy=default.target
+Description=A simple CalDAV (calendar) and CardDAV (contact) server + +[Service] +ExecStart=/usr/bin/env python3 -m radicale +Restart=on-failure + +[Install] +WantedBy=default.target

Radicale will load the configuration file from ~/.config/radicale/config. You should set the configuration option filesystem_folder in the storage section to something like ~/.var/lib/radicale/collections.

To enable and manage the service run:

# Enable the service
-        $ systemctl --user enable radicale
-        # Start the service
-        $ systemctl --user start radicale
-        # Check the status of the service
-        $ systemctl --user status radicale
-        # View all log messages
-        $ journalctl --user --unit radicale.service
+$ systemctl --user enable radicale +# Start the service +$ systemctl --user start radicale +# Check the status of the service +$ systemctl --user status radicale +# View all log messages +$ journalctl --user --unit radicale.service

Windows with "NSSM - the Non-Sucking Service Manager"

@@ -428,12 +428,12 @@
@@ -545,11 +545,11 @@

A configuration file can be set with the RADICALE_CONFIG environment variable, otherwise no configuration file is loaded and the default configuration is used.

Example uWSGI configuration:

[uwsgi]
-        http-socket = 127.0.0.1:5232
-        processes = 8
-        plugin = python3
-        module = radicale
-        env = RADICALE_CONFIG=/etc/radicale/config
+http-socket = 127.0.0.1:5232 +processes = 8 +plugin = python3 +module = radicale +env = RADICALE_CONFIG=/etc/radicale/config

Example Gunicorn configuration:

gunicorn --bind '127.0.0.1:5232' --workers 8 --env 'RADICALE_CONFIG=/etc/radicale/config' radicale
@@ -562,8 +562,8 @@

This tutorial describes how to keep track of all changes to calendars and address books with git (or any other version control system).

The repository must be initialized by running git init in the file system folder. Internal files of Radicale can be excluded by creating the file .gitignore with the following content:

.Radicale.cache
-        .Radicale.lock
-        .Radicale.tmp-*
+.Radicale.lock +.Radicale.tmp-*

The configuration option hook in the storage section must be set to the following command:

git add -A && (git diff --cached --quiet || git commit -m "Changes by "%(user)s)

The command gets executed after every change to the storage and commits the changes into the git repository.

@@ -576,16 +576,16 @@

Radicale can be configured with a configuration file or with command line arguments.

An example configuration file looks like:

[server]
-        # Bind all addresses
-        hosts = 0.0.0.0:5232, [::]:5232
-        
-        [auth]
-        type = htpasswd
-        htpasswd_filename = ~/.config/radicale/users
-        htpasswd_encryption = md5
-        
-        [storage]
-        filesystem_folder = ~/.var/lib/radicale/collections
+# Bind all addresses +hosts = 0.0.0.0:5232, [::]:5232 + +[auth] +type = htpasswd +htpasswd_filename = ~/.config/radicale/users +htpasswd_encryption = md5 + +[storage] +filesystem_folder = ~/.var/lib/radicale/collections

Radicale tries to load configuration files from /etc/radicale/config and ~/.config/radicale/config. Custom paths can be specified with the --config /path/to/config command line argument or the RADICALE_CONFIG environment variable. Multiple configuration files can be separated by : (resp. ; on Windows). Paths that start with ? are optional.

The same example configuration via command line arguments looks like:

python3 -m radicale --server-hosts 0.0.0.0:5232,[::]:5232 --auth-type htpasswd --auth-htpasswd-filename ~/.config/radicale/users --auth-htpasswd-encryption md5
@@ -671,7 +671,7 @@

Available methods:

plain : Passwords are stored in plaintext. This is obviously not secure! The htpasswd file for this can be created by hand and looks like:

user1:password1
-        user2:password2
+user2:password2

bcrypt : This uses a modified version of the Blowfish stream cipher. It's very secure. The installation of radicale[bcrypt] is required for this.

md5 : This uses an iterated md5 digest of the password with a salt.

Default: md5

@@ -804,40 +804,40 @@

This is not the recommended way of creating and managing your calendars and address books. Use Radicale's web interface or a client with support for it (e.g. DAVx⁵).

To create a new calendar run something like:

$ curl -u user -X MKCOL 'http://localhost:5232/user/calendar' --data \
-        '<?xml version="1.0" encoding="UTF-8" ?>
-        <create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/">
-          <set>
-            <prop>
-              <resourcetype>
-                <collection />
-                <C:calendar />
-              </resourcetype>
-              <C:supported-calendar-component-set>
-                <C:comp name="VEVENT" />
-                <C:comp name="VJOURNAL" />
-                <C:comp name="VTODO" />
-              </C:supported-calendar-component-set>
-              <displayname>Calendar</displayname>
-              <C:calendar-description>Example calendar</C:calendar-description>
-              <I:calendar-color>#ff0000ff</I:calendar-color>
-            </prop>
-          </set>
-        </create>'
+'<?xml version="1.0" encoding="UTF-8" ?> +<create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/"> + <set> + <prop> + <resourcetype> + <collection /> + <C:calendar /> + </resourcetype> + <C:supported-calendar-component-set> + <C:comp name="VEVENT" /> + <C:comp name="VJOURNAL" /> + <C:comp name="VTODO" /> + </C:supported-calendar-component-set> + <displayname>Calendar</displayname> + <C:calendar-description>Example calendar</C:calendar-description> + <I:calendar-color>#ff0000ff</I:calendar-color> + </prop> + </set> +</create>'

To create a new address book run something like:

$ curl -u user -X MKCOL 'http://localhost:5232/user/addressbook' --data \
-        '<?xml version="1.0" encoding="UTF-8" ?>
-        <create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav">
-          <set>
-            <prop>
-              <resourcetype>
-                <collection />
-                <CR:addressbook />
-              </resourcetype>
-              <displayname>Address book</displayname>
-              <CR:addressbook-description>Example address book</CR:addressbook-description>
-            </prop>
-          </set>
-        </create>'
+'<?xml version="1.0" encoding="UTF-8" ?> +<create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav"> + <set> + <prop> + <resourcetype> + <collection /> + <CR:addressbook /> + </resourcetype> + <displayname>Address book</displayname> + <CR:addressbook-description>Example address book</CR:addressbook-description> + </prop> + </set> +</create>'

The collection /USERNAME will be created automatically, when the user authenticates to Radicale for the first time. Clients with automatic discovery of collections will only show calendars and address books that are direct children of the path /USERNAME/.

Delete the collections by running something like:

$ curl -u user -X DELETE 'http://localhost:5232/user/calendar'
@@ -849,23 +849,23 @@

The recommended rights method is owner_only. If access to calendars and address books outside the home directory of users (that's /USERNAME/) is granted, clients won't detect these collections and will not show them to the user. This is only useful if you access calendars and address books directly via URL.

An example rights file:

# Allow reading root collection for authenticated users
-        [root]
-        user: .+
-        collection:
-        permissions: R
-        
-        # Allow reading and writing principal collection (same as user name)
-        [principal]
-        user: .+
-        collection: {user}
-        permissions: RW
-        
-        # Allow reading and writing calendars and address books that are direct
-        # children of the principal collection
-        [calendars]
-        user: .+
-        collection: {user}/[^/]+
-        permissions: rw
+[root] +user: .+ +collection: +permissions: R + +# Allow reading and writing principal collection (same as user name) +[principal] +user: .+ +collection: {user} +permissions: RW + +# Allow reading and writing calendars and address books that are direct +# children of the principal collection +[calendars] +user: .+ +collection: {user}/[^/]+ +permissions: rw

The titles of the sections are ignored (but must be unique). The keys user and collection contain regular expressions, that are matched against the user name and the path of the collection. Permissions from the first matching section are used. If no section matches, access gets denied.

The user name is empty for anonymous users. Therefore, the regex .+ only matches authenticated users and .* matches everyone (including anonymous users).

The path of the collection is separated by / and has no leading or trailing /. Therefore, the path of the root collection is empty.

@@ -905,9 +905,9 @@
Linux shell scripts

Use the flock utility.

# Exclusive
-        $ flock --exclusive /path/to/storage/.Radicale.lock COMMAND
-        # Shared
-        $ flock --shared /path/to/storage/.Radicale.lock COMMAND
+$ flock --exclusive /path/to/storage/.Radicale.lock COMMAND +# Shared +$ flock --shared /path/to/storage/.Radicale.lock COMMAND
Linux and MacOS
@@ -1010,39 +1010,39 @@

To get started we walk through the creation of a simple authentication plugin, that accepts login attempts with a static password.

The easiest way to develop and install python modules is Distutils. For a minimal setup create the file setup.py with the following content in an empty folder:

#!/usr/bin/env python3
-        
-        from distutils.core import setup
-        
-        setup(name="radicale_static_password_auth",
-              packages=["radicale_static_password_auth"])
+ +from distutils.core import setup + +setup(name="radicale_static_password_auth", + packages=["radicale_static_password_auth"])

In the same folder create the sub-folder radicale_static_password_auth. The folder must have the same name as specified in packages above.

Create the file __init__.py in the radicale_static_password_auth folder with the following content:

from radicale.auth import BaseAuth
-        from radicale.log import logger
-        
-        PLUGIN_CONFIG_SCHEMA = {"auth": {
-            "password": {"value": "", "type": str}}}
-        
-        
-        class Auth(BaseAuth):
-            def __init__(self, configuration):
-                super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA))
-        
-            def login(self, login, password):
-                # Get password from configuration option
-                static_password = self.configuration.get("auth", "password")
-                # Check authentication
-                logger.info("Login attempt by %r with password %r",
-                            login, password)
-                if password == static_password:
-                    return login
-                return ""
+from radicale.log import logger + +PLUGIN_CONFIG_SCHEMA = {"auth": { + "password": {"value": "", "type": str}}} + + +class Auth(BaseAuth): + def __init__(self, configuration): + super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA)) + + def login(self, login, password): + # Get password from configuration option + static_password = self.configuration.get("auth", "password") + # Check authentication + logger.info("Login attempt by %r with password %r", + login, password) + if password == static_password: + return login + return ""

Install the python module by running the following command in the same folder as setup.py:

python3 -m pip install .

To make use this great creation in Radicale, set the configuration option type in the auth section to radicale_static_password_auth:

[auth]
-        type = radicale_static_password_auth
-        password = secret
+type = radicale_static_password_auth +password = secret

You can uninstall the module with:

python3 -m pip uninstall radicale_static_password_auth
diff --git a/v1.html b/v1.html index 3b7f77ee..101039f4 100644 --- a/v1.html +++ b/v1.html @@ -515,72 +515,72 @@
InfCloud, CalDavZAP & CardDavMATE

Because settings are the same for InfCloud, CalDavZAP and CardDavMATE
- only InfCloud is used in description below.

+only InfCloud is used in description below.

Radicale configuration

Add/Modify the following section in Radicale main configuration file:

# Additional HTTP headers
-        [headers]
-        Access-Control-Allow-Origin = *
-        Access-Control-Allow-Methods = GET, POST, OPTIONS, PROPFIND, PROPPATCH, REPORT, PUT, MOVE, DELETE, LOCK, UNLOCK
-        Access-Control-Allow-Headers = Authorization, Content-type, Depth, Destination, If-match, If-None-Match, Lock-Token, Overwrite, Prefer, Timeout, User-Agent, X-Client, X-Requested-With
-        Access-Control-Expose-Headers = Etag
+[headers] +Access-Control-Allow-Origin = * +Access-Control-Allow-Methods = GET, POST, OPTIONS, PROPFIND, PROPPATCH, REPORT, PUT, MOVE, DELETE, LOCK, UNLOCK +Access-Control-Allow-Headers = Authorization, Content-type, Depth, Destination, If-match, If-None-Match, Lock-Token, Overwrite, Prefer, Timeout, User-Agent, X-Client, X-Requested-With +Access-Control-Expose-Headers = Etag

InfCloud needs read access for everybody (including anonymous users) on Radicale's root directory. If using Radicales rights management add the following section to rights file:

# Allow caldavzap, carddavmate and infcloud to work
-        [infcloud]
-        user: .*
-        collection: /
-        permission: r
+[infcloud] +user: .* +collection: / +permission: r

Additional you need to change [owner-write] section to use the same syntax for collection as shown in [public] section.

# Give write access to owners
-        [owner-write]
-        user: .+
-        # collection: ^%(login)s/.+$    # DOES NOT WORK
-        collection: ^%(login)s(/.+)?$
-        permission: rw
+[owner-write] +user: .+ +# collection: ^%(login)s/.+$ # DOES NOT WORK +collection: ^%(login)s(/.+)?$ +permission: rw

InfCloud configuration

Inside InfCloud configuration file config.js you need to set globalNetworkCheckSettings like following example:

// href: 
-        // put in here your protocol, host and port where Radicale is listening
-        // additionalResources:
-        // put in here a comma separated list of collections you want additionally look at.
-        // Don't forget '' around each collections name
-        var globalNetworkCheckSettings={
-            href: 'https://host.example.com:5232/',
-            hrefLabel: null,
-            crossDomain: null,
-            additionalResources: ['public'],
-            forceReadOnly: null,
-            withCredentials: false,
-            showHeader: true,
-            settingsAccount: true,
-            syncInterval: 60000,
-            timeOut: 30000,
-            lockTimeOut: 10000,
-            delegation: false,
-            ignoreAlarms: false,
-            backgroundCalendars: []
-        }
+// put in here your protocol, host and port where Radicale is listening +// additionalResources: +// put in here a comma separated list of collections you want additionally look at. +// Don't forget '' around each collections name +var globalNetworkCheckSettings={ + href: 'https://host.example.com:5232/', + hrefLabel: null, + crossDomain: null, + additionalResources: ['public'], + forceReadOnly: null, + withCredentials: false, + showHeader: true, + settingsAccount: true, + syncInterval: 60000, + timeOut: 30000, + lockTimeOut: 10000, + delegation: false, + ignoreAlarms: false, + backgroundCalendars: [] +}

Note

InfCloud, CardDavMATE and CalDavZAP cannot create calendars and/or address books. They need to be created before first login. Each user needs to have minimum of one calendar and/or one adressbook even if only using shared addresses and/or calendars. Client will not login, if the user collections don't exists.

You can easily create them by directly calling the URL's from your browser:
-   http(s)://host.example.com:5232/user/calendar.ics/
-   http(s)://host.example.com:5232/user/addresses.vcf/

+  http(s)://host.example.com:5232/user/calendar.ics/
+  http(s)://host.example.com:5232/user/addresses.vcf/

Replace "http(s)" with the correct protocol, "host.example.com:5232" with you host:port where Radicale is running,
- "user" with the correct login name or the shared resource name i.e. 'public',
- "calendar.ics" and "addresses.vcf" with the collection names you want to use
- and do NOT forget the '/' at line end.

+"user" with the correct login name or the shared resource name i.e. 'public',
+"calendar.ics" and "addresses.vcf" with the collection names you want to use
+and do NOT forget the '/' at line end.

Note

If using self-signed certificates you need to do the following steps before using InfCloud, CardDavMATE or CalDavZAP.
- With your browser call one of the above URLs.
- Your browser warn you that you are trying to access an Insecure site.
- Download and accept the certificate offered by the Radicale server.
- After installing and accepting it you should restart your browser.

+With your browser call one of the above URLs.
+Your browser warn you that you are trying to access an Insecure site.
+Download and accept the certificate offered by the Radicale server.
+After installing and accepting it you should restart your browser.

@@ -691,7 +691,7 @@
  • A new account "iCloud" with the given email address appears on the list. The status is "Not up to date". Click the account.
  • An error message is given. Click "close".
  • Enter new and "real" values to the account setting fields: -
  • @@ -917,53 +917,53 @@
    radicale --debug

    Radicale can also be configured to send the messages to the console, logging files, syslog, etc. For more information about the syntax of the configuration file, see: http://docs.python.org/library/logging.config.html. Here is an example of logging configuration file:

    # Loggers, handlers and formatters keys
    -        
    -        [loggers]
    -        # Loggers names, main configuration slots
    -        keys = root
    -        
    -        [handlers]
    -        # Logging handlers, defining logging output methods
    -        keys = console,file
    -        
    -        [formatters]
    -        # Logging formatters
    -        keys = simple,full
    -        
    -        
    -        # Loggers
    -        
    -        [logger_root]
    -        # Root logger
    -        level = DEBUG
    -        handlers = console,file
    -        
    -        
    -        # Handlers
    -        
    -        [handler_console]
    -        # Console handler
    -        class = StreamHandler
    -        level = INFO
    -        args = (sys.stdout,)
    -        formatter = simple
    -        
    -        [handler_file]
    -        # File handler
    -        class = FileHandler
    -        args = ('/var/log/radicale',)
    -        formatter = full
    -        
    -        
    -        # Formatters
    -        
    -        [formatter_simple]
    -        # Simple output format
    -        format = %(message)s
    -        
    -        [formatter_full]
    -        # Full output format
    -        format = %(asctime)s - %(levelname)s: %(message)s
    + +[loggers] +# Loggers names, main configuration slots +keys = root + +[handlers] +# Logging handlers, defining logging output methods +keys = console,file + +[formatters] +# Logging formatters +keys = simple,full + + +# Loggers + +[logger_root] +# Root logger +level = DEBUG +handlers = console,file + + +# Handlers + +[handler_console] +# Console handler +class = StreamHandler +level = INFO +args = (sys.stdout,) +formatter = simple + +[handler_file] +# File handler +class = FileHandler +args = ('/var/log/radicale',) +formatter = full + + +# Formatters + +[formatter_simple] +# Simple output format +format = %(message)s + +[formatter_full] +# Full output format +format = %(asctime)s - %(levelname)s: %(message)s
    Command Line Options
    @@ -979,27 +979,27 @@
    Apache and mod_wsgi

    To use Radicale with Apache's mod_wsgi, you first have to install the Radicale module in your Python path and write your .wsgi file (in /var/www for example):

    import radicale
    -        radicale.log.start()
    -        application = radicale.Application()
    +radicale.log.start() +application = radicale.Application()

    Note

    The hosts, daemon, pid, ssl, certificate, key, protocol and ciphers keys of the [server] part of the configuration are ignored.

    Next you have to create the Apache virtual host (adapt the configuration to your environment):

    <VirtualHost *:80>
    -            ServerName cal.yourdomain.org
    -        
    -            WSGIDaemonProcess radicale user=www-data group=www-data threads=1
    -            WSGIScriptAlias / /var/www/radicale.wsgi
    -        
    -            <Directory /var/www>
    -                WSGIProcessGroup radicale
    -                WSGIApplicationGroup %{GLOBAL}
    -                AllowOverride None
    -                Order allow,deny
    -                allow from all
    -            </Directory>
    -        </VirtualHost>
    + ServerName cal.yourdomain.org + + WSGIDaemonProcess radicale user=www-data group=www-data threads=1 + WSGIScriptAlias / /var/www/radicale.wsgi + + <Directory /var/www> + WSGIProcessGroup radicale + WSGIApplicationGroup %{GLOBAL} + AllowOverride None + Order allow,deny + allow from all + </Directory> +</VirtualHost>

    Warning

    You should use the root of the (sub)domain (WSGIScriptAlias /), else some CalDAV features may not work.

    @@ -1008,28 +1008,28 @@

    Deactivate any rights and module in Radicale and use your favourite Apache authentication backend. You can then restrict the access: allow the alice user to access /alice/* URLs, and everything should work as expected.

    Here is one example of Apache configuration file:

    <VirtualHost *:80>
    -            ServerName radicale.local
    -        
    -            WSGIDaemonProcess radicale user=radicale group=radicale threads=1
    -            WSGIScriptAlias / /usr/share/radicale/radicale.wsgi
    -        
    -            <Directory /usr/share/radicale/>
    -                WSGIProcessGroup radicale
    -                WSGIApplicationGroup %{GLOBAL}
    -        
    -                AuthType Basic
    -                AuthName "Radicale Authentication"
    -                AuthBasicProvider file
    -                AuthUserFile /usr/share/radicale/radicale.passwd
    -        
    -                AllowOverride None
    -                Require valid-user
    -        
    -                RewriteEngine On
    -                RewriteCond %{REMOTE_USER}%{PATH_INFO} !^([^/]+/)\1
    -                RewriteRule .* - [Forbidden]
    -            </Directory>
    -        </VirtualHost>
    + ServerName radicale.local + + WSGIDaemonProcess radicale user=radicale group=radicale threads=1 + WSGIScriptAlias / /usr/share/radicale/radicale.wsgi + + <Directory /usr/share/radicale/> + WSGIProcessGroup radicale + WSGIApplicationGroup %{GLOBAL} + + AuthType Basic + AuthName "Radicale Authentication" + AuthBasicProvider file + AuthUserFile /usr/share/radicale/radicale.passwd + + AllowOverride None + Require valid-user + + RewriteEngine On + RewriteCond %{REMOTE_USER}%{PATH_INFO} !^([^/]+/)\1 + RewriteRule .* - [Forbidden] + </Directory> +</VirtualHost>

    If you're still convinced that access control is better with Radicale, you have to add WSGIPassAuthorization On in your Apache configuration files, as explained in the mod_wsgi documentation.

    Note

    @@ -1085,45 +1085,45 @@

    Leading or ending slashes are trimmed from collection's path.

    Example:

    # The default path for this kind of files is ~/.config/radicale/rights
    -        # This can be changed in the configuration file
    -        #
    -        # This file gives independant examples to help users write their own
    -        # configuration files. Using these examples together in the same configuration
    -        # file is meaningless.
    -        #
    -        # The first rule matching both user and collection patterns will be returned.
    -        
    -        # This means all users starting with "admin" may read any collection
    -        [admin]
    -        user: ^admin.*$
    -        collection: .*
    -        permission: r
    -        
    -        # This means all users may read and write any collection starting with public.
    -        # We do so by just not testing against the user string.
    -        [public]
    -        user: .*
    -        collection: ^public(/.+)?$
    -        permission: rw
    -        
    -        # A little more complex: give read access to users from a domain for all
    -        # collections of all the users (ie. user@domain.tld can read domain/*).
    -        [domain-wide-access]
    -        user: ^.+@(.+)\..+$
    -        collection: ^{0}/.+$
    -        permission: r
    -        
    -        # Allow authenticated user to read all collections
    -        [allow-everyone-read]
    -        user: .+
    -        collection: .*
    -        permission: r
    -        
    -        # Give write access to owners
    -        [owner-write]
    -        user: .+
    -        collection: ^%(login)s/.*$
    -        permission: w
    +# This can be changed in the configuration file +# +# This file gives independant examples to help users write their own +# configuration files. Using these examples together in the same configuration +# file is meaningless. +# +# The first rule matching both user and collection patterns will be returned. + +# This means all users starting with "admin" may read any collection +[admin] +user: ^admin.*$ +collection: .* +permission: r + +# This means all users may read and write any collection starting with public. +# We do so by just not testing against the user string. +[public] +user: .* +collection: ^public(/.+)?$ +permission: rw + +# A little more complex: give read access to users from a domain for all +# collections of all the users (ie. user@domain.tld can read domain/*). +[domain-wide-access] +user: ^.+@(.+)\..+$ +collection: ^{0}/.+$ +permission: r + +# Allow authenticated user to read all collections +[allow-everyone-read] +user: .+ +collection: .* +permission: r + +# Give write access to owners +[owner-write] +user: .+ +collection: ^%(login)s/.*$ +permission: w
    @@ -1319,21 +1319,21 @@

    The package offers 8 modules.

    @@ -1868,11 +1868,11 @@

    Some features have been added in the git repository during the last weeks, thanks to Jerome and Mariusz!

    @@ -1934,9 +1934,9 @@

    HTTPS connections and authentication have been added to Radicale this week. Command-line options and personal configuration files are also ready for test. According to the TODO file included in the package, the next version will finally be 0.2, when sunbird 1.0 is out. Go, Mozilla hackers, go!

    diff --git a/v2.html b/v2.html index 005d2fca..2df652f3 100644 --- a/v2.html +++ b/v2.html @@ -421,7 +421,7 @@

    Installation

    Radicale is really easy to install and works out-of-the-box.

    $ python3 -m pip install --upgrade radicale==2.1.*
    -        $ python3 -m radicale --config "" --storage-filesystem-folder=~/.var/lib/radicale/collections
    +$ python3 -m radicale --config "" --storage-filesystem-folder=~/.var/lib/radicale/collections

    When your server is launched, you can check that everything's OK by going to http://localhost:5232/ with your browser! You can login with any username and password.

    Want more? Why don't you check our wonderful documentation?

    @@ -481,9 +481,9 @@

    First of all, make sure that python 3.3 or later (python ≥ 3.6 is recommended) and pip are installed. On most distributions it should be enough to install the package python3-pip.

    Then open a console and type:

    # Run the following command as root or
    -        # add the --user argument to only install for the current user
    -        $ python3 -m pip install --upgrade radicale==2.1.*
    -        $ python3 -m radicale --config "" --storage-filesystem-folder=~/.var/lib/radicale/collections
    +# add the --user argument to only install for the current user +$ python3 -m pip install --upgrade radicale==2.1.* +$ python3 -m radicale --config "" --storage-filesystem-folder=~/.var/lib/radicale/collections

    Victory! Open http://localhost:5232/ in your browser! You can login with any username and password.

    @@ -491,7 +491,7 @@

    The first step is to install Python. Go to python.org and download the latest version of Python 3. Then run the installer. On the first window of the installer, check the "Add Python to PATH" box and click on "Install now". Wait a couple of minutes, it's done!

    Launch a command prompt and type:

    C:\Users\User> python -m pip install --upgrade radicale==2.1.*
    -        C:\Users\User> python -m radicale --config "" --storage-filesystem-folder=~/radicale/collections
    +C:\Users\User> python -m radicale --config "" --storage-filesystem-folder=~/radicale/collections

    If you are using PowerShell replace --config "" with --config '""'.

    Victory! Open http://localhost:5232/ in your browser! You can login with any username and password.

    @@ -517,62 +517,62 @@
    The secure way

    The users file can be created and managed with htpasswd:

    # Create a new htpasswd file with the user "user1"
    -        $ htpasswd -B -c /path/to/users user1
    -        New password:
    -        Re-type new password:
    -        # Add another user
    -        $ htpasswd -B /path/to/users user2
    -        New password:
    -        Re-type new password:
    +$ htpasswd -B -c /path/to/users user1 +New password: +Re-type new password: +# Add another user +$ htpasswd -B /path/to/users user2 +New password: +Re-type new password:

    bcrypt is used to secure the passwords. Radicale requires additional dependencies for this encryption method:

    $ python3 -m pip install --upgrade radicale[bcrypt]==2.1.*

    Authentication can be enabled with the following configuration:

    [auth]
    -        type = htpasswd
    -        htpasswd_filename = /path/to/users
    -        # encryption method used in the htpasswd file
    -        htpasswd_encryption = bcrypt
    +type = htpasswd +htpasswd_filename = /path/to/users +# encryption method used in the htpasswd file +htpasswd_encryption = bcrypt
    The simple but insecure way

    Create the users file by hand with lines containing the user name and password separated by :. Example:

    user1:password1
    -        user2:password2
    +user2:password2

    Authentication can be enabled with the following configuration:

    [auth]
    -        type = htpasswd
    -        htpasswd_filename = /path/to/users
    -        # encryption method used in the htpasswd file
    -        htpasswd_encryption = plain
    +type = htpasswd +htpasswd_filename = /path/to/users +# encryption method used in the htpasswd file +htpasswd_encryption = plain

    Addresses

    The default configuration binds the server to localhost. It can't be reached from other computers. This can be changed with the following configuration options:

    [server]
    -        hosts = 0.0.0.0:5232
    +hosts = 0.0.0.0:5232

    More addresses can be added (separated by commas).

    Storage

    Data is stored in the folder /var/lib/radicale/collections. The path can be changed with the following configuration:

    [storage]
    -        filesystem_folder = /path/to/storage
    +filesystem_folder = /path/to/storage

    Security: The storage folder should not be readable by unauthorized users. Otherwise, they can read the calendar data and lock the storage. You can find OS dependent instructions in the Running as a service section.

    Limits

    Radicale enforces limits on the maximum number of parallel connections, the maximum file size (important for contacts with big photos) and the rate of incorrect authentication attempts. Connections are terminated after a timeout. The default values should be fine for most scenarios.

    [server]
    -        max_connections = 20
    -        # 100 Megabyte
    -        max_content_length = 100000000
    -        # 30 seconds
    -        timeout = 30
    -        
    -        [auth]
    -        # Average delay after failed login attempts in seconds
    -        delay = 1
    +max_connections = 20 +# 100 Megabyte +max_content_length = 100000000 +# 30 seconds +timeout = 30 + +[auth] +# Average delay after failed login attempts in seconds +delay = 1

    Running as a service

    @@ -581,24 +581,24 @@
    Linux with systemd as a user

    Create the file ~/.config/systemd/user/radicale.service:

    [Unit]
    -        Description=A simple CalDAV (calendar) and CardDAV (contact) server
    -        
    -        [Service]
    -        ExecStart=/usr/bin/env python3 -m radicale
    -        Restart=on-failure
    -        
    -        [Install]
    -        WantedBy=default.target
    +Description=A simple CalDAV (calendar) and CardDAV (contact) server + +[Service] +ExecStart=/usr/bin/env python3 -m radicale +Restart=on-failure + +[Install] +WantedBy=default.target

    Radicale will load the configuration file from ~/.config/radicale/config. You should set the configuration option filesystem_folder in the storage section to something like ~/.var/lib/radicale/collections.

    To enable and manage the service run:

    # Enable the service
    -        $ systemctl --user enable radicale
    -        # Start the service
    -        $ systemctl --user start radicale
    -        # Check the status of the service
    -        $ systemctl --user status radicale
    -        # View all log messages
    -        $ journalctl --user --unit radicale.service
    +$ systemctl --user enable radicale +# Start the service +$ systemctl --user start radicale +# Check the status of the service +$ systemctl --user status radicale +# View all log messages +$ journalctl --user --unit radicale.service
    Linux with systemd system-wide
    @@ -606,39 +606,39 @@

    Security: The storage should not be readable by others. (Run chmod -R o= /var/lib/radicale/collections as root.)

    Create the file /etc/systemd/system/radicale.service:

    [Unit]
    -        Description=A simple CalDAV (calendar) and CardDAV (contact) server
    -        After=network.target
    -        Requires=network.target
    -        
    -        [Service]
    -        ExecStart=/usr/bin/env python3 -m radicale
    -        Restart=on-failure
    -        User=radicale
    -        # Deny other users access to the calendar data
    -        UMask=0027
    -        # Optional security settings
    -        PrivateTmp=true
    -        ProtectSystem=strict
    -        ProtectHome=true
    -        PrivateDevices=true
    -        ProtectKernelTunables=true
    -        ProtectKernelModules=true
    -        ProtectControlGroups=true
    -        NoNewPrivileges=true
    -        ReadWritePaths=/var/lib/radicale/collections
    -        
    -        [Install]
    -        WantedBy=multi-user.target
    +Description=A simple CalDAV (calendar) and CardDAV (contact) server +After=network.target +Requires=network.target + +[Service] +ExecStart=/usr/bin/env python3 -m radicale +Restart=on-failure +User=radicale +# Deny other users access to the calendar data +UMask=0027 +# Optional security settings +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +PrivateDevices=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +NoNewPrivileges=true +ReadWritePaths=/var/lib/radicale/collections + +[Install] +WantedBy=multi-user.target

    Radicale will load the configuration file from /etc/radicale/config.

    To enable and manage the service run:

    # Enable the service
    -        $ systemctl enable radicale
    -        # Start the service
    -        $ systemctl start radicale
    -        # Check the status of the service
    -        $ systemctl status radicale
    -        # View all log messages
    -        $ journalctl --unit radicale.service
    +$ systemctl enable radicale +# Start the service +$ systemctl start radicale +# Check the status of the service +$ systemctl status radicale +# View all log messages +$ journalctl --unit radicale.service
    @@ -658,12 +658,12 @@
    @@ -751,11 +751,11 @@

    Security: The None authentication type disables all rights checking. Don't use it with REMOTE_USER. Use remote_user instead.

    Example uWSGI configuration:

    [uwsgi]
    -        http-socket = 127.0.0.1:5232
    -        processes = 8
    -        plugin = python3
    -        module = radicale
    -        env = RADICALE_CONFIG=/etc/radicale/config
    +http-socket = 127.0.0.1:5232 +processes = 8 +plugin = python3 +module = radicale +env = RADICALE_CONFIG=/etc/radicale/config

    Example Gunicorn configuration:

    gunicorn --bind '127.0.0.1:5232' --workers 8 --env 'RADICALE_CONFIG=/etc/radicale/config' radicale
    @@ -768,8 +768,8 @@

    This page describes how to keep track of all changes to calendars and address books with git (or any other version control system).

    The repository must be initialized by running git init in the file system folder. Internal files of Radicale can be excluded by creating the file .gitignore with the following content:

    .Radicale.cache
    -        .Radicale.lock
    -        .Radicale.tmp-*
    +.Radicale.lock +.Radicale.tmp-*

    The configuration option hook in the storage section must be set to the following command:

    git add -A && (git diff --cached --quiet || git commit -m "Changes by "%(user)s)

    The command gets executed after every change to the storage and commits the changes into the git repository.

    @@ -826,40 +826,40 @@
    HTTP requests with curl

    To create a new calendar run something like:

    $ curl -u user -X MKCOL 'http://localhost:5232/user/calendar' --data \
    -        '<?xml version="1.0" encoding="UTF-8" ?>
    -        <create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/">
    -          <set>
    -            <prop>
    -              <resourcetype>
    -                <collection />
    -                <C:calendar />
    -              </resourcetype>
    -              <C:supported-calendar-component-set>
    -                <C:comp name="VEVENT" />
    -                <C:comp name="VJOURNAL" />
    -                <C:comp name="VTODO" />
    -              </C:supported-calendar-component-set>
    -              <displayname>Calendar</displayname>
    -              <C:calendar-description>Example calendar</C:calendar-description>
    -              <I:calendar-color>#ff0000ff</I:calendar-color>
    -            </prop>
    -          </set>
    -        </create>'
    +'<?xml version="1.0" encoding="UTF-8" ?> +<create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/"> + <set> + <prop> + <resourcetype> + <collection /> + <C:calendar /> + </resourcetype> + <C:supported-calendar-component-set> + <C:comp name="VEVENT" /> + <C:comp name="VJOURNAL" /> + <C:comp name="VTODO" /> + </C:supported-calendar-component-set> + <displayname>Calendar</displayname> + <C:calendar-description>Example calendar</C:calendar-description> + <I:calendar-color>#ff0000ff</I:calendar-color> + </prop> + </set> +</create>'

    To create a new address book run something like:

    $ curl -u user -X MKCOL 'http://localhost:5232/user/addressbook' --data \
    -        '<?xml version="1.0" encoding="UTF-8" ?>
    -        <create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav">
    -          <set>
    -            <prop>
    -              <resourcetype>
    -                <collection />
    -                <CR:addressbook />
    -              </resourcetype>
    -              <displayname>Address book</displayname>
    -              <CR:addressbook-description>Example address book</CR:addressbook-description>
    -            </prop>
    -          </set>
    -        </create>'
    +'<?xml version="1.0" encoding="UTF-8" ?> +<create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav"> + <set> + <prop> + <resourcetype> + <collection /> + <CR:addressbook /> + </resourcetype> + <displayname>Address book</displayname> + <CR:addressbook-description>Example address book</CR:addressbook-description> + </prop> + </set> +</create>'

    The collection /USERNAME will be created automatically, when the user authenticates to Radicale for the first time. Clients with automatic discovery of collections will only show calendars and address books that are direct children of the path /USERNAME/.

    Delete the collections by running something like:

    $ curl -u user -X DELETE 'http://localhost:5232/user/calendar'
    @@ -871,15 +871,15 @@

    Radicale can be configured with a configuration file or with command line arguments.

    An example configuration file looks like:

    [server]
    -        # Bind all addresses
    -        hosts = 0.0.0.0:5232
    -        
    -        [auth]
    -        type = htpasswd
    -        htpasswd_filename = /path/to/users
    -        htpasswd_encryption = bcrypt
    -        [storage]
    -        filesystem_folder = ~/.var/lib/radicale/collections
    +# Bind all addresses +hosts = 0.0.0.0:5232 + +[auth] +type = htpasswd +htpasswd_filename = /path/to/users +htpasswd_encryption = bcrypt +[storage] +filesystem_folder = ~/.var/lib/radicale/collections

    Radicale tries to load configuration files from /etc/radicale/config, ~/.config/radicale/config and the RADICALE_CONFIG environment variable. This behaviour can be overwritten by specifying a path with the --config /path/to/config command line argument.

    The same example configuration via command line arguments looks like:

    python3 -m radicale --config "" --server-hosts 0.0.0.0:5232 --auth-type htpasswd --htpasswd-filename /path/to/htpasswd --htpasswd-encryption bcrypt
    @@ -995,7 +995,7 @@

    Available methods:

    plain : Passwords are stored in plaintext. This is obviously not secure! The htpasswd file for this can be created by hand and looks like:

    user1:password1
    -        user2:password2
    +user2:password2

    bcrypt : This uses a modified version of the Blowfish stream cipher. It's very secure. The passlib python module is required for this. Additionally you may need one of the following python modules: bcrypt, py-bcrypt or bcryptor.

    md5 : This uses an iterated md5 digest of the password with a salt. The passlib python module is required for this.

    sha1 : Passwords are stored as SHA1 hashes. It's insecure!

    @@ -1110,28 +1110,28 @@

    The recommended rights method is owner_only. If access to calendars and address books outside of the home directory of users (that's /USERNAME/) is granted, clients won't detect these collections and will not show them to the user. This is only useful if you access calendars and address books directly via URL.

    An example rights file:

    # The user "admin" can read and write any collection.
    -        [admin]
    -        user = admin
    -        collection = .*
    -        permission = rw
    -        
    -        # Block access for the user "user" to everything.
    -        [block]
    -        user = user
    -        collection = .*
    -        permission =
    -        
    -        # Authenticated users can read and write their own collections.
    -        [owner-write]
    -        user = .+
    -        collection = %(login)s(/.*)?
    -        permission = rw
    -        
    -        # Everyone can read the root collection
    -        [read]
    -        user = .*
    -        collection =
    -        permission = r
    +[admin] +user = admin +collection = .* +permission = rw + +# Block access for the user "user" to everything. +[block] +user = user +collection = .* +permission = + +# Authenticated users can read and write their own collections. +[owner-write] +user = .+ +collection = %(login)s(/.*)? +permission = rw + +# Everyone can read the root collection +[read] +user = .* +collection = +permission = r

    The titles of the sections are ignored (but must be unique). The keys user and collection contain regular expressions, that are matched against the user name and the path of the collection. Permissions from the first matching section are used. If no section matches, access gets denied.

    The user name is empty for anonymous users. Therefore, the regex .+ only matches authenticated users and .* matches everyone (including anonymous users).

    The path of the collection is separated by / and has no leading or trailing /. Therefore, the path of the root collection is empty.

    @@ -1162,9 +1162,9 @@
    Linux shell scripts

    Use the flock utility.

    # Exclusive
    -        $ flock --exclusive /path/to/storage/.Radicale.lock COMMAND
    -        # Shared
    -        $ flock --shared /path/to/storage/.Radicale.lock COMMAND
    +$ flock --exclusive /path/to/storage/.Radicale.lock COMMAND +# Shared +$ flock --shared /path/to/storage/.Radicale.lock COMMAND
    Linux and MacOS
    @@ -1186,27 +1186,27 @@

    Logging to a file

    An example configuration to write the log output to the file /var/log/radicale/log:

    [loggers]
    -        keys = root
    -        
    -        [handlers]
    -        keys = file
    -        
    -        [formatters]
    -        keys = full
    -        
    -        [logger_root]
    -        # Change this to DEBUG or INFO for higher verbosity.
    -        level = WARNING
    -        handlers = file
    -        
    -        [handler_file]
    -        class = FileHandler
    -        # Specify the output file here.
    -        args = ('/var/log/radicale/log',)
    -        formatter = full
    -        
    -        [formatter_full]
    -        format = %(asctime)s - [%(thread)x] %(levelname)s: %(message)s
    +keys = root + +[handlers] +keys = file + +[formatters] +keys = full + +[logger_root] +# Change this to DEBUG or INFO for higher verbosity. +level = WARNING +handlers = file + +[handler_file] +class = FileHandler +# Specify the output file here. +args = ('/var/log/radicale/log',) +formatter = full + +[formatter_full] +format = %(asctime)s - [%(thread)x] %(levelname)s: %(message)s

    You can specify multiple logger, handler and formatter if you want to have multiple simultaneous log outputs.

    The parent folder of the log files must exist and must be writable by Radicale.

    Security: The log files should not be readable by unauthorized users. Set permissions accordingly.

    @@ -1214,23 +1214,23 @@
    Timed rotation of disk log files

    An example handler configuration to write the log output to the file /var/log/radicale/log and rotate it. Replace the section handler_file from the file logging example:

    [handler_file]
    -        class = handlers.TimedRotatingFileHandler
    -        # Specify the output file and parameter for rotation here.
    -        # See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler
    -        # Example: rollover at midnight and keep 7 files (means one week)
    -        args = ('/var/log/radicale/log', 'midnight', 1, 7)
    -        formatter = full
    +class = handlers.TimedRotatingFileHandler +# Specify the output file and parameter for rotation here. +# See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler +# Example: rollover at midnight and keep 7 files (means one week) +args = ('/var/log/radicale/log', 'midnight', 1, 7) +formatter = full
    Rotation of disk log files based on size

    An example handler configuration to write the log output to the file /var/log/radicale/log and rotate it . Replace the section handle_file from the file logging example:

    [handler_file]
    -        class = handlers.RotatingFileHandler
    -        # Specify the output file and parameter for rotation here.
    -        # See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.RotatingFileHandler
    -        # Example: rollover at 100000 kB and keep 10 files (means 1 MB)
    -        args = ('/var/log/radicale/log', 'a', 100000, 10)
    -        formatter = full
    +class = handlers.RotatingFileHandler +# Specify the output file and parameter for rotation here. +# See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.RotatingFileHandler +# Example: rollover at 100000 kB and keep 10 files (means 1 MB) +args = ('/var/log/radicale/log', 'a', 100000, 10) +formatter = full
    @@ -1306,33 +1306,33 @@

    To get started we walk through the creation of a simple authentication plugin, that accepts login attempts if the username and password are equal.

    The easiest way to develop and install python modules is Distutils. For a minimal setup create the file setup.py with the following content in an empty folder:

    #!/usr/bin/env python3
    -        
    -        from distutils.core import setup
    -        
    -        setup(name="radicale_silly_auth", packages=["radicale_silly_auth"])
    + +from distutils.core import setup + +setup(name="radicale_silly_auth", packages=["radicale_silly_auth"])

    In the same folder create the sub-folder radicale_silly_auth. The folder must have the same name as specified in packages above.

    Create the file __init__.py in the radicale_silly_auth folder with the following content:

    from radicale.auth import BaseAuth
    -        
    -        
    -        class Auth(BaseAuth):
    -            def is_authenticated(self, user, password):
    -                # Example custom configuration option
    -                foo = ""
    -                if self.configuration.has_option("auth", "foo"):
    -                    foo = self.configuration.get("auth", "foo")
    -                self.logger.info("Configuration option %r is %r", "foo", foo)
    -        
    -                # Check authentication
    -                self.logger.info("Login attempt by %r with password %r",
    -                                 user, password)
    -                return user == password
    + + +class Auth(BaseAuth): + def is_authenticated(self, user, password): + # Example custom configuration option + foo = "" + if self.configuration.has_option("auth", "foo"): + foo = self.configuration.get("auth", "foo") + self.logger.info("Configuration option %r is %r", "foo", foo) + + # Check authentication + self.logger.info("Login attempt by %r with password %r", + user, password) + return user == password

    Install the python module by running the following command in the same folder as setup.py:

    python3 -m pip install --upgrade .

    To make use this great creation in Radicale, set the configuration option type in the auth section to radicale_silly_auth:

    [auth]
    -        type = radicale_silly_auth
    -        foo = bar
    +type = radicale_silly_auth +foo = bar

    You can uninstall the module with:

    python3 -m pip uninstall radicale_silly_auth
    @@ -1708,13 +1708,13 @@

    This release is compatible with version 2.0.0. Follow our migration guide if you want to switch from 1.x.x to 2.1.0.