[CalendarServer-changes] [5630] CalDAVTester/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu May 20 09:52:03 PDT 2010


Revision: 5630
          http://trac.macosforge.org/projects/calendarserver/changeset/5630
Author:   cdaboo at apple.com
Date:     2010-05-20 09:52:00 -0700 (Thu, 20 May 2010)
Log Message:
-----------
Scripts separate for CalDAV and CardDAV testing.

Modified Paths:
--------------
    CalDAVTester/trunk/odsetup.py
    CalDAVTester/trunk/scripts/server/serverinfo-template.xml
    CalDAVTester/trunk/scripts/server/serverinfo.xml

Added Paths:
-----------
    CalDAVTester/trunk/QuickLook-CalDAV
    CalDAVTester/trunk/QuickLook-CardDAV
    CalDAVTester/trunk/Validation-CalDAV
    CalDAVTester/trunk/Validation-CardDAV

Removed Paths:
-------------
    CalDAVTester/trunk/QuickLook
    CalDAVTester/trunk/Validation

Deleted: CalDAVTester/trunk/QuickLook
===================================================================
--- CalDAVTester/trunk/QuickLook	2010-05-20 05:53:46 UTC (rev 5629)
+++ CalDAVTester/trunk/QuickLook	2010-05-20 16:52:00 UTC (rev 5630)
@@ -1,23 +0,0 @@
-#!/bin/bash
-#
-##
-# Copyright (c) 2009 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.
-##
-#
-# Runs a subset of tests as a quick check that the server is functional.
-#
-
-export PYTHONPATH=/usr/share/caldavd/lib/python
-./testcaldav.py CalDAV/caldavIOP.xml CalDAV/errors.xml CalDAV/get.xml CalDAV/ical-client.xml CalDAV/propfind.xml CalDAV/put.xml CalDAV/quota.xml CalDAV/reports.xml

Copied: CalDAVTester/trunk/QuickLook-CalDAV (from rev 5510, CalDAVTester/trunk/QuickLook)
===================================================================
--- CalDAVTester/trunk/QuickLook-CalDAV	                        (rev 0)
+++ CalDAVTester/trunk/QuickLook-CalDAV	2010-05-20 16:52:00 UTC (rev 5630)
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+##
+# Copyright (c) 2009 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.
+##
+#
+# Runs a subset of tests as a quick check that the server is functional.
+#
+
+export PYTHONPATH=/usr/share/caldavd/lib/python
+./testcaldav.py -s scripts/server/serverinfo-caldav.xml CalDAV/caldavIOP.xml CalDAV/errors.xml CalDAV/get.xml CalDAV/ical-client.xml CalDAV/propfind.xml CalDAV/put.xml CalDAV/quota.xml CalDAV/reports.xml

Added: CalDAVTester/trunk/QuickLook-CardDAV
===================================================================
--- CalDAVTester/trunk/QuickLook-CardDAV	                        (rev 0)
+++ CalDAVTester/trunk/QuickLook-CardDAV	2010-05-20 16:52:00 UTC (rev 5630)
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+##
+# Copyright (c) 2009 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.
+##
+#
+# Runs a subset of tests as a quick check that the server is functional.
+#
+
+export PYTHONPATH=/usr/share/caldavd/lib/python
+./testcaldav.py -s scripts/server/serverinfo-carddav.xml CardDAV/ab-client.xml CardDAV/errors.xml CardDAV/get.xml CardDAV/propfind.xml CardDAV/put.xml CardDAV/reports.xml


Property changes on: CalDAVTester/trunk/QuickLook-CardDAV
___________________________________________________________________
Added: svn:executable
   + *

Deleted: CalDAVTester/trunk/Validation
===================================================================
--- CalDAVTester/trunk/Validation	2010-05-20 05:53:46 UTC (rev 5629)
+++ CalDAVTester/trunk/Validation	2010-05-20 16:52:00 UTC (rev 5630)
@@ -1,28 +0,0 @@
-#!/bin/bash
-#
-##
-# Copyright (c) 2009 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.
-##
-#
-# Runs a full set of tests to verify that the server is functional.
-#
-
-export PYTHONPATH=/usr/share/caldavd/lib/python
-./testcaldav.py --all \
-	--subdir CalDAV \
-	--exclude CalDAV/directory.xml \
-	--exclude CalDAV/errors-big-calendars.xml \
-	--exclude CalDAV/proxyauthz.xml
- 	
\ No newline at end of file

Copied: CalDAVTester/trunk/Validation-CalDAV (from rev 5615, CalDAVTester/trunk/Validation)
===================================================================
--- CalDAVTester/trunk/Validation-CalDAV	                        (rev 0)
+++ CalDAVTester/trunk/Validation-CalDAV	2010-05-20 16:52:00 UTC (rev 5630)
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+##
+# Copyright (c) 2009 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.
+##
+#
+# Runs a full set of tests to verify that the server is functional.
+#
+
+export PYTHONPATH=/usr/share/caldavd/lib/python
+./testcaldav.py -s scripts/server/serverinfo-caldav.xml --all \
+	--subdir CalDAV \
+	--exclude CalDAV/directory.xml \
+	--exclude CalDAV/errors-big-calendars.xml \
+	--exclude CalDAV/proxyauthz.xml
+ 	
\ No newline at end of file

Added: CalDAVTester/trunk/Validation-CardDAV
===================================================================
--- CalDAVTester/trunk/Validation-CardDAV	                        (rev 0)
+++ CalDAVTester/trunk/Validation-CardDAV	2010-05-20 16:52:00 UTC (rev 5630)
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+##
+# Copyright (c) 2009 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.
+##
+#
+# Runs a full set of tests to verify that the server is functional.
+#
+
+export PYTHONPATH=/usr/share/caldavd/lib/python
+./testcaldav.py -s scripts/server/serverinfo-carddav.xml --all \
+	--subdir CardDAV \
+	--exclude CardDAV/directory.xml
+ 	
\ No newline at end of file


Property changes on: CalDAVTester/trunk/Validation-CardDAV
___________________________________________________________________
Added: svn:executable
   + *

Modified: CalDAVTester/trunk/odsetup.py
===================================================================
--- CalDAVTester/trunk/odsetup.py	2010-05-20 05:53:46 UTC (rev 5629)
+++ CalDAVTester/trunk/odsetup.py	2010-05-20 16:52:00 UTC (rev 5630)
@@ -32,16 +32,25 @@
 diradmin_user    = "admin"
 diradmin_pswd    = ""
 directory_node   = "/LDAPv3/127.0.0.1"
-config           = "/etc/caldavd/caldavd.plist"
 utility          = "/usr/sbin/calendarserver_manage_principals"
 cmdutility       = "/usr/sbin/calendarserver_command_gateway"
 
 verbose = False
 veryverbose = False
 
-serverinfo_default  = "scripts/server/serverinfo.xml"
 serverinfo_template = "scripts/server/serverinfo-template.xml"
 
+details = {
+    "caldav": {
+        "config": "/etc/caldavd/caldavd.plist",
+        "serverinfo": "scripts/server/serverinfo-caldav.xml"
+    },
+    "carddav": {
+        "config": "/etc/carddavd/carddavd.plist",
+        "serverinfo": "scripts/server/serverinfo-carddav.xml"
+    }
+}
+
 base_dir = "../CalendarServer/"
 
 number_of_users = 10
@@ -210,14 +219,16 @@
 def usage():
     print """Usage: odsteup [options] create|create-users|remove
 Options:
-    -h       Print this help and exit
-    -n node  OpenDirectory node to target
-    -u uid   OpenDirectory Admin user id
-    -p pswd  OpenDirectory Admin user password
-    -f file  caldavd.plist config file used by the server
-    -c users number of user accounts to create (default: 10)
-    -v       verbose logging
-    -V       very verbose logging
+    -h        Print this help and exit
+    -n node   OpenDirectory node to target
+    -u uid    OpenDirectory Admin user id
+    -p pswd   OpenDirectory Admin user password
+    -f file   .plist config file used by the server
+    -c users  number of user accounts to create (default: 10)
+    -v        verbose logging
+    -V        very verbose logging
+    --caldav  testing CalDAV server
+    --carddav testing CardDAV server
 """
 
 def cmd(args, input=None, raiseOnFail=True):
@@ -257,7 +268,8 @@
         plist["SudoersFile"] = "/etc/caldavd/sudoers.plist"
         writePlist(plist,config)
 
-    try: sudoerspl = readPlist('/etc/caldavd/sudoers.plist')
+    try:
+        sudoerspl = readPlist('/etc/caldavd/sudoers.plist')
     except IOError:
         # create a new sudoers.plist with empty 'users' array
         sudoerspl = {'users': []}
@@ -272,6 +284,8 @@
 
     sudoers = plist["SudoersFile"]
 
+    port = plist["HTTPPort"]
+
     try:
         basic_ok = plist["Authentication"]["Basic"]["Enabled"]
     except KeyError:
@@ -292,7 +306,7 @@
     if sudoers[0] != "/":
         sudoers = base_dir + sudoers
 
-    return hostname, authtype, docroot, sudoers
+    return hostname, port, authtype, docroot, sudoers
 
 def patchConfig(config, admin):
     """
@@ -335,7 +349,7 @@
         users.append({"username":"superuser", "password": "superuser"})
         writePlist(plist, sudoers)
 
-def buildServerinfo(hostname, authtype, docroot):
+def buildServerinfo(serverinfo_default, hostname, port, authtype, docroot):
     
     # Read in the serverinfo-template.xml file
     fd = open(serverinfo_template, "r")
@@ -374,6 +388,7 @@
 
     data = data % {
         "hostname"       : hostname,
+        "port"           : str(port),
         "authtype"       : authtype,
         "overrides"      : subs_str,
     }
@@ -404,7 +419,7 @@
             cmd("tar -C %s -zx -f data/%s.tgz" % (path, calendar,))
             cmd("chown -R calendar:calendar %s" % (os.path.join(path, calendar) ,))
 
-def loadLists(path, records):
+def loadLists(config, path, records):
     if path == "/Places":
         result = cmd(
             "%s -f %s" % (cmdutility, config,),
@@ -427,9 +442,11 @@
     for record in plist["result"]:
         records[record["RecordName"][0]] = record["GeneratedUID"] 
 
-def doToAccounts(f, users_only=False):
+def doToAccounts(config, protocol, f, users_only=False):
     
     for record in records:
+        if protocol == "carddav" and record[0] in ("/Places", "/Resources"):
+            continue
         if record[4] is None:
             count = number_of_users
         elif users_only:
@@ -444,9 +461,9 @@
                         value = value % (ctr,)
                     attrs[key] = value
                 ruser = (record[1] % (ctr,), record[2] % (ctr,), attrs, 1)
-                f(record[0], ruser)
+                f(config, record[0], ruser)
         else:
-            f(record[0], record[1:])
+            f(config, record[0], record[1:])
 
 def doGroupMemberships():
     
@@ -465,12 +482,12 @@
         cmd("dscl -u %s -P %s %s -append /Groups/%s \"dsAttrTypeStandard:GroupMembers\"%s" % (diradmin_user, diradmin_pswd, directory_node, groupname, "".join([" \"%s\"" % (guid,) for guid in memberGUIDs])), raiseOnFail=False)
         cmd("dscl -u %s -P %s %s -append /Groups/%s \"dsAttrTypeStandard:NestedGroups\"%s" % (diradmin_user, diradmin_pswd, directory_node, groupname, "".join([" \"%s\"" % (guid,) for guid in nestedGUIDs])), raiseOnFail=False)
 
-def createUser(path, user):
+def createUser(config, path, user):
     
     if path in ("/Users", "/Groups",):
-        createUserViaDS(path, user)
-    else:
-        createUserViaGateway(path, user)
+        createUserViaDS(config, path, user)
+    elif protocol == "caldav":
+        createUserViaGateway(config, path, user)
         
     # Do caldav_utility setup
     if path in ("/Places", "/Resources",):
@@ -485,7 +502,7 @@
                 user[0],
             ))
 
-def createUserViaDS(path, user):
+def createUserViaDS(config, path, user):
     # Do dscl command line operations to create a calendar user
     
     # Only create if it does not exist
@@ -511,7 +528,7 @@
         guid = result[0].split()[1]
         guids[user[0]] = guid
 
-def createUserViaGateway(path, user):
+def createUserViaGateway(config, path, user):
     
     # Check for existing
     if path == "/Places":
@@ -547,28 +564,33 @@
     else:
         raise ValueError()
     
-def removeUser(path, user):
+def removeUser(config, path, user):
     
     if path in ("/Users", "/Groups",):
-        removeUserViaDS(path, user)
+        removeUserViaDS(config, path, user)
     else:
-        removeUserViaGateway(path, user)
+        removeUserViaGateway(config, path, user)
 
-def removeUserViaDS(path, user):
+def removeUserViaDS(config, path, user):
     # Do dscl command line operations to create a calendar user
     
     # Create the user
     cmd("dscl -u %s -P %s %s -delete %s/%s" % (diradmin_user, diradmin_pswd, directory_node, path, user[0]), raiseOnFail=False)
 
-def removeUserViaGateway(path, user):
+def removeUserViaGateway(config, path, user):
     
-    guid = uuid.uuid4()
     if path == "/Places":
+        if user[0] not in locations:
+            return
+        guid = locations[user[0]]
         cmd(
             "%s -f %s" % (cmdutility, config,),
             locationremovecmd % {"guid":guid,}
         )
     elif path == "/Resources":
+        if user[0] not in resources:
+            return
+        guid = resources[user[0]]
         cmd(
             "%s -f %s" % (cmdutility, config,),
             resourceremovecmd % {"guid":guid,}
@@ -578,8 +600,11 @@
 
 if __name__ == "__main__":
 
+    config = None
+    protocol = None
+    serverinfo_default = None
     try:
-        options, args = getopt.getopt(sys.argv[1:], "hn:p:u:f:c:vV", ["old"])
+        options, args = getopt.getopt(sys.argv[1:], "hn:p:u:f:c:vV", ["carddav", "caldav", "old"])
 
         for option, value in options:
             if option == "-h":
@@ -600,11 +625,24 @@
             elif option == "-V":
                 verbose = True
                 veryverbose = True
+            elif option == "--carddav":
+                protocol = "carddav"
+            elif option == "--caldav":
+                protocol = "caldav"
             else:
                 print "Unrecognized option: %s" % (option,)
                 usage()
                 raise ValueError
 
+        if not protocol:
+            print "One of --carddav or --caldav MUST be specified"
+            usage()
+            raise ValueError
+        else:
+            if not config:
+                config = details[protocol]["config"]
+                serverinfo_default = details[protocol]["serverinfo"]
+            
         if not diradmin_pswd:
             diradmin_pswd = getpass("Password: ")
 
@@ -624,42 +662,48 @@
         
         if args[0] == "create":
             # Read the caldavd.plist file and extract some information we will need.
-            hostname, authtype, docroot, sudoers = readConfig(config)
+            hostname, port, authtype, docroot, sudoers = readConfig(config)
             
             # Patch the sudoers file for the superuser principal.
             patchSudoers(sudoers)
     
             # Now generate the OD accounts (caching guids as we go).
-            loadLists("/Places", locations)
-            loadLists("/Resources", resources)
+            if protocol == "caldav":
+                loadLists(config, "/Places", locations)
+                loadLists(config, "/Resources", resources)
 
-            doToAccounts(createUser)
+            doToAccounts(config, protocol, createUser)
             doGroupMemberships()
             
             # Patch the caldavd.plist file with the testadmin user's guid-based principal-URL
             patchConfig(config, "/principals/__uids__/%s/" % (guids["testadmin"],))
             
             # Create an appropriate serverinfo.xml file from the template
-            buildServerinfo(hostname, authtype, docroot)
+            buildServerinfo(serverinfo_default, hostname, port, authtype, docroot)
 
             # Add large calendars to user account
-            addLargeCalendars(hostname, docroot)
+            if protocol == "caldav":
+                addLargeCalendars(hostname, docroot)
 
         elif args[0] == "create-users":
             # Read the caldavd.plist file and extract some information we will need.
-            hostname, authtype, docroot, sudoers = readConfig(config)
+            hostname, port, authtype, docroot, sudoers = readConfig(config)
             
             # Now generate the OD accounts (caching guids as we go).
-            loadLists("/Places", locations)
-            loadLists("/Resources", resources)
+            if protocol == "caldav":
+                loadLists(config, "/Places", locations)
+                loadLists(config, "/Resources", resources)
 
-            doToAccounts(createUser, users_only=True)
+            doToAccounts(config, protocol, createUser, users_only=True)
             
             # Create an appropriate serverinfo.xml file from the template
-            buildServerinfo(hostname, authtype, docroot)
+            buildServerinfo(serverinfo_default, hostname, port, authtype, docroot)
 
         elif args[0] == "remove":
-            doToAccounts(removeUser)
+            if protocol == "caldav":
+                loadLists(config, "/Places", locations)
+                loadLists(config, "/Resources", resources)
+            doToAccounts(config, protocol, removeUser)
             
     except Exception, e:
         sys.exit(str(e))

Modified: CalDAVTester/trunk/scripts/server/serverinfo-template.xml
===================================================================
--- CalDAVTester/trunk/scripts/server/serverinfo-template.xml	2010-05-20 05:53:46 UTC (rev 5629)
+++ CalDAVTester/trunk/scripts/server/serverinfo-template.xml	2010-05-20 16:52:00 UTC (rev 5630)
@@ -20,7 +20,7 @@
 
 <serverinfo>
 	<host>%(hostname)s</host>
-	<port>8008</port>
+	<port>%(port)s</port>
 	<authtype>%(authtype)s</authtype>
 
 	<features>
@@ -67,13 +67,15 @@
 		<!-- CardDAV specific extension -->
 		<feature>carddav</feature> 						<!-- Basic CardDAV feature enabler -->
 		<feature>global-addressbook</feature> 			<!-- Global address book for each user -->
+		<feature>shared-addressbooks</feature>			<!-- Shared address books extension -->
+		<feature>directory-gateway</feature>			<!-- Directory gateway extension -->
 
 	</features>
 
 	<substitutions>
 		<substitution>
 			<key>$host:</key>
-			<value>http://%(hostname)s:8008</value>
+			<value>http://%(hostname)s:%(port)s</value>
 		</substitution>
 
 		<!-- relative path to caldav root-->
@@ -359,6 +361,11 @@
 				<key>$calendarpath%%d:</key>
 				<value>$calendars_uids:$userguid%%d:/$calendar:</value>
 			</substitution>
+			<!-- relative path to user alternate calendar home-->
+			<substitution>
+				<key>$calendarpathalt%%d:</key>
+				<value>$calendars_users:$userid%%d:/$calendar:</value>
+			</substitution>
 			<!-- relative path to user inbox-->
 			<substitution>
 				<key>$inboxpath%%d:</key>
@@ -384,12 +391,7 @@
 				<key>$freebusypath%%d:</key>
 				<value>$calendars_uids:$userguid%%d:/$freebusy:</value>
 			</substitution>
-			<!-- relative path to user alternate calendar home-->
 			<substitution>
-				<key>$calendarpathalt%%d:</key>
-				<value>$calendars_users:$userid%%d:/$calendar:</value>
-			</substitution>
-			<substitution>
 				<key>$email%%d:</key>
 				<value>$userid%%d:@example.com</value>
 			</substitution>

Modified: CalDAVTester/trunk/scripts/server/serverinfo.xml
===================================================================
--- CalDAVTester/trunk/scripts/server/serverinfo.xml	2010-05-20 05:53:46 UTC (rev 5629)
+++ CalDAVTester/trunk/scripts/server/serverinfo.xml	2010-05-20 16:52:00 UTC (rev 5630)
@@ -68,6 +68,7 @@
 		<feature>carddav</feature> 						<!-- Basic CardDAV feature enabler -->
 		<feature>global-addressbook</feature> 			<!-- Global address book for each user -->
 		<feature>shared-addressbooks</feature>			<!-- Shared address books extension -->
+		<!-- <feature>directory-gateway</feature> -->	<!-- Directory gateway extension -->
 
 	</features>
 
@@ -351,11 +352,21 @@
 				<key>$pathprefix%d:</key>
 				<value>$calendars_uids:$userguid%d:</value>
 			</substitution>
+			<!-- relative path to user alternate calendar home-->
+			<substitution>
+				<key>$pathprefixalt%d:</key>
+				<value>$calendars_users:$userid%d:</value>
+			</substitution>
 			<!-- relative path to user calendar-->
 			<substitution>
 				<key>$calendarpath%d:</key>
 				<value>$calendars_uids:$userguid%d:/$calendar:</value>
 			</substitution>
+			<!-- relative path to user alternate calendar-->
+			<substitution>
+				<key>$calendarpathalt%d:</key>
+				<value>$calendars_users:$userid%d:/$calendar:</value>
+			</substitution>
 			<!-- relative path to user inbox-->
 			<substitution>
 				<key>$inboxpath%d:</key>
@@ -381,17 +392,7 @@
 				<key>$freebusypath%d:</key>
 				<value>$calendars_uids:$userguid%d:/$freebusy:</value>
 			</substitution>
-			<!-- relative path to user alternate calendar home-->
 			<substitution>
-				<key>$pathprefixalt%d:</key>
-				<value>$calendars_users:$userid%d:</value>
-			</substitution>
-			<!-- relative path to user alternate calendar-->
-			<substitution>
-				<key>$calendarpathalt%d:</key>
-				<value>$calendars_users:$userid%d:/$calendar:</value>
-			</substitution>
-			<substitution>
 				<key>$email%d:</key>
 				<value>$userid%d:@example.com</value>
 			</substitution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100520/f0035939/attachment-0001.html>


More information about the calendarserver-changes mailing list