<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15404] CalendarServer/trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15404">15404</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-12-18 12:02:34 -0800 (Fri, 18 Dec 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>New tool to dump the default config to a plist file, preserving key order and comments from the Python source.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkconfcaldavdstdconfigplist">CalendarServer/trunk/conf/caldavd-stdconfig.plist</a></li>
<li><a href="#CalendarServertrunktwistedcaldavstdconfigpy">CalendarServer/trunk/twistedcaldav/stdconfig.py</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#CalendarServertrunktwistedcaldavdumpconfigpy">CalendarServer/trunk/twistedcaldav/dumpconfig.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavtesttest_dumpconfigpy">CalendarServer/trunk/twistedcaldav/test/test_dumpconfig.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkconfcaldavdstdconfigplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/caldavd-stdconfig.plist (15403 => 15404)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/caldavd-stdconfig.plist        2015-12-17 20:18:32 UTC (rev 15403)
+++ CalendarServer/trunk/conf/caldavd-stdconfig.plist        2015-12-18 20:02:34 UTC (rev 15404)
</span><span class="lines">@@ -19,180 +19,337 @@
</span><span class="cx"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
</span><span class="cx"> <plist version="1.0">
</span><span class="cx"> <dict>
</span><del>-        <!-- Public network address information -->
</del><ins>+        <!-- Public network address information
+
+         This is the server's public network address, which is provided to clients
+         in URLs and the like. It may or may not be the network address that the
+         server is listening to directly, though it is by default. For example, it
+         may be the address of a load balancer or proxy which forwards connections
+         to the server. -->
+
+        <!-- Network host name. -->
</ins><span class="cx">         <key>ServerHostName</key>
</span><span class="cx">         <string></string>
</span><ins>+
+        <!-- HTTP port (0 to disable HTTP) -->
</ins><span class="cx">         <key>HTTPPort</key>
</span><span class="cx">         <integer>0</integer>
</span><ins>+
+        <!-- SSL port (0 to disable HTTPS) -->
</ins><span class="cx">         <key>SSLPort</key>
</span><span class="cx">         <integer>0</integer>
</span><ins>+
+        <!-- Whether to listen on SSL port(s) -->
</ins><span class="cx">         <key>EnableSSL</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- If True, all nonSSL requests redirected to an SSL Port -->
</ins><span class="cx">         <key>RedirectHTTPToHTTPS</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD -->
</ins><span class="cx">         <key>SSLMethod</key>
</span><span class="cx">         <string>SSLv23_METHOD</string>
</span><ins>+
</ins><span class="cx">         <key>SSLCiphers</key>
</span><span class="cx">         <string>RC4-SHA:HIGH:!ADH</string>
</span><span class="cx">
</span><ins>+        <!-- Max-age value for Strict-Transport-Security header; set to 0 to disable
+         header. -->
</ins><span class="cx">         <key>StrictTransportSecuritySeconds</key>
</span><span class="cx">         <integer>604800</integer>
</span><span class="cx">
</span><del>-        <!-- Network address configuration information -->
</del><ins>+        <!-- Network address configuration information.
+
+         This configures the actual network address that the server binds to. -->
+
</ins><span class="cx">         <key>SocketFiles</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><ins>+
+                <!-- Socket file to listen for secure requests on -->
+                <key>Secured</key>
+                <string>secured.sock</string>
+
+                <!-- Socket file to listen for insecure requests on -->
+                <key>Unsecured</key>
+                <string>unsecured.sock</string>
+
+                <key>Owner</key>
+                <string></string>
+
</ins><span class="cx">                 <key>Group</key>
</span><span class="cx">                 <string></string>
</span><del>-                <key>Owner</key>
-                <string></string>
</del><ins>+
</ins><span class="cx">                 <key>Permissions</key>
</span><span class="cx">                 <integer>504</integer>
</span><del>-                <key>Secured</key>
-                <string>secured.sock</string>
-                <key>Unsecured</key>
-                <string>unsecured.sock</string>
</del><span class="cx">         </dict>
</span><ins>+
</ins><span class="cx">         <key>SocketRoot</key>
</span><span class="cx">         <string>/tmp/calendarserver</string>
</span><span class="cx">
</span><ins>+        <!-- List of IP addresses to bind to [empty = all] -->
</ins><span class="cx">         <key>BindAddresses</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- List of port numbers to bind to for HTTP [empty = same as "Port"] -->
</ins><span class="cx">         <key>BindHTTPPorts</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- List of port numbers to bind to for SSL [empty = same as "SSLPort"] -->
</ins><span class="cx">         <key>BindSSLPorts</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- File descriptors to inherit for HTTP requests [empty = don't inherit] -->
</ins><span class="cx">         <key>InheritFDs</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- File descriptors to inherit for HTTPS requests [empty = don't inherit] -->
</ins><span class="cx">         <key>InheritSSLFDs</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- Inherited file descriptor to call recvmsg() on to receive sockets (none =
+         don't inherit) -->
</ins><span class="cx">         <key>MetaFD</key>
</span><span class="cx">         <integer>0</integer>
</span><ins>+
+        <!-- Use a 'meta' FD, i.e. an FD to transmit other FDs to slave processes. -->
</ins><span class="cx">         <key>UseMetaFD</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><del>-        <!-- Database configuration -->
</del><ins>+        <!-- True: database; False: files -->
</ins><span class="cx">         <key>UseDatabase</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- Timeout transactions that take longer than the specified number of
+         seconds. Zero means no timeouts. 5 minute default. -->
</ins><span class="cx">         <key>TransactionTimeoutSeconds</key>
</span><span class="cx">         <integer>300</integer>
</span><span class="cx">
</span><ins>+        <!-- When a transactions times out tell HTTP clients clients to retry after
+         this amount of time -->
</ins><span class="cx">         <key>TransactionHTTPRetrySeconds</key>
</span><span class="cx">         <integer>300</integer>
</span><span class="cx">
</span><ins>+        <!-- 2 possible values: empty, meaning 'spawn postgres yourself', or
+         'postgres', meaning 'connect to a postgres database as specified by the
+         'DSN' configuration key. Will support more values in the future. -->
</ins><span class="cx">         <key>DBType</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- The username to use when DBType is empty -->
</ins><span class="cx">         <key>SpawnedDBUser</key>
</span><span class="cx">         <string>caldav</string>
</span><span class="cx">
</span><ins>+        <!-- Used to connect to an external database if DBType is non-empty -->
</ins><span class="cx">         <key>DatabaseConnection</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Database connection endpoint -->
+                <key>endpoint</key>
+                <string></string>
+
+                <!-- Name of database or Oracle SID -->
</ins><span class="cx">                 <key>database</key>
</span><span class="cx">                 <string></string>
</span><del>-                <key>endpoint</key>
</del><ins>+
+                <!-- User name to connect as -->
+                <key>user</key>
</ins><span class="cx">                 <string></string>
</span><ins>+
+                <!-- Password to use -->
</ins><span class="cx">                 <key>password</key>
</span><span class="cx">                 <string></string>
</span><del>-                <key>user</key>
-                <string></string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><ins>+        <!-- Internally used by database to tell slave processes to inherit a file
+         descriptor and use it as an AMP connection over a UNIX socket; see
+         twext.enterprise.adbapi2.ConnectionPoolConnection -->
</ins><span class="cx">         <key>DBAMPFD</key>
</span><span class="cx">         <integer>0</integer>
</span><span class="cx">
</span><ins>+        <!-- Use a shared database connection pool in the master process, rather than
+         having each client make its connections directly. -->
</ins><span class="cx">         <key>SharedConnectionPool</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- Set to True to prevent the server or utility tools from running if the
+         database needs a schema upgrade. -->
</ins><span class="cx">         <key>FailIfUpgradeNeeded</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- Set to True to check the current database schema against the schema file
+         matching the database schema version. -->
+        <key>CheckExistingSchema</key>
+        <false/>
+
+        <!-- When upgrading, only upgrade homes where the owner UID starts with the
+         specified prefix. The upgrade will only be partial and only apply to
+         upgrade pieces that affect entire homes. The upgrade will need to be run
+         again without this prefix set to complete the overall upgrade. -->
</ins><span class="cx">         <key>UpgradeHomePrefix</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><span class="cx">         <!-- Work queue configuration information -->
</span><ins>+
</ins><span class="cx">         <key>WorkQueue</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Interval in seconds for job queue polling -->
+                <key>queuePollInterval</key>
+                <real>0.1</real>
+
+                <!-- Number of seconds before an assigned job is considered overdue -->
+                <key>queueOverdueTimeout</key>
+                <integer>300</integer>
+
+                <!-- Array of array that describe the threshold and new polling interval for
+                 job queue polling back off -->
+                <key>queuePollingBackoff</key>
+                <array>
+                        <array>
+                                <integer>60</integer>
+                                <integer>60</integer>
+                        </array>
+                        <array>
+                                <integer>5</integer>
+                                <integer>1</integer>
+                        </array>
+                </array>
+
+                <!-- Queue capacity (percentage) which causes job processing to halt -->
+                <key>overloadLevel</key>
+                <integer>95</integer>
+
+                <!-- Queue capacity (percentage) at which only high priority items are run -->
+                <key>highPriorityLevel</key>
+                <integer>80</integer>
+
+                <!-- Queue capacity (percentage) at which only high/medium priority items are
+                 run -->
+                <key>mediumPriorityLevel</key>
+                <integer>50</integer>
+
+                <!-- When a job fails, reschedule it this number of seconds in the future -->
</ins><span class="cx">                 <key>failureRescheduleInterval</key>
</span><span class="cx">                 <integer>60</integer>
</span><del>-                <key>highPriorityLevel</key>
-                <integer>80</integer>
</del><ins>+
+                <!-- When a job can't run because of a lock, reschedule it this number of
+                 seconds in the future -->
</ins><span class="cx">                 <key>lockRescheduleInterval</key>
</span><span class="cx">                 <integer>60</integer>
</span><del>-                <key>mediumPriorityLevel</key>
-                <integer>50</integer>
-                <key>overloadLevel</key>
-                <integer>95</integer>
-                <key>queueOverdueTimeout</key>
-                <integer>300</integer>
-                <key>queuePollInterval</key>
-                <real>0.1</real>
</del><ins>+
+                <!-- dict of work table name's, whose values are dicts containing "priority"
+                 and "weight" items to use for newly created work. -->
+                <key>workParameters</key>
+                <dict>
+                </dict>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Types of service provided -->
</span><ins>+
+        <!-- Enable CalDAV service -->
</ins><span class="cx">         <key>EnableCalDAV</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Enable CardDAV service -->
</ins><span class="cx">         <key>EnableCardDAV</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- When True override all other services and set the server into podding-only
+         mode -->
</ins><span class="cx">         <key>MigrationOnly</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><span class="cx">         <!-- Data store -->
</span><ins>+
</ins><span class="cx">         <key>ServerRoot</key>
</span><span class="cx">         <string>/var/db/caldavd</string>
</span><ins>+
</ins><span class="cx">         <key>DataRoot</key>
</span><span class="cx">         <string>Data</string>
</span><ins>+
</ins><span class="cx">         <key>DatabaseRoot</key>
</span><span class="cx">         <string>Database</string>
</span><ins>+
</ins><span class="cx">         <key>AttachmentsRoot</key>
</span><span class="cx">         <string>Attachments</string>
</span><ins>+
</ins><span class="cx">         <key>DocumentRoot</key>
</span><span class="cx">         <string>Documents</string>
</span><ins>+
</ins><span class="cx">         <key>ConfigRoot</key>
</span><span class="cx">         <string>Config</string>
</span><ins>+
</ins><span class="cx">         <key>LogRoot</key>
</span><span class="cx">         <string>/var/log/caldavd</string>
</span><ins>+
</ins><span class="cx">         <key>RunRoot</key>
</span><span class="cx">         <string>/var/run/caldavd</string>
</span><ins>+
</ins><span class="cx">         <key>WebCalendarRoot</key>
</span><span class="cx">         <string>/Applications/Server.app/Contents/ServerRoot/usr/share/collabd/webcal/public</string>
</span><span class="cx">
</span><del>-        <!-- Quotas -->
</del><ins>+        <!-- Quotas -->
+
+        <!-- Attachments -->
+        <!-- User attachment quota (in bytes - default 100MB) -->
</ins><span class="cx">         <key>UserQuota</key>
</span><span class="cx">         <integer>104857600</integer>
</span><ins>+
+        <!-- Maximum size for a single attachment (in bytes - default 10MB) -->
</ins><span class="cx">         <key>MaximumAttachmentSize</key>
</span><span class="cx">         <integer>10485760</integer>
</span><span class="cx">
</span><ins>+        <!-- Resource data -->
+        <!-- Maximum number of calendars/address books allowed in a home -->
</ins><span class="cx">         <key>MaxCollectionsPerHome</key>
</span><span class="cx">         <integer>50</integer>
</span><ins>+
+        <!-- Maximum number of resources in a calendar/address book -->
</ins><span class="cx">         <key>MaxResourcesPerCollection</key>
</span><span class="cx">         <integer>10000</integer>
</span><ins>+
+        <!-- Maximum resource size (in bytes) -->
</ins><span class="cx">         <key>MaxResourceSize</key>
</span><span class="cx">         <integer>1048576</integer>
</span><ins>+
+        <!-- Maximum number of unique attendees -->
</ins><span class="cx">         <key>MaxAttendeesPerInstance</key>
</span><span class="cx">         <integer>100</integer>
</span><ins>+
+        <!-- Maximum number of instances the server will index -->
</ins><span class="cx">         <key>MaxAllowedInstances</key>
</span><span class="cx">         <integer>3000</integer>
</span><span class="cx">
</span><ins>+        <!-- Set to URL path of wiki authentication service, e.g. "/auth", in order to
+         use javascript authentication dialog. Empty string indicates standard
+         browser authentication dialog should be used. -->
</ins><span class="cx">         <key>WebCalendarAuthPath</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- Define mappings of URLs to file system objects (directories or files) -->
</ins><span class="cx">         <key>Aliases</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><span class="cx">
</span><del>-        <!-- Directory service -->
</del><ins>+        <!-- Directory service
+
+         A directory service provides information about principals (e.g. users,
+         groups, locations and resources) to the server. -->
+
</ins><span class="cx">         <key>DirectoryService</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <key>type</key>
+                <string>xml</string>
+
</ins><span class="cx">                 <key>params</key>
</span><span class="cx">                 <dict>
</span><span class="cx">                         <key>recordTypes</key>
</span><span class="lines">@@ -200,24 +357,33 @@
</span><span class="cx">                                 <string>users</string>
</span><span class="cx">                                 <string>groups</string>
</span><span class="cx">                         </array>
</span><ins>+
</ins><span class="cx">                         <key>xmlFile</key>
</span><span class="cx">                         <string>accounts.xml</string>
</span><span class="cx">                 </dict>
</span><del>-                <key>type</key>
-                <string>xml</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>DirectoryRealmName</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- Apply an additional filter for attendee lookups where names must start
+         with the search tokens rather than just contain them. -->
</ins><span class="cx">         <key>DirectoryFilterStartsWith</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><del>-        <!-- Locations and Resources service -->
</del><ins>+        <!-- Locations and Resources service
+
+         Supplements the directory service with information about locations and
+         resources. -->
+
</ins><span class="cx">         <key>ResourceService</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <key>type</key>
+                <string>xml</string>
+
</ins><span class="cx">                 <key>params</key>
</span><span class="cx">                 <dict>
</span><span class="cx">                         <key>recordTypes</key>
</span><span class="lines">@@ -226,141 +392,217 @@
</span><span class="cx">                                 <string>resources</string>
</span><span class="cx">                                 <string>addresses</string>
</span><span class="cx">                         </array>
</span><ins>+
</ins><span class="cx">                         <key>xmlFile</key>
</span><span class="cx">                         <string>resources.xml</string>
</span><span class="cx">                 </dict>
</span><del>-                <key>type</key>
-                <string>xml</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><del>-        <!-- Augment service -->
</del><ins>+        <!-- Augment service
+
+         Augments for the directory service records to add calendar specific
+         attributes. -->
+
</ins><span class="cx">         <key>AugmentService</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>type</key>
+                <string>twistedcaldav.directory.augment.AugmentXMLDB</string>
+
</ins><span class="cx">                 <key>params</key>
</span><span class="cx">                 <dict>
</span><del>-                        <key>statSeconds</key>
-                        <integer>15</integer>
</del><span class="cx">                         <key>xmlFiles</key>
</span><span class="cx">                         <array>
</span><span class="cx">                                 <string>augments.xml</string>
</span><span class="cx">                         </array>
</span><ins>+
+                        <key>statSeconds</key>
+                        <integer>15</integer>
</ins><span class="cx">                 </dict>
</span><del>-                <key>type</key>
-                <string>twistedcaldav.directory.augment.AugmentXMLDB</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Proxies -->
</span><ins>+
+        <!-- Allows for initialization of the proxy database from an XML file -->
</ins><span class="cx">         <key>ProxyLoadFromFile</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><span class="cx">         <!-- Special principals -->
</span><ins>+
+        <!-- Principals with "DAV:all" access (relative URLs) -->
</ins><span class="cx">         <key>AdminPrincipals</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- Principals with "DAV:read" access (relative URLs) -->
</ins><span class="cx">         <key>ReadPrincipals</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
+        <!-- Create "proxy access" principals -->
</ins><span class="cx">         <key>EnableProxyPrincipals</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><span class="cx">         <!-- Permissions -->
</span><ins>+
+        <!-- Allow unauthenticated read access to / -->
</ins><span class="cx">         <key>EnableAnonymousReadRoot</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Allow unauthenticated read access to hierarchy -->
</ins><span class="cx">         <key>EnableAnonymousReadNav</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- Allow listing of principal collections -->
</ins><span class="cx">         <key>EnablePrincipalListings</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Render calendar collections as a monolithic iCalendar object -->
</ins><span class="cx">         <key>EnableMonolithicCalendars</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><span class="cx">         <!-- Client controls -->
</span><ins>+
+        <!-- List of regexes for clients to disallow -->
</ins><span class="cx">         <key>RejectClients</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><span class="cx">
</span><span class="cx">         <!-- Authentication -->
</span><ins>+
</ins><span class="cx">         <key>Authentication</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Clear text; best avoided -->
</ins><span class="cx">                 <key>Basic</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <key>Enabled</key>
+                        <true/>
+
+                        <!-- Advertised over non-SSL? -->
</ins><span class="cx">                         <key>AllowedOverWireUnencrypted</key>
</span><span class="cx">                         <false/>
</span><del>-                        <key>Enabled</key>
-                        <true/>
</del><span class="cx">                 </dict>
</span><ins>+
+                <!-- Digest challenge/response -->
</ins><span class="cx">                 <key>Digest</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <key>Enabled</key>
+                        <true/>
+
</ins><span class="cx">                         <key>Algorithm</key>
</span><span class="cx">                         <string>md5</string>
</span><ins>+
+                        <key>Qop</key>
+                        <string></string>
+
+                        <!-- Advertised over non-SSL? -->
</ins><span class="cx">                         <key>AllowedOverWireUnencrypted</key>
</span><span class="cx">                         <true/>
</span><del>-                        <key>Enabled</key>
-                        <true/>
-                        <key>Qop</key>
-                        <string></string>
</del><span class="cx">                 </dict>
</span><ins>+
+                <!-- Kerberos/SPNEGO -->
</ins><span class="cx">                 <key>Kerberos</key>
</span><span class="cx">                 <dict>
</span><del>-                        <key>AllowedOverWireUnencrypted</key>
-                        <true/>
</del><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <false/>
</span><ins>+
</ins><span class="cx">                         <key>ServicePrincipal</key>
</span><span class="cx">                         <string></string>
</span><ins>+
+                        <!-- Advertised over non-SSL? -->
+                        <key>AllowedOverWireUnencrypted</key>
+                        <true/>
</ins><span class="cx">                 </dict>
</span><ins>+
+                <!-- TLS Client Certificate -->
</ins><span class="cx">                 <key>ClientCertificate</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <key>Enabled</key>
+                        <false/>
+
+                        <!-- Advertised over non-SSL? -->
</ins><span class="cx">                         <key>AllowedOverWireUnencrypted</key>
</span><span class="cx">                         <true/>
</span><ins>+
+                        <!-- Always require a client cert -->
+                        <key>Required</key>
+                        <true/>
+
+                        <!-- Array of acceptable client cert CA file names -->
</ins><span class="cx">                         <key>CAFiles</key>
</span><span class="cx">                         <array>
</span><span class="cx">                         </array>
</span><del>-                        <key>Enabled</key>
-                        <false/>
-                        <key>Required</key>
-                        <true/>
</del><ins>+
+                        <!-- Send the list of acceptable CAs to the client -->
</ins><span class="cx">                         <key>SendCAsToClient</key>
</span><span class="cx">                         <true/>
</span><span class="cx">                 </dict>
</span><ins>+
</ins><span class="cx">                 <key>Wiki</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <key>Enabled</key>
+                        <false/>
+
</ins><span class="cx">                         <key>Cookie</key>
</span><span class="cx">                         <string>cc.collabd_session_guid</string>
</span><del>-                        <key>Enabled</key>
-                        <false/>
</del><ins>+
</ins><span class="cx">                         <key>EndpointDescriptor</key>
</span><span class="cx">                         <string>unix:path=/var/run/collabd</string>
</span><span class="cx">                 </dict>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Logging -->
</span><ins>+
+        <!-- Apache-style access log -->
</ins><span class="cx">         <key>AccessLogFile</key>
</span><span class="cx">         <string>access.log</string>
</span><ins>+
+        <!-- Server activity log -->
</ins><span class="cx">         <key>ErrorLogFile</key>
</span><span class="cx">         <string>error.log</string>
</span><ins>+
+        <!-- Agent activity log -->
</ins><span class="cx">         <key>AgentLogFile</key>
</span><span class="cx">         <string>agent.log</string>
</span><ins>+
+        <!-- Utility log - name will be dynamically changed to executable name -->
</ins><span class="cx">         <key>UtilityLogFile</key>
</span><del>-        <string>.log</string>
</del><ins>+        <string>utility.log</string>
+
+        <!-- True = use log file, False = stdout -->
</ins><span class="cx">         <key>ErrorLogEnabled</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Rotate error log after so many megabytes -->
</ins><span class="cx">         <key>ErrorLogRotateMB</key>
</span><span class="cx">         <integer>10</integer>
</span><ins>+
+        <!-- Retain this many error log files -->
</ins><span class="cx">         <key>ErrorLogMaxRotatedFiles</key>
</span><span class="cx">         <integer>5</integer>
</span><ins>+
+        <!-- Rotate error log when service starts -->
+        <key>ErrorLogRotateOnStart</key>
+        <false/>
+
</ins><span class="cx">         <key>PIDFile</key>
</span><span class="cx">         <string>caldavd.pid</string>
</span><ins>+
</ins><span class="cx">         <key>RotateAccessLog</key>
</span><span class="cx">         <false/>
</span><ins>+
</ins><span class="cx">         <key>EnableExtendedAccessLog</key>
</span><span class="cx">         <true/>
</span><ins>+
</ins><span class="cx">         <key>EnableExtendedTimingAccessLog</key>
</span><span class="cx">         <false/>
</span><ins>+
</ins><span class="cx">         <key>DefaultLogLevel</key>
</span><span class="cx">         <string></string>
</span><ins>+
</ins><span class="cx">         <key>LogLevels</key>
</span><span class="cx">         <dict>
</span><span class="cx">         </dict>
</span><ins>+
</ins><span class="cx">         <key>LogID</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><span class="lines">@@ -368,194 +610,304 @@
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>HTTP</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>iTIP</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>iTIP-VFREEBUSY</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>Implicit Errors</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>AutoScheduling</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>iSchedule</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>migration</key>
</span><span class="cx">                 <false/>
</span><span class="cx">         </dict>
</span><ins>+
</ins><span class="cx">         <key>AccountingPrincipals</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><ins>+
</ins><span class="cx">         <key>AccountingLogRoot</key>
</span><span class="cx">         <string>accounting</string>
</span><span class="cx">
</span><span class="cx">         <key>Stats</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>EnableUnixStatsSocket</key>
+                <false/>
+
+                <key>UnixStatsSocket</key>
+                <string>caldavd-stats.sock</string>
+
</ins><span class="cx">                 <key>EnableTCPStatsSocket</key>
</span><span class="cx">                 <false/>
</span><del>-                <key>EnableUnixStatsSocket</key>
-                <false/>
</del><ins>+
</ins><span class="cx">                 <key>TCPStatsPort</key>
</span><span class="cx">                 <integer>8100</integer>
</span><del>-                <key>UnixStatsSocket</key>
-                <string>caldavd-stats.sock</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>LogDatabase</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>LabelsInSQL</key>
</span><span class="cx">                 <false/>
</span><del>-                <key>SQLStatements</key>
-                <false/>
</del><ins>+
</ins><span class="cx">                 <key>Statistics</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>StatisticsLogFile</key>
</span><span class="cx">                 <string>sqlstats.log</string>
</span><ins>+
+                <key>SQLStatements</key>
+                <false/>
+
</ins><span class="cx">                 <key>TransactionWaitSeconds</key>
</span><span class="cx">                 <integer>0</integer>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- SSL/TLS -->
</span><ins>+
+        <!-- Public key -->
</ins><span class="cx">         <key>SSLCertificate</key>
</span><span class="cx">         <string></string>
</span><ins>+
+        <!-- Private key -->
</ins><span class="cx">         <key>SSLPrivateKey</key>
</span><span class="cx">         <string></string>
</span><ins>+
+        <!-- Certificate Authority Chain -->
</ins><span class="cx">         <key>SSLAuthorityChain</key>
</span><span class="cx">         <string></string>
</span><ins>+
</ins><span class="cx">         <key>SSLPassPhraseDialog</key>
</span><span class="cx">         <string>/etc/apache2/getsslpassphrase</string>
</span><ins>+
</ins><span class="cx">         <key>SSLCertAdmin</key>
</span><span class="cx">         <string>/Applications/Server.app/Contents/ServerRoot/usr/sbin/certadmin</string>
</span><span class="cx">
</span><ins>+        <!-- Keychain identity to use in place of cert files -->
+        <key>SSLKeychainIdentity</key>
+        <string></string>
+
</ins><span class="cx">         <!-- Process management -->
</span><ins>+
+        <!-- Username and Groupname to drop privileges to, if empty privileges will not
+         be dropped. -->
</ins><span class="cx">         <key>UserName</key>
</span><span class="cx">         <string></string>
</span><ins>+
</ins><span class="cx">         <key>GroupName</key>
</span><span class="cx">         <string></string>
</span><ins>+
+        <!-- Multi-process -->
</ins><span class="cx">         <key>ProcessType</key>
</span><span class="cx">         <string>Combined</string>
</span><ins>+
</ins><span class="cx">         <key>MultiProcess</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>ProcessCount</key>
+                <integer>0</integer>
+
</ins><span class="cx">                 <key>MinProcessCount</key>
</span><span class="cx">                 <integer>2</integer>
</span><ins>+
</ins><span class="cx">                 <key>PerCPU</key>
</span><span class="cx">                 <integer>1</integer>
</span><ins>+
</ins><span class="cx">                 <key>PerGB</key>
</span><span class="cx">                 <integer>1</integer>
</span><del>-                <key>ProcessCount</key>
-                <integer>0</integer>
</del><ins>+
</ins><span class="cx">                 <key>StaggeredStartup</key>
</span><span class="cx">                 <dict>
</span><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <false/>
</span><ins>+
</ins><span class="cx">                         <key>Interval</key>
</span><span class="cx">                         <integer>15</integer>
</span><span class="cx">                 </dict>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><ins>+        <!-- How large a spawned process is allowed to get before it's stopped -->
</ins><span class="cx">         <key>MemoryLimiter</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>Enabled</key>
+                <true/>
+
+                <!-- How often to check memory sizes (in seconds) -->
+                <key>Seconds</key>
+                <integer>60</integer>
+
+                <!-- Memory limit (RSS in bytes) -->
</ins><span class="cx">                 <key>Bytes</key>
</span><span class="cx">                 <integer>2147483648</integer>
</span><del>-                <key>Enabled</key>
-                <true/>
</del><ins>+
+                <!-- True: only take into account resident memory; False: include virtual
+                 memory -->
</ins><span class="cx">                 <key>ResidentOnly</key>
</span><span class="cx">                 <true/>
</span><del>-                <key>Seconds</key>
-                <integer>60</integer>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Service ACLs -->
</span><span class="cx">         <key>EnableSACLs</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- Make all data read-only -->
</ins><span class="cx">         <key>EnableReadOnlyServer</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><span class="cx">         <!-- Standard (or draft) WebDAV extensions -->
</span><ins>+
+        <!-- POST ;add-member extension -->
</ins><span class="cx">         <key>EnableAddMember</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- REPORT collection-sync -->
</ins><span class="cx">         <key>EnableSyncReport</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- REPORT collection-sync on home collections -->
</ins><span class="cx">         <key>EnableSyncReportHome</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Sync token includes config component -->
</ins><span class="cx">         <key>EnableConfigSyncToken</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- /.well-known resource -->
</ins><span class="cx">         <key>EnableWellKnown</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Extended calendar-query REPORT -->
</ins><span class="cx">         <key>EnableCalendarQueryExtended</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- Support Managed Attachments -->
</ins><span class="cx">         <key>EnableManagedAttachments</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- server-info document -->
+        <key>EnableServerInfo</key>
+        <false/>
+
</ins><span class="cx">         <!-- Generic CalDAV/CardDAV extensions -->
</span><ins>+
+        <!-- Allow clients to send/receive JSON jCal and jCard format data -->
</ins><span class="cx">         <key>EnableJSONData</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><span class="cx">         <!-- Non-standard CalDAV extensions -->
</span><ins>+
+        <!-- Calendar Drop Box -->
</ins><span class="cx">         <key>EnableDropBox</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- Private Events -->
</ins><span class="cx">         <key>EnablePrivateEvents</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- Old Timezone service -->
</ins><span class="cx">         <key>EnableTimezoneService</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- New standard timezone service -->
</ins><span class="cx">         <key>TimezoneService</key>
</span><span class="cx">         <dict>
</span><del>-                <key>BasePath</key>
-                <string></string>
</del><ins>+                <!-- Overall on/off switch -->
</ins><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <!-- URI where service is hosted -->
+                <key>URI</key>
+                <string>/stdtimezones</string>
+
+                <!-- Can be "primary" or "secondary" -->
</ins><span class="cx">                 <key>Mode</key>
</span><span class="cx">                 <string>primary</string>
</span><ins>+
+                <!-- Path to directory containing a zoneinfo - if None use default package
+                 path secondary service MUST define its own writable path -->
+                <key>BasePath</key>
+                <string></string>
+
+                <!-- Path to db cache info - if None use default package path secondary
+                 service MUST define its own writable path if not None -->
+                <key>XMLInfoPath</key>
+                <string></string>
+
+                <!-- User friendly JSON output -->
</ins><span class="cx">                 <key>PrettyPrintJSON</key>
</span><span class="cx">                 <true/>
</span><ins>+
</ins><span class="cx">                 <key>SecondaryService</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Only one of these should be used when a secondary service is used -->
+                        <!-- Domain/IP of secondary service to discover -->
</ins><span class="cx">                         <key>Host</key>
</span><span class="cx">                         <string></string>
</span><ins>+
+                        <!-- HTTP(s) URI to secondary service -->
</ins><span class="cx">                         <key>URI</key>
</span><span class="cx">                         <string></string>
</span><ins>+
</ins><span class="cx">                         <key>UpdateIntervalMinutes</key>
</span><span class="cx">                         <integer>1440</integer>
</span><span class="cx">                 </dict>
</span><del>-                <key>URI</key>
-                <string>/stdtimezones</string>
-                <key>XMLInfoPath</key>
-                <string></string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><ins>+        <!-- Strip out VTIMEZONES that are known -->
</ins><span class="cx">         <key>EnableTimezonesByReference</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Use timezone data from twistedcaldav.zoneinfo - don't copy to Data
+         directory -->
</ins><span class="cx">         <key>UsePackageTimezones</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- POST batch uploads -->
</ins><span class="cx">         <key>EnableBatchUpload</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Maximum number of resources in a batch POST -->
</ins><span class="cx">         <key>MaxResourcesBatchUpload</key>
</span><span class="cx">         <integer>100</integer>
</span><ins>+
+        <!-- Maximum size of a batch POST (10 MB) -->
</ins><span class="cx">         <key>MaxBytesBatchUpload</key>
</span><span class="cx">         <integer>10485760</integer>
</span><span class="cx">
</span><span class="cx">         <key>Sharing</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Overall on/off switch -->
</ins><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <!-- External (non-principal) sharees allowed -->
</ins><span class="cx">                 <key>AllowExternalUsers</key>
</span><span class="cx">                 <false/>
</span><span class="cx">
</span><span class="cx">                 <key>Calendars</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Calendar on/off switch -->
</ins><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <true/>
</span><ins>+
</ins><span class="cx">                         <key>IgnorePerUserProperties</key>
</span><span class="cx">                         <array>
</span><span class="cx">                                 <string>X-APPLE-STRUCTURED-LOCATION</string>
</span><span class="cx">                         </array>
</span><ins>+
</ins><span class="cx">                         <key>CollectionProperties</key>
</span><span class="cx">                         <dict>
</span><del>-                                <key>Global</key>
</del><ins>+                                <key>Shadowable</key>
</ins><span class="cx">                                 <array>
</span><ins>+                                        <string>{urn:ietf:params:xml:ns:caldav}calendar-description</string>
</ins><span class="cx">                                 </array>
</span><ins>+
</ins><span class="cx">                                 <key>ProxyOverride</key>
</span><span class="cx">                                 <array>
</span><span class="cx">                                         <string>{urn:ietf:params:xml:ns:caldav}calendar-description</string>
</span><span class="lines">@@ -563,15 +915,18 @@
</span><span class="cx">                                         <string>{http://apple.com/ns/ical/}calendar-color</string>
</span><span class="cx">                                         <string>{http://apple.com/ns/ical/}calendar-order</string>
</span><span class="cx">                                 </array>
</span><del>-                                <key>Shadowable</key>
</del><ins>+
+                                <key>Global</key>
</ins><span class="cx">                                 <array>
</span><del>-                                        <string>{urn:ietf:params:xml:ns:caldav}calendar-description</string>
</del><span class="cx">                                 </array>
</span><span class="cx">                         </dict>
</span><ins>+
</ins><span class="cx">                         <key>Groups</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- Calendar sharing to groups on/off switch -->
</ins><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <true/>
</span><ins>+
</ins><span class="cx">                                 <key>ReconciliationDelaySeconds</key>
</span><span class="cx">                                 <integer>5</integer>
</span><span class="cx">                         </dict>
</span><span class="lines">@@ -579,92 +934,135 @@
</span><span class="cx">
</span><span class="cx">                 <key>AddressBooks</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Address Book sharing on/off switch -->
</ins><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <false/>
</span><ins>+
</ins><span class="cx">                         <key>CollectionProperties</key>
</span><span class="cx">                         <dict>
</span><del>-                                <key>Global</key>
</del><ins>+                                <key>Shadowable</key>
</ins><span class="cx">                                 <array>
</span><ins>+                                        <string>{urn:ietf:params:xml:ns:carddav}addressbook-description</string>
</ins><span class="cx">                                 </array>
</span><ins>+
</ins><span class="cx">                                 <key>ProxyOverride</key>
</span><span class="cx">                                 <array>
</span><span class="cx">                                 </array>
</span><del>-                                <key>Shadowable</key>
</del><ins>+
+                                <key>Global</key>
</ins><span class="cx">                                 <array>
</span><del>-                                        <string>{urn:ietf:params:xml:ns:carddav}addressbook-description</string>
</del><span class="cx">                                 </array>
</span><span class="cx">                         </dict>
</span><ins>+
</ins><span class="cx">                         <key>Groups</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- Address Book Group sharing on/off switch -->
</ins><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <false/>
</span><span class="cx">                         </dict>
</span><span class="cx">                 </dict>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><ins>+        <!-- Only allow calendars to be created with a single component type If this is
+         on, it will also trigger an upgrade behavior that will split existing
+         calendars into multiples based on component type. If on, it will also
+         cause new accounts to provision with separate calendars for events and
+         tasks. -->
</ins><span class="cx">         <key>RestrictCalendarsToOneComponentType</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- Set of supported iCalendar components -->
</ins><span class="cx">         <key>SupportedComponents</key>
</span><span class="cx">         <array>
</span><span class="cx">                 <string>VEVENT</string>
</span><span class="cx">                 <string>VTODO</string>
</span><span class="cx">         </array>
</span><span class="cx">
</span><ins>+        <!-- Enable Trash Collection -->
</ins><span class="cx">         <key>EnableTrashCollection</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- Expose Trash Collection as a resource -->
</ins><span class="cx">         <key>ExposeTrashCollection</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- Perform upgrades - currently only the database to filesystem migration -
+         but in the future, hopefully all relevant upgrades - in parallel in
+         subprocesses. -->
</ins><span class="cx">         <key>ParallelUpgrades</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- During the upgrade phase of startup, rather than skipping homes found both
+         on the filesystem and in the database, merge the data from the filesystem
+         into the database homes. -->
</ins><span class="cx">         <key>MergeUpgrades</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- Support for default alarms generated by the server -->
</ins><span class="cx">         <key>EnableDefaultAlarms</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Remove duplicate alarms on PUT -->
</ins><span class="cx">         <key>RemoveDuplicateAlarms</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- Remove duplicate private comments on PUT -->
</ins><span class="cx">         <key>RemoveDuplicatePrivateComments</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><span class="cx">         <key>HostedStatus</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Decorate ATTENDEEs with the following parameter to indicate where the
+                 ATTENDEE is hosted, locally or externally. It's configurable and
+                 extensible in case we want to add more values. A value of empty string
+                 means no decoration. -->
</ins><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>Parameter</key>
</span><span class="cx">                 <string>X-APPLE-HOSTED-STATUS</string>
</span><ins>+
</ins><span class="cx">                 <key>Values</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <key>local</key>
+                        <string></string>
+
</ins><span class="cx">                         <key>external</key>
</span><span class="cx">                         <string>EXTERNAL</string>
</span><del>-                        <key>local</key>
-                        <string></string>
</del><span class="cx">                 </dict>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>RevisionCleanup</key>
</span><span class="cx">         <dict>
</span><del>-                <key>CleanupPeriodDays</key>
-                <real>2.0</real>
</del><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <!-- Number of days that a client sync report token is valid -->
</ins><span class="cx">                 <key>SyncTokenLifetimeDays</key>
</span><span class="cx">                 <real>14.0</real>
</span><ins>+
+                <!-- Number of days between revision cleanups -->
+                <key>CleanupPeriodDays</key>
+                <real>2.0</real>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>InboxCleanup</key>
</span><span class="cx">         <dict>
</span><del>-                <key>CleanupPeriodDays</key>
-                <real>2.0</real>
</del><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <!-- Number of days before deleting a new inbox item -->
+                <key>ItemLifetimeDays</key>
+                <real>14.0</real>
+
+                <!-- Number of days to keep an inbox item past the time when its referenced
+                 event ends -->
</ins><span class="cx">                 <key>ItemLifeBeyondEventEndDays</key>
</span><span class="cx">                 <real>14.0</real>
</span><del>-                <key>ItemLifetimeDays</key>
-                <real>14.0</real>
</del><ins>+
+                <!-- Number of days between inbox cleanups -->
+                <key>CleanupPeriodDays</key>
+                <real>2.0</real>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- CardDAV Features -->
</span><span class="lines">@@ -672,57 +1070,83 @@
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><del>-                <key>MaxQueryResults</key>
-                <integer>1000</integer>
-                <key>name</key>
-                <string>directory</string>
</del><ins>+
+                <key>type</key>
+                <string>twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService</string>
+
</ins><span class="cx">                 <key>params</key>
</span><span class="cx">                 <dict>
</span><del>-                        <key>addDSAttrXProperties</key>
-                        <false/>
-                        <key>additionalAttributes</key>
-                        <array>
-                        </array>
-                        <key>allowedAttributes</key>
-                        <array>
-                        </array>
-                        <key>appleInternalServer</key>
-                        <false/>
-                        <key>cacheQuery</key>
-                        <false/>
-                        <key>cacheTimeout</key>
-                        <integer>30</integer>
-                        <key>dsLocalCacheTimeout</key>
-                        <integer>30</integer>
-                        <key>fakeETag</key>
</del><ins>+                        <key>queryPeopleRecords</key>
</ins><span class="cx">                         <true/>
</span><del>-                        <key>ignoreSystemRecords</key>
</del><ins>+
+                        <key>peopleNode</key>
+                        <string>/Search/Contacts</string>
+
+                        <key>queryUserRecords</key>
</ins><span class="cx">                         <true/>
</span><del>-                        <key>liveQuery</key>
-                        <true/>
</del><ins>+
+                        <key>userNode</key>
+                        <string>/Search/Contacts</string>
+
</ins><span class="cx">                         <key>maxDSQueryRecords</key>
</span><span class="cx">                         <integer>0</integer>
</span><del>-                        <key>peopleNode</key>
-                        <string>/Search/Contacts</string>
</del><ins>+
</ins><span class="cx">                         <key>queryDSLocal</key>
</span><span class="cx">                         <false/>
</span><del>-                        <key>queryPeopleRecords</key>
</del><ins>+
+                        <key>ignoreSystemRecords</key>
</ins><span class="cx">                         <true/>
</span><del>-                        <key>queryUserRecords</key>
</del><ins>+
+                        <key>dsLocalCacheTimeout</key>
+                        <integer>30</integer>
+
+                        <key>liveQuery</key>
</ins><span class="cx">                         <true/>
</span><ins>+
+                        <key>fakeETag</key>
+                        <true/>
+
+                        <key>cacheQuery</key>
+                        <false/>
+
+                        <key>cacheTimeout</key>
+                        <integer>30</integer>
+
</ins><span class="cx">                         <key>standardizeSyntheticUIDs</key>
</span><span class="cx">                         <false/>
</span><del>-                        <key>userNode</key>
-                        <string>/Search/Contacts</string>
</del><ins>+
+                        <key>addDSAttrXProperties</key>
+                        <false/>
+
+                        <key>appleInternalServer</key>
+                        <false/>
+
+                        <key>additionalAttributes</key>
+                        <array>
+                        </array>
+
+                        <key>allowedAttributes</key>
+                        <array>
+                        </array>
</ins><span class="cx">                 </dict>
</span><del>-                <key>type</key>
-                <string>twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService</string>
</del><ins>+
+                <key>name</key>
+                <string>directory</string>
+
+                <key>MaxQueryResults</key>
+                <integer>1000</integer>
</ins><span class="cx">         </dict>
</span><ins>+
+        <!-- /directory resource exists -->
</ins><span class="cx">         <key>EnableSearchAddressBook</key>
</span><span class="cx">         <false/>
</span><ins>+
+        <!-- Anonymous users may access directory address book -->
</ins><span class="cx">         <key>AnonymousDirectoryAddressBookAccess</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- /XXX CardDAV -->
+
</ins><span class="cx">         <!-- Web-based administration -->
</span><span class="cx">         <key>EnableWebAdmin</key>
</span><span class="cx">         <true/>
</span><span class="lines">@@ -732,23 +1156,38 @@
</span><span class="cx">         <false/>
</span><span class="cx">
</span><span class="cx">         <!-- Scheduling related options -->
</span><ins>+
</ins><span class="cx">         <key>Scheduling</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>CalDAV</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Domain for mailto calendar user addresses on this server -->
</ins><span class="cx">                         <key>EmailDomain</key>
</span><span class="cx">                         <string></string>
</span><ins>+
+                        <!-- Domain for http calendar user addresses on this server -->
</ins><span class="cx">                         <key>HTTPDomain</key>
</span><span class="cx">                         <string></string>
</span><ins>+
+                        <!-- Regex patterns to match local calendar user addresses -->
</ins><span class="cx">                         <key>AddressPatterns</key>
</span><span class="cx">                         <array>
</span><span class="cx">                         </array>
</span><ins>+
+                        <!-- Whether to maintain compatibility with non-implicit mode -->
</ins><span class="cx">                         <key>OldDraftCompatibility</key>
</span><span class="cx">                         <true/>
</span><ins>+
+                        <!-- Whether to support older clients that do not use Schedule-Tag feature -->
</ins><span class="cx">                         <key>ScheduleTagCompatibility</key>
</span><span class="cx">                         <true/>
</span><ins>+
+                        <!-- Private comments from attendees to organizer -->
</ins><span class="cx">                         <key>EnablePrivateComments</key>
</span><span class="cx">                         <true/>
</span><ins>+
+                        <!-- Names of iCalendar properties that are preserved when an Attendee does
+                         an invite PUT -->
</ins><span class="cx">                         <key>PerAttendeeProperties</key>
</span><span class="cx">                         <array>
</span><span class="cx">                                 <string>X-APPLE-NEEDS-REPLY</string>
</span><span class="lines">@@ -757,177 +1196,346 @@
</span><span class="cx">                                 <string>X-APPLE-TRAVEL-RETURN-DURATION</string>
</span><span class="cx">                                 <string>X-APPLE-TRAVEL-RETURN</string>
</span><span class="cx">                         </array>
</span><ins>+
+                        <!-- Names of X- iCalendar properties that are sent from ORGANIZER to
+                         ATTENDEE -->
</ins><span class="cx">                         <key>OrganizerPublicProperties</key>
</span><span class="cx">                         <array>
</span><span class="cx">                                 <string>X-APPLE-DROPBOX</string>
</span><span class="cx">                                 <string>X-APPLE-STRUCTURED-LOCATION</string>
</span><span class="cx">                         </array>
</span><ins>+
+                        <!-- Names of X- iCalendar parameters that are sent from ORGANIZER to
+                         ATTENDEE -->
+                        <key>OrganizerPublicParameters</key>
+                        <array>
+                        </array>
+
+                        <!-- Names of X- iCalendar properties that are sent from ATTENDEE to
+                         ORGANIZER These are also implicitly added to OrganizerPublicProperties -->
+                        <key>AttendeePublicProperties</key>
+                        <array>
+                        </array>
+
+                        <!-- Names of X- iCalendar parameters that are sent from ATTENDEE to
+                         ORGANIZER These are also implicitly added to OrganizerPublicParameters -->
+                        <key>AttendeePublicParameters</key>
+                        <array>
+                        </array>
</ins><span class="cx">                 </dict>
</span><ins>+
</ins><span class="cx">                 <key>iSchedule</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- iSchedule protocol -->
</ins><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <false/>
</span><ins>+
+                        <!-- Reg-ex patterns to match iSchedule-able calendar user addresses -->
</ins><span class="cx">                         <key>AddressPatterns</key>
</span><span class="cx">                         <array>
</span><span class="cx">                         </array>
</span><ins>+
+                        <!-- iSchedule server configurations -->
</ins><span class="cx">                         <key>RemoteServers</key>
</span><span class="cx">                         <string>remoteservers.xml</string>
</span><ins>+
+                        <!-- Capabilities serial number -->
</ins><span class="cx">                         <key>SerialNumber</key>
</span><span class="cx">                         <integer>1</integer>
</span><ins>+
+                        <!-- File where a fake Bind zone exists for creating fake DNS results -->
</ins><span class="cx">                         <key>DNSDebug</key>
</span><span class="cx">                         <string></string>
</span><ins>+
+                        <!-- DKIM options -->
</ins><span class="cx">                         <key>DKIM</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- DKIM signing/verification enabled -->
</ins><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- Domain for DKIM (defaults to ServerHostName) -->
</ins><span class="cx">                                 <key>Domain</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- Selector for public key -->
</ins><span class="cx">                                 <key>KeySelector</key>
</span><span class="cx">                                 <string>ischedule</string>
</span><ins>+
+                                <!-- Signature algorithm (one of rsa-sha1 or rsa-sha256) -->
</ins><span class="cx">                                 <key>SignatureAlgorithm</key>
</span><span class="cx">                                 <string>rsa-sha256</string>
</span><ins>+
+                                <!-- This server's public key stored in DNS -->
</ins><span class="cx">                                 <key>UseDNSKey</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- This server's public key stored in HTTP /.well-known -->
</ins><span class="cx">                                 <key>UseHTTPKey</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- This server's public key manually exchanged with others -->
</ins><span class="cx">                                 <key>UsePrivateExchangeKey</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- Expiration time for signature verification -->
</ins><span class="cx">                                 <key>ExpireSeconds</key>
</span><span class="cx">                                 <integer>3600</integer>
</span><ins>+
+                                <!-- File where private key is stored -->
</ins><span class="cx">                                 <key>PrivateKeyFile</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- File where public key is stored -->
</ins><span class="cx">                                 <key>PublicKeyFile</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- Directory where private exchange public keys are stored -->
</ins><span class="cx">                                 <key>PrivateExchanges</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- Turn on protocol level debugging to return detailed information to the
+                                 requestor -->
</ins><span class="cx">                                 <key>ProtocolDebug</key>
</span><span class="cx">                                 <false/>
</span><span class="cx">                         </dict>
</span><span class="cx">                 </dict>
</span><ins>+
</ins><span class="cx">                 <key>iMIP</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Server-to-iMIP protocol -->
</ins><span class="cx">                         <key>Enabled</key>
</span><span class="cx">                         <false/>
</span><ins>+
</ins><span class="cx">                         <key>Sending</key>
</span><span class="cx">                         <dict>
</span><del>-                                <key>Address</key>
</del><ins>+                                <!-- SMTP server to relay messages through -->
+                                <key>Server</key>
</ins><span class="cx">                                 <string></string>
</span><del>-                                <key>Password</key>
-                                <string></string>
</del><ins>+
+                                <!-- SMTP server port to relay messages through -->
</ins><span class="cx">                                 <key>Port</key>
</span><span class="cx">                                 <integer>587</integer>
</span><del>-                                <key>Server</key>
</del><ins>+
+                                <!-- 'From' address for server -->
+                                <key>Address</key>
</ins><span class="cx">                                 <string></string>
</span><del>-                                <key>SuppressionDays</key>
-                                <integer>7</integer>
</del><ins>+
</ins><span class="cx">                                 <key>UseSSL</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- For account sending mail -->
</ins><span class="cx">                                 <key>Username</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- For account sending mail -->
+                                <key>Password</key>
+                                <string></string>
+
+                                <!-- Messages for events older than this may days are not sent -->
+                                <key>SuppressionDays</key>
+                                <integer>7</integer>
</ins><span class="cx">                         </dict>
</span><ins>+
</ins><span class="cx">                         <key>Receiving</key>
</span><span class="cx">                         <dict>
</span><del>-                                <key>Password</key>
</del><ins>+                                <!-- Server to retrieve email messages from -->
+                                <key>Server</key>
</ins><span class="cx">                                 <string></string>
</span><del>-                                <key>PollingSeconds</key>
-                                <integer>30</integer>
</del><ins>+
+                                <!-- Server port to retrieve email messages from -->
</ins><span class="cx">                                 <key>Port</key>
</span><span class="cx">                                 <integer>0</integer>
</span><del>-                                <key>Server</key>
-                                <string></string>
</del><ins>+
+                                <key>UseSSL</key>
+                                <true/>
+
+                                <!-- Type of message access server: 'pop' or 'imap' -->
</ins><span class="cx">                                 <key>Type</key>
</span><span class="cx">                                 <string></string>
</span><del>-                                <key>UseSSL</key>
-                                <true/>
</del><ins>+
+                                <!-- How often to fetch mail -->
+                                <key>PollingSeconds</key>
+                                <integer>30</integer>
+
+                                <!-- For account receiving mail -->
</ins><span class="cx">                                 <key>Username</key>
</span><span class="cx">                                 <string></string>
</span><ins>+
+                                <!-- For account receiving mail -->
+                                <key>Password</key>
+                                <string></string>
</ins><span class="cx">                         </dict>
</span><ins>+
+                        <!-- Regex patterns to match iMIP-able calendar user addresses -->
</ins><span class="cx">                         <key>AddressPatterns</key>
</span><span class="cx">                         <array>
</span><span class="cx">                         </array>
</span><ins>+
+                        <!-- Directory containing HTML templates for email invitations (invite.html,
+                         cancel.html) -->
</ins><span class="cx">                         <key>MailTemplatesDirectory</key>
</span><span class="cx">                         <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/email_templates</string>
</span><ins>+
+                        <!-- Directory containing language-specific subdirectories containing date-
+                         specific icons for email invitations -->
</ins><span class="cx">                         <key>MailIconsDirectory</key>
</span><span class="cx">                         <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/date_icons</string>
</span><ins>+
+                        <!-- How many days invitations are valid -->
</ins><span class="cx">                         <key>InvitationDaysToLive</key>
</span><span class="cx">                         <integer>90</integer>
</span><span class="cx">                 </dict>
</span><ins>+
</ins><span class="cx">                 <key>Options</key>
</span><span class="cx">                 <dict>
</span><ins>+                        <!-- Allow groups to be Organizers -->
</ins><span class="cx">                         <key>AllowGroupAsOrganizer</key>
</span><span class="cx">                         <false/>
</span><ins>+
+                        <!-- Allow locations to be Organizers -->
</ins><span class="cx">                         <key>AllowLocationAsOrganizer</key>
</span><span class="cx">                         <false/>
</span><ins>+
+                        <!-- Allow resources to be Organizers -->
+                        <key>AllowResourceAsOrganizer</key>
+                        <false/>
+
+                        <!-- Allow locations to have events without an Organizer -->
</ins><span class="cx">                         <key>AllowLocationWithoutOrganizer</key>
</span><span class="cx">                         <true/>
</span><del>-                        <key>AllowResourceAsOrganizer</key>
-                        <false/>
</del><ins>+
+                        <!-- Allow resources to have events without an Organizer -->
</ins><span class="cx">                         <key>AllowResourceWithoutOrganizer</key>
</span><span class="cx">                         <true/>
</span><ins>+
+                        <!-- Track who the last modifier of an unscheduled location event is -->
+                        <key>TrackUnscheduledLocationData</key>
+                        <true/>
+
+                        <!-- Track who the last modifier of an unscheduled resource event is -->
+                        <key>TrackUnscheduledResourceData</key>
+                        <true/>
+
+                        <!-- Maximum number of attendees to request freebusy for -->
+                        <key>LimitFreeBusyAttendees</key>
+                        <integer>30</integer>
+
+                        <!-- Number of attendees to do batched refreshes: 0 - no batching -->
</ins><span class="cx">                         <key>AttendeeRefreshBatch</key>
</span><span class="cx">                         <integer>5</integer>
</span><ins>+
+                        <!-- Number of attendees above which attendee refreshes are suppressed: 0 -
+                         no limit -->
</ins><span class="cx">                         <key>AttendeeRefreshCountLimit</key>
</span><span class="cx">                         <integer>50</integer>
</span><ins>+
+                        <!-- Time for implicit UID lock timeout -->
+                        <key>UIDLockTimeoutSeconds</key>
+                        <integer>60</integer>
+
+                        <!-- Expiration time for UID lock, -->
+                        <key>UIDLockExpirySeconds</key>
+                        <integer>300</integer>
+
+                        <!-- Host names matched in http(s) CUAs -->
+                        <key>PrincipalHostAliases</key>
+                        <array>
+                        </array>
+
+                        <!-- Add a time stamp when an Attendee changes their PARTSTAT -->
+                        <key>TimestampAttendeePartStatChanges</key>
+                        <true/>
+
+                        <!-- Delegates can get extra info in a freebusy request -->
+                        <key>DelegeteRichFreeBusy</key>
+                        <true/>
+
+                        <!-- Any user can get extra info for rooms/resources in a freebusy request -->
+                        <key>RoomResourceRichFreeBusy</key>
+                        <true/>
+
</ins><span class="cx">                         <key>AutoSchedule</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- Auto-scheduling will never occur if set to False -->
</ins><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- Override augments setting and always auto-schedule -->
+                                <key>Always</key>
+                                <false/>
+
+                                <!-- Allow auto-schedule for users -->
</ins><span class="cx">                                 <key>AllowUsers</key>
</span><span class="cx">                                 <false/>
</span><del>-                                <key>Always</key>
-                                <false/>
</del><ins>+
+                                <!-- Default mode for auto-schedule processing, one of: "none" -
+                                 no auto-scheduling "accept-always" - always accept, ignore busy time
+                                 "decline-always" - always decline, ignore free time "accept-if-free"
+                                 - accept if free, do nothing if busy "decline-if-busy" - decline if
+                                 busy, do nothing if free "automatic" - accept if free, decline if
+                                 busy -->
</ins><span class="cx">                                 <key>DefaultMode</key>
</span><span class="cx">                                 <string>automatic</string>
</span><ins>+
+                                <!-- How far into the future to check for booking conflicts -->
</ins><span class="cx">                                 <key>FutureFreeBusyDays</key>
</span><span class="cx">                                 <integer>1095</integer>
</span><span class="cx">                         </dict>
</span><del>-                        <key>DelegeteRichFreeBusy</key>
-                        <true/>
-                        <key>LimitFreeBusyAttendees</key>
-                        <integer>30</integer>
-                        <key>PrincipalHostAliases</key>
-                        <array>
-                        </array>
-                        <key>RoomResourceRichFreeBusy</key>
-                        <true/>
-                        <key>Splitting</key>
-                        <dict>
-                                <key>Enabled</key>
-                                <false/>
-                                <key>Delay</key>
-                                <integer>60</integer>
-                                <key>PastDays</key>
-                                <integer>14</integer>
-                                <key>Size</key>
-                                <integer>102400</integer>
-                        </dict>
-                        <key>TimestampAttendeePartStatChanges</key>
-                        <true/>
-                        <key>TrackUnscheduledLocationData</key>
-                        <true/>
-                        <key>TrackUnscheduledResourceData</key>
-                        <true/>
-                        <key>UIDLockExpirySeconds</key>
-                        <integer>300</integer>
-                        <key>UIDLockTimeoutSeconds</key>
-                        <integer>60</integer>
</del><ins>+
</ins><span class="cx">                         <key>WorkQueues</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- Work queues for scheduling enabled -->
</ins><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <true/>
</span><ins>+
+                                <!-- Number of seconds delay for a queued scheduling request/cancel -->
+                                <key>RequestDelaySeconds</key>
+                                <integer>5</integer>
+
+                                <!-- Number of seconds delay for a queued scheduling reply -->
+                                <key>ReplyDelaySeconds</key>
+                                <integer>1</integer>
+
+                                <!-- Time delay for sending an auto reply iTIP message -->
+                                <key>AutoReplyDelaySeconds</key>
+                                <integer>5</integer>
+
+                                <!-- Time after an iTIP REPLY for first batched attendee refresh -->
</ins><span class="cx">                                 <key>AttendeeRefreshBatchDelaySeconds</key>
</span><span class="cx">                                 <integer>5</integer>
</span><ins>+
+                                <!-- Time between attendee batch refreshes -->
</ins><span class="cx">                                 <key>AttendeeRefreshBatchIntervalSeconds</key>
</span><span class="cx">                                 <integer>5</integer>
</span><del>-                                <key>AutoReplyDelaySeconds</key>
-                                <integer>5</integer>
</del><ins>+
+                                <!-- Delay in seconds before a work item is executed again after a temp
+                                 failure -->
+                                <key>TemporaryFailureDelay</key>
+                                <integer>60</integer>
+
+                                <!-- Max number of temp failure retries before treating as a permanent
+                                 failure -->
</ins><span class="cx">                                 <key>MaxTemporaryFailures</key>
</span><span class="cx">                                 <integer>10</integer>
</span><del>-                                <key>ReplyDelaySeconds</key>
-                                <integer>1</integer>
-                                <key>RequestDelaySeconds</key>
-                                <integer>5</integer>
-                                <key>TemporaryFailureDelay</key>
</del><ins>+                        </dict>
+
+                        <key>Splitting</key>
+                        <dict>
+                                <!-- False for now whilst we experiment with this -->
+                                <key>Enabled</key>
+                                <false/>
+
+                                <!-- Consider splitting when greater than 100KB -->
+                                <key>Size</key>
+                                <integer>102400</integer>
+
+                                <!-- Number of days in the past where the split will occur -->
+                                <key>PastDays</key>
+                                <integer>14</integer>
+
+                                <!-- How many seconds to delay the split work item -->
+                                <key>Delay</key>
</ins><span class="cx">                                 <integer>60</integer>
</span><span class="cx">                         </dict>
</span><span class="cx">                 </dict>
</span><span class="lines">@@ -935,86 +1543,137 @@
</span><span class="cx">
</span><span class="cx">         <key>FreeBusyURL</key>
</span><span class="cx">         <dict>
</span><del>-                <key>AnonymousAccess</key>
-                <false/>
</del><ins>+                <!-- Per-user free-busy-url protocol -->
</ins><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><ins>+
+                <!-- Number of days into the future to generate f-b data if no explicit time-
+                 range is specified -->
</ins><span class="cx">                 <key>TimePeriod</key>
</span><span class="cx">                 <integer>14</integer>
</span><ins>+
+                <!-- Allow anonymous read access to free-busy URL -->
+                <key>AnonymousAccess</key>
+                <false/>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Notifications -->
</span><ins>+
</ins><span class="cx">         <key>Notifications</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>Enabled</key>
+                <false/>
+
</ins><span class="cx">                 <key>CoalesceSeconds</key>
</span><span class="cx">                 <integer>3</integer>
</span><del>-                <key>Enabled</key>
-                <false/>
</del><ins>+
</ins><span class="cx">                 <key>Services</key>
</span><span class="cx">                 <dict>
</span><span class="cx">                         <key>APNS</key>
</span><span class="cx">                         <dict>
</span><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <false/>
</span><ins>+
</ins><span class="cx">                                 <key>SubscriptionURL</key>
</span><span class="cx">                                 <string>apns</string>
</span><ins>+
+                                <!-- How often the client should re-register (2 days) -->
</ins><span class="cx">                                 <key>SubscriptionRefreshIntervalSeconds</key>
</span><span class="cx">                                 <integer>172800</integer>
</span><ins>+
+                                <!-- How often a purge is done (12 hours) -->
</ins><span class="cx">                                 <key>SubscriptionPurgeIntervalSeconds</key>
</span><span class="cx">                                 <integer>43200</integer>
</span><ins>+
+                                <!-- How old a subscription must be before it's purged (14 days) -->
</ins><span class="cx">                                 <key>SubscriptionPurgeSeconds</key>
</span><span class="cx">                                 <integer>1209600</integer>
</span><ins>+
</ins><span class="cx">                                 <key>ProviderHost</key>
</span><span class="cx">                                 <string>gateway.push.apple.com</string>
</span><ins>+
</ins><span class="cx">                                 <key>ProviderPort</key>
</span><span class="cx">                                 <integer>2195</integer>
</span><ins>+
</ins><span class="cx">                                 <key>FeedbackHost</key>
</span><span class="cx">                                 <string>feedback.push.apple.com</string>
</span><ins>+
</ins><span class="cx">                                 <key>FeedbackPort</key>
</span><span class="cx">                                 <integer>2196</integer>
</span><ins>+
+                                <!-- 8 hours -->
</ins><span class="cx">                                 <key>FeedbackUpdateSeconds</key>
</span><span class="cx">                                 <integer>28800</integer>
</span><ins>+
</ins><span class="cx">                                 <key>Environment</key>
</span><span class="cx">                                 <string>PRODUCTION</string>
</span><ins>+
</ins><span class="cx">                                 <key>EnableStaggering</key>
</span><span class="cx">                                 <false/>
</span><ins>+
</ins><span class="cx">                                 <key>StaggerSeconds</key>
</span><span class="cx">                                 <integer>3</integer>
</span><ins>+
</ins><span class="cx">                                 <key>CalDAV</key>
</span><span class="cx">                                 <dict>
</span><ins>+                                        <key>Enabled</key>
+                                        <false/>
+
+                                        <key>CertificatePath</key>
+                                        <string>Certificates/apns:com.apple.calendar.cert.pem</string>
+
+                                        <key>PrivateKeyPath</key>
+                                        <string>Certificates/apns:com.apple.calendar.key.pem</string>
+
</ins><span class="cx">                                         <key>AuthorityChainPath</key>
</span><span class="cx">                                         <string>Certificates/apns:com.apple.calendar.chain.pem</string>
</span><del>-                                        <key>CertificatePath</key>
-                                        <string>Certificates/apns:com.apple.calendar.cert.pem</string>
</del><ins>+
</ins><span class="cx">                                         <key>Passphrase</key>
</span><span class="cx">                                         <string></string>
</span><del>-                                        <key>PrivateKeyPath</key>
-                                        <string>Certificates/apns:com.apple.calendar.key.pem</string>
</del><ins>+
+                                        <key>KeychainIdentity</key>
+                                        <string>apns:com.apple.calendar</string>
+
</ins><span class="cx">                                         <key>Topic</key>
</span><span class="cx">                                         <string></string>
</span><span class="cx">                                 </dict>
</span><ins>+
</ins><span class="cx">                                 <key>CardDAV</key>
</span><span class="cx">                                 <dict>
</span><ins>+                                        <key>Enabled</key>
+                                        <false/>
+
+                                        <key>CertificatePath</key>
+                                        <string>Certificates/apns:com.apple.contact.cert.pem</string>
+
+                                        <key>PrivateKeyPath</key>
+                                        <string>Certificates/apns:com.apple.contact.key.pem</string>
+
</ins><span class="cx">                                         <key>AuthorityChainPath</key>
</span><span class="cx">                                         <string>Certificates/apns:com.apple.contact.chain.pem</string>
</span><del>-                                        <key>CertificatePath</key>
-                                        <string>Certificates/apns:com.apple.contact.cert.pem</string>
</del><ins>+
</ins><span class="cx">                                         <key>Passphrase</key>
</span><span class="cx">                                         <string></string>
</span><del>-                                        <key>PrivateKeyPath</key>
-                                        <string>Certificates/apns:com.apple.contact.key.pem</string>
</del><ins>+
+                                        <key>KeychainIdentity</key>
+                                        <string>apns:com.apple.contact</string>
+
</ins><span class="cx">                                         <key>Topic</key>
</span><span class="cx">                                         <string></string>
</span><span class="cx">                                 </dict>
</span><span class="cx">                         </dict>
</span><ins>+
</ins><span class="cx">                         <key>AMP</key>
</span><span class="cx">                         <dict>
</span><span class="cx">                                 <key>Enabled</key>
</span><span class="cx">                                 <false/>
</span><ins>+
</ins><span class="cx">                                 <key>Port</key>
</span><span class="cx">                                 <integer>62311</integer>
</span><ins>+
</ins><span class="cx">                                 <key>EnableStaggering</key>
</span><span class="cx">                                 <false/>
</span><ins>+
</ins><span class="cx">                                 <key>StaggerSeconds</key>
</span><span class="cx">                                 <integer>3</integer>
</span><span class="cx">                         </dict>
</span><span class="lines">@@ -1023,47 +1682,74 @@
</span><span class="cx">
</span><span class="cx">         <key>DirectoryProxy</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>SocketPath</key>
+                <string>directory-proxy.sock</string>
+
</ins><span class="cx">                 <key>InProcessCachingSeconds</key>
</span><span class="cx">                 <integer>60</integer>
</span><ins>+
</ins><span class="cx">                 <key>InSidecarCachingSeconds</key>
</span><span class="cx">                 <integer>120</integer>
</span><del>-                <key>SocketPath</key>
-                <string>directory-proxy.sock</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Support multiple hosts within a domain -->
</span><ins>+
</ins><span class="cx">         <key>Servers</key>
</span><span class="cx">         <dict>
</span><ins>+                <!-- Multiple servers enabled or not -->
</ins><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><del>-                <key>ConduitName</key>
-                <string>conduit</string>
</del><ins>+
+                <!-- File path for server information -->
</ins><span class="cx">                 <key>ConfigFile</key>
</span><span class="cx">                 <string>localservers.xml</string>
</span><ins>+
+                <!-- Pool size for connections between servers -->
+                <key>MaxClients</key>
+                <integer>5</integer>
+
+                <!-- Name for top-level inbox resource -->
</ins><span class="cx">                 <key>InboxName</key>
</span><span class="cx">                 <string>podding</string>
</span><del>-                <key>MaxClients</key>
-                <integer>5</integer>
</del><ins>+
+                <!-- Name for top-level cross-pod resource -->
+                <key>ConduitName</key>
+                <string>conduit</string>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Performance tuning -->
</span><ins>+
+        <!-- Set the maximum number of outstanding requests to this server. -->
</ins><span class="cx">         <key>MaxRequests</key>
</span><span class="cx">         <integer>3</integer>
</span><ins>+
</ins><span class="cx">         <key>MaxAccepts</key>
</span><span class="cx">         <integer>1</integer>
</span><span class="cx">
</span><ins>+        <!-- The maximum number of outstanding database connections per database
+         connection pool. When SharedConnectionPool (see above) is set to True,
+         this is the total number of outgoing database connections allowed to the
+         entire server; when SharedConnectionPool is False - this is the default -
+         this is the number of database connections used per worker process. -->
</ins><span class="cx">         <key>MaxDBConnectionsPerPool</key>
</span><span class="cx">         <integer>10</integer>
</span><span class="cx">
</span><span class="cx">         <key>ListenBacklog</key>
</span><span class="cx">         <integer>2024</integer>
</span><span class="cx">
</span><ins>+        <!-- Max. time between request lines -->
</ins><span class="cx">         <key>IncomingDataTimeOut</key>
</span><span class="cx">         <integer>60</integer>
</span><ins>+
+        <!-- Max. time between pipelined requests -->
</ins><span class="cx">         <key>PipelineIdleTimeOut</key>
</span><span class="cx">         <integer>15</integer>
</span><ins>+
+        <!-- Max. time for response processing -->
</ins><span class="cx">         <key>IdleConnectionTimeOut</key>
</span><span class="cx">         <integer>360</integer>
</span><ins>+
+        <!-- Max. time for client close -->
</ins><span class="cx">         <key>CloseConnectionTimeOut</key>
</span><span class="cx">         <integer>15</integer>
</span><span class="cx">
</span><span class="lines">@@ -1072,59 +1758,81 @@
</span><span class="cx">
</span><span class="cx">         <key>MaxMultigetWithDataHrefs</key>
</span><span class="cx">         <integer>5000</integer>
</span><ins>+
</ins><span class="cx">         <key>MaxQueryWithDataResults</key>
</span><span class="cx">         <integer>1000</integer>
</span><span class="cx">
</span><ins>+        <!-- How many results to return for principal-property-search REPORT requests -->
</ins><span class="cx">         <key>MaxPrincipalSearchReportResults</key>
</span><span class="cx">         <integer>500</integer>
</span><span class="cx">
</span><span class="cx">         <!-- Client fixes per user-agent match -->
</span><ins>+
</ins><span class="cx">         <key>ClientFixes</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>ForceAttendeeTRANSP</key>
</span><span class="cx">                 <array>
</span><del>-                        <string>iOS/8\.0(\..*)?</string>
-                        <string>iOS/8\.1(\..*)?</string>
-                        <string>iOS/8\.2(\..*)?</string>
</del><ins>+                        <string>iOS/8\\.0(\\..*)?</string>
+                        <string>iOS/8\\.1(\\..*)?</string>
+                        <string>iOS/8\\.2(\\..*)?</string>
</ins><span class="cx">                 </array>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <!-- Localization -->
</span><ins>+
</ins><span class="cx">         <key>Localization</key>
</span><span class="cx">         <dict>
</span><ins>+                <key>TranslationsDirectory</key>
+                <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/translations</string>
+
+                <key>LocalesDirectory</key>
+                <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/locales</string>
+
</ins><span class="cx">                 <key>Language</key>
</span><span class="cx">                 <string></string>
</span><del>-                <key>LocalesDirectory</key>
-                <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/locales</string>
-                <key>TranslationsDirectory</key>
-                <string>/Applications/Server.app/Contents/ServerRoot/usr/share/caldavd/share/translations</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><del>-        <!-- Implementation details -->
</del><ins>+        <!-- Implementation details
+
+         The following are specific to how the server is built, and useful for
+         development, but shouldn't be needed by users. -->
+
+        <!-- Twisted -->
</ins><span class="cx">         <key>Twisted</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>reactor</key>
</span><span class="cx">                 <string>select</string>
</span><span class="cx">         </dict>
</span><ins>+
+        <!-- Umask -->
</ins><span class="cx">         <key>umask</key>
</span><span class="cx">         <integer>18</integer>
</span><span class="cx">
</span><ins>+        <!-- A TCP port used for communication between the child and master processes
+         (bound to 127.0.0.1). Specify 0 to let OS assign a port. -->
</ins><span class="cx">         <key>ControlPort</key>
</span><span class="cx">         <integer>0</integer>
</span><span class="cx">
</span><ins>+        <!-- A unix socket used for communication between the child and master
+         processes. If blank, then an AF_INET socket is used instead. -->
</ins><span class="cx">         <key>ControlSocket</key>
</span><span class="cx">         <string>caldavd.sock</string>
</span><span class="cx">
</span><ins>+        <!-- Support for Content-Encoding compression options as specified in RFC2616
+         Section 3.5 Defaults off, because it weakens TLS (CRIME attack). -->
</ins><span class="cx">         <key>ResponseCompression</key>
</span><span class="cx">         <false/>
</span><span class="cx">
</span><ins>+        <!-- The retry-after value (in seconds) to return with a 503 error -->
</ins><span class="cx">         <key>HTTPRetryAfter</key>
</span><span class="cx">         <integer>180</integer>
</span><span class="cx">
</span><ins>+        <!-- Profiling options -->
</ins><span class="cx">         <key>Profiling</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>BaseDirectory</key>
</span><span class="cx">                 <string>/tmp/stats</string>
</span><span class="cx">         </dict>
</span><span class="lines">@@ -1133,88 +1841,136 @@
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>MaxClients</key>
</span><span class="cx">                 <integer>5</integer>
</span><ins>+
</ins><span class="cx">                 <key>Pools</key>
</span><span class="cx">                 <dict>
</span><span class="cx">                         <key>Default</key>
</span><span class="cx">                         <dict>
</span><ins>+                                <!-- A unix socket used for communication with memcached. If MemcacheSocket
+                                 is empty string, an AF_INET socket is used. -->
+                                <key>MemcacheSocket</key>
+                                <string>memcache.sock</string>
+
+                                <key>ClientEnabled</key>
+                                <true/>
+
+                                <key>ServerEnabled</key>
+                                <true/>
+
</ins><span class="cx">                                 <key>BindAddress</key>
</span><span class="cx">                                 <string>127.0.0.1</string>
</span><del>-                                <key>ClientEnabled</key>
-                                <true/>
</del><ins>+
+                                <key>Port</key>
+                                <integer>11311</integer>
+
+                                <!-- Possible types: "OpenDirectoryBacker", "ImplicitUIDLock",
+                                 "RefreshUIDLock", "DIGESTCREDENTIALS", "resourceInfoDB", "pubsubnodes",
+                                 "FBCache", "ScheduleAddressMapper", "SQL.props", "SQL.calhome",
+                                 "SQL.adbkhome", -->
</ins><span class="cx">                                 <key>HandleCacheTypes</key>
</span><span class="cx">                                 <array>
</span><span class="cx">                                         <string>Default</string>
</span><span class="cx">                                 </array>
</span><del>-                                <key>MemcacheSocket</key>
-                                <string>memcache.sock</string>
-                                <key>Port</key>
-                                <integer>11311</integer>
-                                <key>ServerEnabled</key>
-                                <true/>
</del><span class="cx">                         </dict>
</span><ins>+
+                        <!-- "Shared": { "ClientEnabled": True, "ServerEnabled": True, "BindAddress":
+                         "127.0.0.1", "Port": 11211, "HandleCacheTypes": [ "ProxyDB",
+                         "DelegatesDB", "PrincipalToken", ] }, -->
</ins><span class="cx">                 </dict>
</span><ins>+
+                <!-- Find in PATH -->
</ins><span class="cx">                 <key>memcached</key>
</span><span class="cx">                 <string>memcached</string>
</span><ins>+
+                <!-- Megabytes -->
</ins><span class="cx">                 <key>MaxMemory</key>
</span><span class="cx">                 <integer>0</integer>
</span><ins>+
</ins><span class="cx">                 <key>Options</key>
</span><span class="cx">                 <array>
</span><span class="cx">                 </array>
</span><ins>+
</ins><span class="cx">                 <key>ProxyDBKeyNormalization</key>
</span><span class="cx">                 <true/>
</span><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>Postgres</key>
</span><span class="cx">         <dict>
</span><del>-                <key>BuffersToConnectionsRatio</key>
-                <real>1.5</real>
</del><ins>+                <key>DatabaseName</key>
+                <string>caldav</string>
+
</ins><span class="cx">                 <key>ClusterName</key>
</span><span class="cx">                 <string>cluster</string>
</span><del>-                <key>Ctl</key>
-                <string>pg_ctl</string>
-                <key>DatabaseName</key>
-                <string>caldav</string>
-                <key>ExtraConnections</key>
-                <integer>3</integer>
-                <key>Init</key>
-                <string>initdb</string>
-                <key>ListenAddresses</key>
-                <array>
-                </array>
</del><ins>+
</ins><span class="cx">                 <key>LogFile</key>
</span><span class="cx">                 <string>postgres.log</string>
</span><ins>+
</ins><span class="cx">                 <key>LogRotation</key>
</span><span class="cx">                 <false/>
</span><ins>+
+                <key>SocketDirectory</key>
+                <string></string>
+
+                <key>SocketName</key>
+                <string></string>
+
+                <key>ListenAddresses</key>
+                <array>
+                </array>
+
+                <!-- BuffersToConnectionsRatio * MaxConnections Note: don't set this, it will
+                 be computed dynamically See _updateMultiProcess( ) below for details -->
+                <key>SharedBuffers</key>
+                <integer>0</integer>
+
+                <!-- Dynamically computed based on ProcessCount, etc. Note: don't set this, it
+                 will be computed dynamically See _updateMultiProcess( ) below for details -->
</ins><span class="cx">                 <key>MaxConnections</key>
</span><span class="cx">                 <integer>0</integer>
</span><ins>+
+                <!-- how many extra connections to leave for utilities -->
+                <key>ExtraConnections</key>
+                <integer>3</integer>
+
+                <key>BuffersToConnectionsRatio</key>
+                <real>1.5</real>
+
</ins><span class="cx">                 <key>Options</key>
</span><span class="cx">                 <array>
</span><span class="cx">                         <string>-c standard_conforming_strings=on</string>
</span><span class="cx">                 </array>
</span><del>-                <key>SharedBuffers</key>
-                <integer>0</integer>
-                <key>SocketDirectory</key>
-                <string></string>
-                <key>SocketName</key>
-                <string></string>
</del><ins>+
+                <!-- If the DBType is '', and we're spawning postgres ourselves, where is the
+                 pg_ctl tool to spawn it with? -->
+                <key>Ctl</key>
+                <string>pg_ctl</string>
+
+                <!-- If the DBType is '', and we're spawning postgres ourselves, where is the
+                 initdb tool to create its database cluster with? -->
+                <key>Init</key>
+                <string>initdb</string>
</ins><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>QueryCaching</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <key>MemcachedPool</key>
+                <string>Default</string>
+
</ins><span class="cx">                 <key>ExpireSeconds</key>
</span><span class="cx">                 <integer>3600</integer>
</span><del>-                <key>MemcachedPool</key>
-                <string>Default</string>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>GroupCaching</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
</ins><span class="cx">                 <key>UpdateSeconds</key>
</span><span class="cx">                 <integer>300</integer>
</span><ins>+
</ins><span class="cx">                 <key>UseDirectoryBasedDelegates</key>
</span><span class="cx">                 <false/>
</span><span class="cx">         </dict>
</span><span class="lines">@@ -1223,36 +1979,51 @@
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <key>ReconciliationDelaySeconds</key>
+                <integer>5</integer>
+
+                <!-- 1 hour -->
</ins><span class="cx">                 <key>AutoUpdateSecondsFromNow</key>
</span><span class="cx">                 <integer>3600</integer>
</span><del>-                <key>ReconciliationDelaySeconds</key>
-                <integer>5</integer>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>AutomaticPurging</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <true/>
</span><ins>+
+                <!-- 7 days -->
+                <key>PollingIntervalSeconds</key>
+                <integer>604800</integer>
+
+                <!-- No staggering -->
</ins><span class="cx">                 <key>CheckStaggerSeconds</key>
</span><span class="cx">                 <integer>0</integer>
</span><del>-                <key>GroupPurgeIntervalSeconds</key>
</del><ins>+
+                <!-- 7 days -->
+                <key>PurgeIntervalSeconds</key>
</ins><span class="cx">                 <integer>604800</integer>
</span><ins>+
</ins><span class="cx">                 <key>HomePurgeDelaySeconds</key>
</span><span class="cx">                 <integer>60</integer>
</span><del>-                <key>PollingIntervalSeconds</key>
</del><ins>+
+                <!-- 7 days -->
+                <key>GroupPurgeIntervalSeconds</key>
</ins><span class="cx">                 <integer>604800</integer>
</span><del>-                <key>PurgeIntervalSeconds</key>
-                <integer>604800</integer>
</del><span class="cx">         </dict>
</span><span class="cx">
</span><span class="cx">         <key>Manhole</key>
</span><span class="cx">         <dict>
</span><span class="cx">                 <key>Enabled</key>
</span><span class="cx">                 <false/>
</span><ins>+
</ins><span class="cx">                 <key>StartingPortNumber</key>
</span><span class="cx">                 <integer>5000</integer>
</span><ins>+
</ins><span class="cx">                 <key>DPSPortNumber</key>
</span><span class="cx">                 <integer>4999</integer>
</span><ins>+
</ins><span class="cx">                 <key>PasswordFilePath</key>
</span><span class="cx">                 <string></string>
</span><span class="cx">         </dict>
</span><span class="lines">@@ -1262,55 +2033,86 @@
</span><span class="cx">
</span><span class="cx">         <key>EnableResponseCache</key>
</span><span class="cx">         <true/>
</span><ins>+
+        <!-- Minutes -->
</ins><span class="cx">         <key>ResponseCacheTimeout</key>
</span><span class="cx">         <integer>30</integer>
</span><span class="cx">
</span><span class="cx">         <key>EnableFreeBusyCache</key>
</span><span class="cx">         <true/>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyCacheDaysBack</key>
</span><span class="cx">         <integer>7</integer>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyCacheDaysForward</key>
</span><span class="cx">         <integer>84</integer>
</span><span class="cx">
</span><span class="cx">         <key>FreeBusyIndexLowerLimitDays</key>
</span><span class="cx">         <integer>365</integer>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyIndexExpandAheadDays</key>
</span><span class="cx">         <integer>365</integer>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyIndexExpandMaxDays</key>
</span><span class="cx">         <integer>1825</integer>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyIndexDelayedExpand</key>
</span><span class="cx">         <false/>
</span><ins>+
</ins><span class="cx">         <key>FreeBusyIndexSmartUpdate</key>
</span><span class="cx">         <true/>
</span><span class="cx">
</span><ins>+        <!-- The RootResource uses a twext property store. Specify the class here -->
</ins><span class="cx">         <key>RootResourcePropStoreClass</key>
</span><span class="cx">         <string>txweb2.dav.xattrprops.xattrPropertyStore</string>
</span><span class="cx">
</span><ins>+        <!-- Used in the command line utilities to specify which service class to use
+         to carry out work. -->
</ins><span class="cx">         <key>UtilityServiceClass</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- Inbox items created more than MigratedInboxDaysCutoff days in the past are
+         removed during migration -->
</ins><span class="cx">         <key>MigratedInboxDaysCutoff</key>
</span><span class="cx">         <integer>60</integer>
</span><span class="cx">
</span><ins>+        <!-- The default timezone for the server; on OS X you can leave this empty and
+         the system's timezone will be used. If empty and not on OS X it will
+         default to America/Los_Angeles. -->
</ins><span class="cx">         <key>DefaultTimezone</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- After this many seconds of no admin requests, shutdown the agent. Zero
+         means no automatic shutdown. -->
</ins><span class="cx">         <key>AgentInactivityTimeoutSeconds</key>
</span><span class="cx">         <integer>300</integer>
</span><span class="cx">
</span><ins>+        <!-- Program to execute if the service cannot start; for example in OS X we
+         want to call serveradmin to disable the service so launchd does not keep
+         respawning it. Empty string to disable this feature. -->
</ins><span class="cx">         <key>ServiceDisablingProgram</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- Program to execute to post an alert to the administrator; for example in
+         OS X we want to call calendarserver_alert &lt;alert-type&gt; &lt;args&gt; -->
</ins><span class="cx">         <key>AlertPostingProgram</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- These three keys are relative to ConfigRoot: -->
+
+        <!-- Config to read first and merge -->
</ins><span class="cx">         <key>ImportConfig</key>
</span><span class="cx">         <string></string>
</span><span class="cx">
</span><ins>+        <!-- Other plists to parse after this one; note that an Include can change the
+         ServerRoot and/or ConfigRoot, thereby affecting the locations of the
+         following Includes in the list. (Useful for service directory relocation) -->
</ins><span class="cx">         <key>Includes</key>
</span><span class="cx">         <array>
</span><span class="cx">         </array>
</span><span class="cx">
</span><ins>+        <!-- Which config file calendarserver_config should write to for changes;
+         empty string means the main config file -->
</ins><span class="cx">         <key>WritableConfigFile</key>
</span><span class="cx">         <string></string>
</span><span class="cx"> </dict>
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavdumpconfigpy"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/twistedcaldav/dumpconfig.py (0 => 15404)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/dumpconfig.py         (rev 0)
+++ CalendarServer/trunk/twistedcaldav/dumpconfig.py        2015-12-18 20:02:34 UTC (rev 15404)
</span><span class="lines">@@ -0,0 +1,284 @@
</span><ins>+##
+# Copyright (c) 2015 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from cStringIO import StringIO
+from collections import OrderedDict
+from json.encoder import encode_basestring
+from plistlib import PlistWriter, _escapeAndEncode
+import json
+import os
+import re
+import textwrap
+
+def parseConfigItem(item):
+ """
+ Read the definition of a "DEFAULT_*" value from the stdconfig.py file so that we get
+ the literal Python source as a L{str} that we then then process into JSON.
+
+ @param item: the "DEFAULT_*" item to read
+ @type item: L{str}
+
+ @return: the "DEFAULT_*" value
+ @rtype: L{str}
+ """
+ with open(os.path.join(os.path.dirname(__file__), "stdconfig.py")) as f:
+ # Read up to the first line containing DEFAULT_*
+ while f.readline() != "{} = {{\n".format(item):
+ continue
+
+ # Build list of all lines up to the end of the DEFAULT_* definition and
+ # make it look like a JSON object
+ lines = ['{']
+ line = f.readline()
+ while line != "}\n":
+ lines.append(line[:-1])
+ line = f.readline()
+ lines.append('}')
+
+ return "\n".join(lines)
+
+
+
+def processConfig(configlines, with_comments=False, verbose=False, substitutions=None):
+ """
+ Process the "raw" config lines from stdconfig.py into a JSON object
+ (a Python L{dict}) that is ordered and contains commentary based on
+ the Python comments.
+
+ @param configlines: config data lines
+ @type configlines: L{list} of L{str}
+ @param with_comments: whether to include comments or not
+ @type with_comments: L{bool}
+ @param verbose: print out intermediate state
+ @type verbose: L{bool}
+
+ @return: the serialized JSON object
+ @rtype: L{OrderedDict}
+ """
+
+ # Comments will either be "block" (as in section dividers) or "inline"
+ # (as in appended to the end of the line). We treat these slightly
+ # differently wrt to whitespace and where they appear.
+ lines = []
+ ctr = 0
+ block_comment = []
+ inline_comment = []
+
+ # Regular expression to match an inline comment and a
+ # value containing a numeric expression that needs to be
+ # evaluated (e.g. "60 * 60")
+ comments = re.compile("([ ]*.*?,?)[ ]*#[ ]*(.*)[ ]*$")
+ value = re.compile("([^:]+:[ ]+)([0-9 \*]+)(.*)")
+
+ for line in configlines.splitlines():
+
+ if line.strip() and line.strip()[0] == "#":
+ # Line with just a comment is a block comment unless the
+ # previous comment was inline (in which case it is a multi-line
+ # inline). Aggregate block and inline comments into one overall
+ # comment.
+ comment = line.strip()[1:].strip()
+ if len(comment) == 0 and len(block_comment) == 0 and len(inline_comment) == 0:
+ pass
+ elif inline_comment:
+ inline_comment.append(comment if comment else "\n")
+ else:
+ block_comment.append(comment if comment else "\n")
+ continue
+ elif block_comment:
+ # Generate a block comment JSON member
+ if with_comments:
+ comment_type = "comment_" if line.strip() and block_comment[-1] != "\n" else "section_"
+ while block_comment[-1] == "\n":
+ block_comment.pop()
+ lines.append("\"{}{}\": {},".format(comment_type, ctr, encode_basestring(" ".join(block_comment))))
+ ctr += 1
+ block_comment = []
+ elif inline_comment:
+ # Generate an inline comment JSON member
+ if with_comments:
+ lines.insert(-1, "\"comment_{}\": {},".format(ctr, encode_basestring(" ".join(inline_comment))))
+ ctr += 1
+ inline_comment = []
+
+ # Check if the current line contains an inline comment, if so extract
+ # the comment and add to the current inline comments list
+ m = comments.match(line)
+ if m:
+ inline_comment.append(m.group(2))
+ append = m.group(1)
+ else:
+ append = line
+
+ # Do some simple value conversions
+ append = append.rstrip().replace(" None", ' ""').replace(" True", " true").replace(" False", " false").replace("\\", "\\\\")
+
+ # Look for special substitutions
+ if substitutions:
+ for subskey in substitutions.keys():
+ pos = append.find(subskey)
+ if pos >= 0:
+ actual = append[pos + len(subskey) + 2:]
+ comma = ""
+ if actual[-1] == ",":
+ actual = actual[:-1]
+ comma = ","
+ actual = actual[:-2]
+ append = "{}{}{}".format(
+ append[:pos],
+ json.dumps(substitutions[subskey][actual]),
+ comma,
+ )
+ break
+
+
+ # Look for numeric expressions in the value and eval() those to get a value
+ # that is compatible with JSON
+ m = value.match(append)
+ if m:
+ expression = eval(m.group(2))
+ append = "{}{}{}".format(m.group(1), expression, m.group(3))
+
+ # Remove trailing commas for the last items in an array
+ # or object as JSON does not like that
+ if append.strip() and append.strip()[0] in ("]", "}"):
+ if lines[-1][-1] == ",":
+ lines[-1] = lines[-1][:-1]
+
+ # Line is ready to use
+ lines.append(append)
+
+ newj = "\n".join(lines)
+ if verbose:
+ print(newj)
+
+ # Created an ordered JSON object
+ j = json.loads(newj, object_pairs_hook=OrderedDict)
+ return j
+
+
+
+class OrderedPlistWriter(PlistWriter):
+ """
+ L{PlistWriter} that maintains the order of dict items. It also handles special keys
+ "section_" and "comment_" which are used to insert XML comments in the plist output.
+ Some additional blank lines are also added for readability of the plist.
+ """
+
+ def writeDict(self, d):
+ """
+ Basically a copy of L{PlistWriter.writeDict} that does not sort the dict keys
+ if the dict type is L{OrderedDict}.
+ """
+ self.beginElement("dict")
+ items = d.items()
+ if not isinstance(d, OrderedDict):
+ items.sort()
+ newline = False
+ for key, value in items:
+ if not isinstance(key, (str, unicode)):
+ raise TypeError("keys must be strings")
+ if newline:
+ self.writeln("")
+ if key.startswith("section_"):
+ self.writeComment(value)
+ newline = True
+ elif key.startswith("comment_"):
+ self.writeComment(value)
+ newline = False
+ else:
+ self.simpleElement("key", key)
+ self.writeValue(value)
+ newline = True
+ self.endElement("dict")
+
+
+ def writeComment(self, comment):
+
+ indent = self.indentLevel * self.indent
+
+ paragraphs = comment.splitlines()
+ for ctr, paragraph in enumerate(comment.splitlines()):
+ line = _escapeAndEncode(paragraph).strip()
+ initial_indent = ("{}<!-- " if ctr == 0 else "{} ").format(indent)
+ subsequent_indent = "{} ".format(indent)
+
+ line = textwrap.fill(
+ line,
+ width=80,
+ initial_indent=initial_indent,
+ subsequent_indent=subsequent_indent,
+ )
+
+ if ctr == len(paragraphs) - 1:
+ self.file.write("{} -->\n".format(line))
+ else:
+ self.file.write("{}\n\n".format(line))
+
+
+
+def writeOrderedPlist(rootObject, pathOrFile):
+ """
+ A copy of L{plistlib.writePlist} that uses an L{OrderedPlistWriter} to
+ write the plist.
+ """
+
+ """Write 'rootObject' to a .plist file. 'pathOrFile' may either be a
+ file name or a (writable) file object.
+ """
+ didOpen = 0
+ if isinstance(pathOrFile, (str, unicode)):
+ pathOrFile = open(pathOrFile, "w")
+ didOpen = 1
+ writer = OrderedPlistWriter(pathOrFile)
+ writer.writeln("<plist version=\"1.0\">")
+ writer.writeValue(rootObject)
+ writer.writeln("</plist>")
+ if didOpen:
+ pathOrFile.close()
+
+
+
+def writeOrderedPlistToString(rootObject):
+ """
+ A copy of L{plistlib.writePlistToString} that uses an L{writeOrderedPlist} to
+ write the plist.
+ """
+
+ """Return 'rootObject' as a plist-formatted string.
+ """
+ f = StringIO()
+ writeOrderedPlist(rootObject, f)
+ return f.getvalue()
+
+if __name__ == '__main__':
+
+ # Generate a set of serialized JSON objects for the *_PARAMS config items
+ maps = {
+ "DEFAULT_SERVICE_PARAMS": "",
+ "DEFAULT_RESOURCE_PARAMS": "",
+ "DEFAULT_AUGMENT_PARAMS": "",
+ "DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS": "",
+ }
+
+ for item in maps.keys():
+ lines = parseConfigItem(item)
+ maps[item] = processConfig(lines, with_comments=True, verbose=False)
+
+ # Generate the plist for the default config, substituting for the *_PARAMS items
+ lines = parseConfigItem("DEFAULT_CONFIG")
+ j = processConfig(lines, with_comments=True, verbose=False, substitutions=maps)
+ print(writeOrderedPlistToString(j))
</ins></span></pre></div>
<a id="CalendarServertrunktwistedcaldavstdconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py (15403 => 15404)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/stdconfig.py        2015-12-17 20:18:32 UTC (rev 15403)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py        2015-12-18 20:02:34 UTC (rev 15404)
</span><span class="lines">@@ -57,15 +57,15 @@
</span><span class="cx">
</span><span class="cx"> DEFAULT_SERVICE_PARAMS = {
</span><span class="cx"> "xml": {
</span><del>- "recordTypes": ("users", "groups"),
</del><ins>+ "recordTypes": ["users", "groups"],
</ins><span class="cx"> "xmlFile": "accounts.xml",
</span><span class="cx"> },
</span><span class="cx"> "opendirectory": {
</span><del>- "recordTypes": ("users", "groups"),
</del><ins>+ "recordTypes": ["users", "groups"],
</ins><span class="cx"> "node": "/Search",
</span><span class="cx"> },
</span><span class="cx"> "ldap": {
</span><del>- "recordTypes": ("users", "groups"),
</del><ins>+ "recordTypes": ["users", "groups"],
</ins><span class="cx"> "uri": "ldap://localhost/",
</span><span class="cx"> "credentials": {
</span><span class="cx"> "dn": None,
</span><span class="lines">@@ -80,17 +80,17 @@
</span><span class="cx"> "addresses": "cn=addresses",
</span><span class="cx"> },
</span><span class="cx"> "mapping": {
</span><del>- "uid": ["apple-generateduid", ],
- "guid": ["apple-generateduid", ],
- "shortNames": ["uid", ],
- "fullNames": ["cn", ],
- "emailAddresses": ["mail", ],
- "memberDNs": ["uniqueMember", ],
</del><ins>+ "uid": ["apple-generateduid"],
+ "guid": ["apple-generateduid"],
+ "shortNames": ["uid"],
+ "fullNames": ["cn"],
+ "emailAddresses": ["mail"],
+ "memberDNs": ["uniqueMember"],
</ins><span class="cx"> "hasCalendars": [],
</span><span class="cx"> "autoScheduleMode": [],
</span><span class="cx"> "autoAcceptGroup": [],
</span><del>- "readWriteProxy": ["icsContact", ],
- "readOnlyProxy": ["icsSecondaryOwners", ],
</del><ins>+ "readWriteProxy": ["icsContact"],
+ "readOnlyProxy": ["icsSecondaryOwners"],
</ins><span class="cx"> "serviceNodeUID": [],
</span><span class="cx"> },
</span><span class="cx"> "extraFilters": {
</span><span class="lines">@@ -106,18 +106,18 @@
</span><span class="cx">
</span><span class="cx"> DEFAULT_RESOURCE_PARAMS = {
</span><span class="cx"> "xml": {
</span><del>- "recordTypes": ("locations", "resources", "addresses"),
</del><ins>+ "recordTypes": ["locations", "resources", "addresses"],
</ins><span class="cx"> "xmlFile": "resources.xml",
</span><span class="cx"> },
</span><span class="cx"> "opendirectory": {
</span><del>- "recordTypes": ("locations", "resources", "addresses"),
</del><ins>+ "recordTypes": ["locations", "resources", "addresses"],
</ins><span class="cx"> "node": "/Search",
</span><span class="cx"> },
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> DEFAULT_AUGMENT_PARAMS = {
</span><span class="cx"> "twistedcaldav.directory.augment.AugmentXMLDB": {
</span><del>- "xmlFiles": ["augments.xml", ],
</del><ins>+ "xmlFiles": ["augments.xml"],
</ins><span class="cx"> "statSeconds": 15,
</span><span class="cx"> },
</span><span class="cx"> "twistedcaldav.directory.augment.AugmentSqliteDB": {
</span><span class="lines">@@ -132,7 +132,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><del>-directoryAddressBookBackingServiceDefaultParams = {
</del><ins>+DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS = {
</ins><span class="cx"> "twistedcaldav.directory.xmlfile.XMLDirectoryService": {
</span><span class="cx"> "xmlFile": "/etc/carddavd/accounts.xml",
</span><span class="cx"> },
</span><span class="lines">@@ -157,9 +157,8 @@
</span><span class="cx"> },
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+# Note: Don't use None values below; that confuses the command-line parser.
</ins><span class="cx"> DEFAULT_CONFIG = {
</span><del>- # Note: Don't use None values below; that confuses the command-line parser.
-
</del><span class="cx"> #
</span><span class="cx"> # Public network address information
</span><span class="cx"> #
</span><span class="lines">@@ -169,6 +168,7 @@
</span><span class="cx"> # default. For example, it may be the address of a load balancer or
</span><span class="cx"> # proxy which forwards connections to the server.
</span><span class="cx"> #
</span><ins>+
</ins><span class="cx"> "ServerHostName": "", # Network host name.
</span><span class="cx"> "HTTPPort": 0, # HTTP port (0 to disable HTTP)
</span><span class="cx"> "SSLPort": 0, # SSL port (0 to disable HTTPS)
</span><span class="lines">@@ -177,12 +177,11 @@
</span><span class="cx"> "SSLMethod": "SSLv23_METHOD", # SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
</span><span class="cx"> "SSLCiphers": "RC4-SHA:HIGH:!ADH",
</span><span class="cx">
</span><del>- # Max-age value for Strict-Transport-Security header; set to 0 to
- # disable header.
</del><ins>+ # Max-age value for Strict-Transport-Security header; set to 0 to disable header.
</ins><span class="cx"> "StrictTransportSecuritySeconds": 7 * 24 * 60 * 60,
</span><span class="cx">
</span><span class="cx"> #
</span><del>- # Network address configuration information
</del><ins>+ # Network address configuration information.
</ins><span class="cx"> #
</span><span class="cx"> # This configures the actual network address that the server binds to.
</span><span class="cx"> #
</span><span class="lines">@@ -200,17 +199,12 @@
</span><span class="cx"> "BindAddresses": [], # List of IP addresses to bind to [empty = all]
</span><span class="cx"> "BindHTTPPorts": [], # List of port numbers to bind to for HTTP
</span><span class="cx"> # [empty = same as "Port"]
</span><del>- "BindSSLPorts": [], # List of port numbers to bind to for SSL
- # [empty = same as "SSLPort"]
- "InheritFDs": [], # File descriptors to inherit for HTTP requests
- # (empty = don't inherit)
- "InheritSSLFDs": [], # File descriptors to inherit for HTTPS requests
- # (empty = don't inherit)
- "MetaFD": 0, # Inherited file descriptor to call recvmsg() on to
- # receive sockets (none = don't inherit)
</del><ins>+ "BindSSLPorts": [], # List of port numbers to bind to for SSL [empty = same as "SSLPort"]
+ "InheritFDs": [], # File descriptors to inherit for HTTP requests [empty = don't inherit]
+ "InheritSSLFDs": [], # File descriptors to inherit for HTTPS requests [empty = don't inherit]
+ "MetaFD": 0, # Inherited file descriptor to call recvmsg() on to receive sockets (none = don't inherit)
</ins><span class="cx">
</span><del>- "UseMetaFD": True, # Use a 'meta' FD, i.e. an FD to transmit other FDs
- # to slave processes.
</del><ins>+ "UseMetaFD": True, # Use a 'meta' FD, i.e. an FD to transmit other FDs to slave processes.
</ins><span class="cx">
</span><span class="cx"> "UseDatabase": True, # True: database; False: files
</span><span class="cx">
</span><span class="lines">@@ -261,11 +255,13 @@
</span><span class="cx"> #
</span><span class="cx"> # Work queue configuration information
</span><span class="cx"> #
</span><ins>+
</ins><span class="cx"> "WorkQueue": {
</span><span class="cx"> "queuePollInterval": 0.1, # Interval in seconds for job queue polling
</span><span class="cx"> "queueOverdueTimeout": 300, # Number of seconds before an assigned job is considered overdue
</span><span class="cx"> "queuePollingBackoff": [ # Array of array that describe the threshold and new polling interval
</span><del>- [60, 60], [5, 1] # for job queue polling back off
</del><ins>+ # for job queue polling back off
+ [60, 60], [5, 1]
</ins><span class="cx"> ],
</span><span class="cx">
</span><span class="cx"> "overloadLevel": 95, # Queue capacity (percentage) which causes job processing to halt
</span><span class="lines">@@ -426,7 +422,7 @@
</span><span class="cx"> "AccessLogFile" : "access.log", # Apache-style access log
</span><span class="cx"> "ErrorLogFile" : "error.log", # Server activity log
</span><span class="cx"> "AgentLogFile" : "agent.log", # Agent activity log
</span><del>- "UtilityLogFile" : "{}.log".format(basename(sys.argv[0])), # Command line utility log
</del><ins>+ "UtilityLogFile" : "utility.log", # Utility log - name will be dynamically changed to executable name
</ins><span class="cx"> "ErrorLogEnabled" : True, # True = use log file, False = stdout
</span><span class="cx"> "ErrorLogRotateMB" : 10, # Rotate error log after so many megabytes
</span><span class="cx"> "ErrorLogMaxRotatedFiles" : 5, # Retain this many error log files
</span><span class="lines">@@ -480,11 +476,11 @@
</span><span class="cx"> # Process management
</span><span class="cx"> #
</span><span class="cx">
</span><del>- # Username and Groupname to drop privileges to, if empty privileges will
- # not be dropped.
-
</del><ins>+ # Username and Groupname to drop privileges to, if empty privileges will not be dropped.
</ins><span class="cx"> "UserName": "",
</span><span class="cx"> "GroupName": "",
</span><ins>+
+ # Multi-process
</ins><span class="cx"> "ProcessType": "Combined",
</span><span class="cx"> "MultiProcess": {
</span><span class="cx"> "ProcessCount": 0,
</span><span class="lines">@@ -502,14 +498,10 @@
</span><span class="cx"> "Enabled" : True,
</span><span class="cx"> "Seconds" : 60, # How often to check memory sizes (in seconds)
</span><span class="cx"> "Bytes" : 2 * 1024 * 1024 * 1024, # Memory limit (RSS in bytes)
</span><del>- "ResidentOnly" : True, # True: only take into account resident memory;
- # False: include virtual memory
</del><ins>+ "ResidentOnly" : True, # True: only take into account resident memory; False: include virtual memory
</ins><span class="cx"> },
</span><span class="cx">
</span><del>- #
- # Service ACLs
- #
- "EnableSACLs": False,
</del><ins>+ "EnableSACLs": False, # Service ACLs
</ins><span class="cx">
</span><span class="cx"> "EnableReadOnlyServer": False, # Make all data read-only
</span><span class="cx">
</span><span class="lines">@@ -616,17 +608,16 @@
</span><span class="cx"> # If on, it will also cause new accounts to provision with separate
</span><span class="cx"> # calendars for events and tasks.
</span><span class="cx">
</span><del>- "SupportedComponents" : [ # Set of supported iCalendar components
</del><ins>+ "SupportedComponents" : [ # Set of supported iCalendar components
</ins><span class="cx"> "VEVENT",
</span><span class="cx"> "VTODO",
</span><del>- # "VPOLL",
</del><span class="cx"> ],
</span><span class="cx">
</span><span class="cx"> "EnableTrashCollection": False, # Enable Trash Collection
</span><span class="cx"> "ExposeTrashCollection": False, # Expose Trash Collection as a resource
</span><span class="cx">
</span><span class="cx"> "ParallelUpgrades": False, # Perform upgrades - currently only the
</span><del>- # database -> filesystem migration - but in
</del><ins>+ # database to filesystem migration - but in
</ins><span class="cx"> # the future, hopefully all relevant
</span><span class="cx"> # upgrades - in parallel in subprocesses.
</span><span class="cx">
</span><span class="lines">@@ -670,7 +661,7 @@
</span><span class="cx"> "DirectoryAddressBook": {
</span><span class="cx"> "Enabled": True,
</span><span class="cx"> "type": "twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService",
</span><del>- "params": directoryAddressBookBackingServiceDefaultParams["twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService"],
</del><ins>+ "params": DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS["twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService"],
</ins><span class="cx"> "name": "directory",
</span><span class="cx"> "MaxQueryResults": 1000,
</span><span class="cx"> },
</span><span class="lines">@@ -679,14 +670,10 @@
</span><span class="cx">
</span><span class="cx"> # /XXX CardDAV
</span><span class="cx">
</span><del>- #
</del><span class="cx"> # Web-based administration
</span><del>- #
</del><span class="cx"> "EnableWebAdmin" : True,
</span><span class="cx">
</span><del>- #
</del><span class="cx"> # JSON control API - only for testing
</span><del>- #
</del><span class="cx"> "EnableControlAPI" : False,
</span><span class="cx">
</span><span class="cx"> #
</span><span class="lines">@@ -974,8 +961,7 @@
</span><span class="cx"> # processes. If blank, then an AF_INET socket is used instead.
</span><span class="cx"> "ControlSocket": "caldavd.sock",
</span><span class="cx">
</span><del>- # Support for Content-Encoding compression options as specified in
- # RFC2616 Section 3.5
</del><ins>+ # Support for Content-Encoding compression options as specified in RFC2616 Section 3.5
</ins><span class="cx"> # Defaults off, because it weakens TLS (CRIME attack).
</span><span class="cx"> "ResponseCompression": False,
</span><span class="cx">
</span><span class="lines">@@ -999,8 +985,7 @@
</span><span class="cx"> "ServerEnabled": True,
</span><span class="cx"> "BindAddress": "127.0.0.1",
</span><span class="cx"> "Port": 11311,
</span><del>- "HandleCacheTypes": [
- "Default",
</del><ins>+ "HandleCacheTypes": [ # Possible types:
</ins><span class="cx"> # "OpenDirectoryBacker",
</span><span class="cx"> # "ImplicitUIDLock",
</span><span class="cx"> # "RefreshUIDLock",
</span><span class="lines">@@ -1012,6 +997,7 @@
</span><span class="cx"> # "SQL.props",
</span><span class="cx"> # "SQL.calhome",
</span><span class="cx"> # "SQL.adbkhome",
</span><ins>+ "Default",
</ins><span class="cx"> ]
</span><span class="cx"> },
</span><span class="cx"> # "Shared": {
</span><span class="lines">@@ -1051,9 +1037,9 @@
</span><span class="cx"> "Options": [
</span><span class="cx"> "-c standard_conforming_strings=on",
</span><span class="cx"> ],
</span><del>- "Ctl": "pg_ctl", # Iff the DBType is '', and we're spawning postgres
</del><ins>+ "Ctl": "pg_ctl", # If the DBType is '', and we're spawning postgres
</ins><span class="cx"> # ourselves, where is the pg_ctl tool to spawn it with?
</span><del>- "Init": "initdb", # Iff the DBType is '', and we're spawning postgres
</del><ins>+ "Init": "initdb", # If the DBType is '', and we're spawning postgres
</ins><span class="cx"> # ourselves, where is the initdb tool to create its
</span><span class="cx"> # database cluster with?
</span><span class="cx"> },
</span><span class="lines">@@ -1110,12 +1096,10 @@
</span><span class="cx"> # The RootResource uses a twext property store. Specify the class here
</span><span class="cx"> "RootResourcePropStoreClass": "txweb2.dav.xattrprops.xattrPropertyStore",
</span><span class="cx">
</span><del>- # Used in the command line utilities to specify which service class to
- # use to carry out work.
</del><ins>+ # Used in the command line utilities to specify which service class to use to carry out work.
</ins><span class="cx"> "UtilityServiceClass": "",
</span><span class="cx">
</span><del>- # Inbox items created more than MigratedInboxDaysCutoff days in the past are removed
- # during migration
</del><ins>+ # Inbox items created more than MigratedInboxDaysCutoff days in the past are removed during migration
</ins><span class="cx"> "MigratedInboxDaysCutoff": 60,
</span><span class="cx">
</span><span class="cx"> # The default timezone for the server; on OS X you can leave this empty and the
</span><span class="lines">@@ -1496,19 +1480,19 @@
</span><span class="cx"> newParams = items["DirectoryAddressBook"].get("params", {})
</span><span class="cx"> mergeData(oldParams, newParams)
</span><span class="cx"> else:
</span><del>- if dsType in directoryAddressBookBackingServiceDefaultParams:
- configDict.DirectoryAddressBook.params = copy.deepcopy(directoryAddressBookBackingServiceDefaultParams[dsType])
</del><ins>+ if dsType in DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS:
+ configDict.DirectoryAddressBook.params = copy.deepcopy(DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS[dsType])
</ins><span class="cx"> else:
</span><span class="cx"> configDict.DirectoryAddressBook.params = {}
</span><span class="cx">
</span><span class="cx"> for param in items.get("DirectoryAddressBook", {}).get("params", {}):
</span><del>- if param not in directoryAddressBookBackingServiceDefaultParams[dsType]:
</del><ins>+ if param not in DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS[dsType]:
</ins><span class="cx"> raise ConfigurationError("Parameter %s is not supported by service %s" % (param, dsType))
</span><span class="cx">
</span><span class="cx"> mergeData(configDict, items)
</span><span class="cx">
</span><span class="cx"> for param in tuple(configDict.DirectoryAddressBook.params):
</span><del>- if param not in directoryAddressBookBackingServiceDefaultParams[configDict.DirectoryAddressBook.type]:
</del><ins>+ if param not in DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS[configDict.DirectoryAddressBook.type]:
</ins><span class="cx"> del configDict.DirectoryAddressBook.params[param]
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -1642,6 +1626,11 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+def _updateUtilityLog(configDict, reloading=False):
+ configDict["UtilityLogFile"] = "{}.log".format(basename(sys.argv[0])), # Command line utility log
+
+
+
</ins><span class="cx"> def _updateLogLevels(configDict, reloading=False):
</span><span class="cx"> log.levels().clearLogLevels()
</span><span class="cx">
</span><span class="lines">@@ -1787,12 +1776,12 @@
</span><span class="cx"> _updateACLs,
</span><span class="cx"> _updateRejectClients,
</span><span class="cx"> _updateClientFixes,
</span><ins>+ _updateUtilityLog,
</ins><span class="cx"> _updateLogLevels,
</span><span class="cx"> _updateNotifications,
</span><span class="cx"> _updateICalendar,
</span><span class="cx"> _updateScheduling,
</span><span class="cx"> _updateSharing,
</span><del>- # _updateServers,
</del><span class="cx"> _updateCompliance,
</span><span class="cx"> )
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavtesttest_dumpconfigpy"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/twistedcaldav/test/test_dumpconfig.py (0 => 15404)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/test/test_dumpconfig.py         (rev 0)
+++ CalendarServer/trunk/twistedcaldav/test/test_dumpconfig.py        2015-12-18 20:02:34 UTC (rev 15404)
</span><span class="lines">@@ -0,0 +1,135 @@
</span><ins>+##
+# Copyright (c) 2015 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from unittest.case import TestCase
+from twistedcaldav.dumpconfig import parseConfigItem, processConfig, \
+ writeOrderedPlistToString
+from collections import OrderedDict
+
+class TestDumpConfig (TestCase):
+
+ def test_parseConfigItem(self):
+ """
+ Make sure L{parseConfigItem} can parse the DEFAULT_* items
+ """
+
+ items = {
+ "DEFAULT_SERVICE_PARAMS",
+ "DEFAULT_RESOURCE_PARAMS",
+ "DEFAULT_AUGMENT_PARAMS",
+ "DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS",
+ "DEFAULT_CONFIG",
+ }
+
+ for item in items:
+ lines = parseConfigItem(item)
+ self.assertNotEqual(len(lines), 0, msg="Failed {}".format(item))
+
+
+ def test_writeOrderedPlistToString(self):
+ """
+ Make sure L{writeOrderedPlistToString} preserves key order
+ """
+
+ data = OrderedDict()
+ data["KeyB"] = "1"
+ data["KeyA"] = "2"
+ data["KeyC"] = "3"
+ data["KeyE"] = "4"
+ data["KeyD"] = "5"
+
+ plist = writeOrderedPlistToString(data)
+ self.assertEqual(plist, """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+\t<key>KeyB</key>
+\t<string>1</string>
+
+\t<key>KeyA</key>
+\t<string>2</string>
+
+\t<key>KeyC</key>
+\t<string>3</string>
+
+\t<key>KeyE</key>
+\t<string>4</string>
+
+\t<key>KeyD</key>
+\t<string>5</string>
+</dict>
+</plist>
+""")
+
+
+ def test_plistWithComments(self):
+ """
+ Make sure L{writeOrderedPlistToString} preserves key order
+ """
+
+ data = OrderedDict()
+ data["comment_1"] = "All about KeyB"
+ data["KeyB"] = "1"
+ data["section_2"] = "Details on KeyA & KeyC"
+ data["comment_3"] = "All about KeyA"
+ data["KeyA"] = "2"
+ data["comment_4"] = "All about KeyC"
+ data["KeyC"] = "3"
+
+ plist = writeOrderedPlistToString(data)
+ self.assertEqual(plist, """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+\t<!-- All about KeyB -->
+\t<key>KeyB</key>
+\t<string>1</string>
+
+\t<!-- Details on KeyA &amp; KeyC -->
+
+\t<!-- All about KeyA -->
+\t<key>KeyA</key>
+\t<string>2</string>
+
+\t<!-- All about KeyC -->
+\t<key>KeyC</key>
+\t<string>3</string>
+</dict>
+</plist>
+""")
+
+
+ def test_fullPlistDump(self):
+ """
+ Make sure a full dump of DEFAULT_CONFIG works
+ """
+
+ maps = {
+ "DEFAULT_SERVICE_PARAMS": "",
+ "DEFAULT_RESOURCE_PARAMS": "",
+ "DEFAULT_AUGMENT_PARAMS": "",
+ "DEFAULT_DIRECTORY_ADDRESSBOOK_PARAMS": "",
+ }
+
+ for item in maps.keys():
+ lines = parseConfigItem(item)
+ maps[item] = processConfig(lines, with_comments=True, verbose=False)
+
+ # Generate the plist for the default config, substituting for the *_PARAMS items
+ lines = parseConfigItem("DEFAULT_CONFIG")
+ j = processConfig(lines, with_comments=True, verbose=False, substitutions=maps)
+ result = writeOrderedPlistToString(j)
+ self.assertIn('<plist version="1.0">', result)
</ins></span></pre>
</div>
</div>
</body>
</html>