1
0
mirror of https://github.com/etesync/android synced 2024-11-22 16:08:13 +00:00

Update collection properties (name, color) on every sync

This commit is contained in:
Ricki Hirner 2015-08-02 08:57:03 +02:00
parent 5b7947034a
commit abf04e14d2
15 changed files with 100 additions and 52 deletions

View File

@ -8,10 +8,14 @@
package at.bitfire.davdroid; package at.bitfire.davdroid;
import android.util.Log;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class DAVUtils { public class DAVUtils {
private static final String TAG = "davdroid.DAVutils";
public static int CalDAVtoARGBColor(String davColor) { public static int CalDAVtoARGBColor(String davColor) {
int color = 0xFFC3EA6E; // fallback: "DAVdroid green" int color = 0xFFC3EA6E; // fallback: "DAVdroid green"
if (davColor != null) { if (davColor != null) {
@ -21,8 +25,10 @@ public class DAVUtils {
int color_rgb = Integer.parseInt(m.group(1), 16); int color_rgb = Integer.parseInt(m.group(1), 16);
int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF; int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF;
color = (color_alpha << 24) | color_rgb; color = (color_alpha << 24) | color_rgb;
} } else
Log.w(TAG, "Couldn't parse color " + davColor + ", using DAVdroid green");
} }
return color; return color;
} }
} }

View File

@ -22,7 +22,7 @@ import at.bitfire.davdroid.webdav.DavFilter;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.DavProp; import at.bitfire.davdroid.webdav.DavProp;
public class CalDavCalendar extends RemoteCollection<Event> { public class CalDavCalendar extends WebDavCollection<Event> {
private final static String TAG = "davdroid.CalDAVCalendar"; private final static String TAG = "davdroid.CalDAVCalendar";
public CalDavCalendar(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public CalDavCalendar(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {

View File

@ -23,7 +23,7 @@ import at.bitfire.davdroid.webdav.DavFilter;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.DavProp; import at.bitfire.davdroid.webdav.DavProp;
public class CalDavTaskList extends RemoteCollection<Task> { public class CalDavTaskList extends WebDavCollection<Task> {
private final static String TAG = "davdroid.CalDAVTaskList"; private final static String TAG = "davdroid.CalDAVTaskList";
public CalDavTaskList(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public CalDavTaskList(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {

View File

@ -15,7 +15,7 @@ import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import ezvcard.VCardVersion; import ezvcard.VCardVersion;
public class CardDavAddressBook extends RemoteCollection<Contact> { public class CardDavAddressBook extends WebDavCollection<Contact> {
AccountSettings accountSettings; AccountSettings accountSettings;
@Override @Override

View File

@ -124,6 +124,12 @@ public class LocalAddressBook extends LocalCollection<Contact> {
accountSettings.setAddressBookCTag(cTag); accountSettings.setAddressBookCTag(cTag);
} }
@Override
public void updateMetaData(String displayName, String color)
{
// address books don't have a display name or color in Android
}
/* create/update/delete */ /* create/update/delete */

View File

@ -192,6 +192,21 @@ public class LocalCalendar extends LocalCollection<Event> {
} }
} }
@Override
public void updateMetaData(String displayName, String color) throws LocalStorageException {
ContentValues values = new ContentValues();
if (displayName != null)
values.put(Calendars.CALENDAR_DISPLAY_NAME, displayName);
if (color != null)
values.put(Calendars.CALENDAR_COLOR, DAVUtils.CalDAVtoARGBColor(color));
try {
if (values.size() > 0)
providerClient.update(ContentUris.withAppendedId(calendarsURI(), id), values, null, null);
} catch(RemoteException e) {
throw new LocalStorageException(e);
}
}
@Override @Override
public long[] findUpdated() throws LocalStorageException { public long[] findUpdated() throws LocalStorageException {
// mark (recurring) events with changed/deleted exceptions as dirty // mark (recurring) events with changed/deleted exceptions as dirty

View File

@ -91,10 +91,12 @@ public abstract class LocalCollection<T extends Resource> {
/** gets the ID if the collection (for instance, ID of the Android calendar) */ /** gets the ID if the collection (for instance, ID of the Android calendar) */
abstract public long getId(); abstract public long getId();
/** sets local stored CTag */
abstract public void setCTag(String cTag) throws LocalStorageException;
/** gets the CTag of the collection */ /** gets the CTag of the collection */
abstract public String getCTag() throws LocalStorageException; abstract public String getCTag() throws LocalStorageException;
/** sets the CTag of the collection */ /** update locally stored collection properties */
abstract public void setCTag(String cTag) throws LocalStorageException; abstract public void updateMetaData(String displayName, String color) throws LocalStorageException;
// content provider (= database) querying // content provider (= database) querying

View File

@ -90,7 +90,7 @@ public class LocalTaskList extends LocalCollection<Task> {
public static LocalTaskList[] findAll(Account account, ContentProviderClient providerClient) throws RemoteException { public static LocalTaskList[] findAll(Account account, ContentProviderClient providerClient) throws RemoteException {
@Cleanup Cursor cursor = providerClient.query(taskListsURI(account), @Cleanup Cursor cursor = providerClient.query(taskListsURI(account),
new String[] { TaskContract.TaskLists._ID, TaskContract.TaskLists._SYNC_ID }, new String[]{TaskContract.TaskLists._ID, TaskContract.TaskLists._SYNC_ID},
null, null, null); null, null, null);
LinkedList<LocalTaskList> taskList = new LinkedList<>(); LinkedList<LocalTaskList> taskList = new LinkedList<>();
@ -131,6 +131,21 @@ public class LocalTaskList extends LocalCollection<Task> {
} }
} }
@Override
public void updateMetaData(String displayName, String color) throws LocalStorageException {
ContentValues values = new ContentValues();
if (displayName != null)
values.put(TaskContract.TaskLists.LIST_NAME, displayName);
if (color != null)
values.put(TaskContract.TaskLists.LIST_COLOR, DAVUtils.CalDAVtoARGBColor(color));
try {
if (values.size() > 0)
providerClient.update(ContentUris.withAppendedId(taskListsURI(account), id), values, null, null);
} catch(RemoteException e) {
throw new LocalStorageException(e);
}
}
@Override @Override
public Task newResource(long localID, String resourceName, String eTag) { public Task newResource(long localID, String resourceName, String eTag) {
return new Task(localID, resourceName, eTag); return new Task(localID, resourceName, eTag);

View File

@ -39,7 +39,7 @@ import lombok.Getter;
* *
* @param <T> Subtype of Resource that can be stored in the collection * @param <T> Subtype of Resource that can be stored in the collection
*/ */
public abstract class RemoteCollection<T extends Resource> { public abstract class WebDavCollection<T extends Resource> {
private static final String TAG = "davdroid.resource"; private static final String TAG = "davdroid.resource";
URI baseURI; URI baseURI;
@ -50,7 +50,7 @@ public abstract class RemoteCollection<T extends Resource> {
abstract protected T newResourceSkeleton(String name, String ETag); abstract protected T newResourceSkeleton(String name, String ETag);
public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public WebDavCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
baseURI = URIUtils.parseURI(baseURL, false); baseURI = URIUtils.parseURI(baseURL, false);
collection = new WebDavResource(httpClient, baseURI, user, password, preemptiveAuth); collection = new WebDavResource(httpClient, baseURI, user, password, preemptiveAuth);
} }
@ -58,14 +58,8 @@ public abstract class RemoteCollection<T extends Resource> {
/* collection operations */ /* collection operations */
public String getCTag() throws URISyntaxException, IOException, HttpException { public void getProperties() throws URISyntaxException, IOException, HttpException, DavException {
try { collection.propfind(HttpPropfind.Mode.COLLECTION_PROPERTIES);
if (collection.getCTag() == null && collection.getMembers() == null) // not already fetched
collection.propfind(HttpPropfind.Mode.COLLECTION_CTAG);
} catch (DavException e) {
return null;
}
return collection.getCTag();
} }

View File

@ -23,7 +23,7 @@ import java.util.Map;
import at.bitfire.davdroid.resource.CalDavCalendar; import at.bitfire.davdroid.resource.CalDavCalendar;
import at.bitfire.davdroid.resource.LocalCalendar; import at.bitfire.davdroid.resource.LocalCalendar;
import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.RemoteCollection; import at.bitfire.davdroid.resource.WebDavCollection;
public class CalendarsSyncAdapterService extends Service { public class CalendarsSyncAdapterService extends Service {
private static SyncAdapter syncAdapter; private static SyncAdapter syncAdapter;
@ -54,17 +54,17 @@ public class CalendarsSyncAdapterService extends Service {
} }
@Override @Override
protected Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) { protected Map<LocalCollection<?>, WebDavCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) {
AccountSettings settings = new AccountSettings(getContext(), account); AccountSettings settings = new AccountSettings(getContext(), account);
String userName = settings.getUserName(), String userName = settings.getUserName(),
password = settings.getPassword(); password = settings.getPassword();
boolean preemptive = settings.getPreemptiveAuth(); boolean preemptive = settings.getPreemptiveAuth();
try { try {
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>(); Map<LocalCollection<?>, WebDavCollection<?>> map = new HashMap<>();
for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) { for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) {
RemoteCollection<?> dav = new CalDavCalendar(httpClient, calendar.getUrl(), userName, password, preemptive); WebDavCollection<?> dav = new CalDavCalendar(httpClient, calendar.getUrl(), userName, password, preemptive);
map.put(calendar, dav); map.put(calendar, dav);
} }
return map; return map;

View File

@ -22,7 +22,7 @@ import java.util.Map;
import at.bitfire.davdroid.resource.CardDavAddressBook; import at.bitfire.davdroid.resource.CardDavAddressBook;
import at.bitfire.davdroid.resource.LocalAddressBook; import at.bitfire.davdroid.resource.LocalAddressBook;
import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.RemoteCollection; import at.bitfire.davdroid.resource.WebDavCollection;
public class ContactsSyncAdapterService extends Service { public class ContactsSyncAdapterService extends Service {
private static ContactsSyncAdapter syncAdapter; private static ContactsSyncAdapter syncAdapter;
@ -53,7 +53,7 @@ public class ContactsSyncAdapterService extends Service {
} }
@Override @Override
protected Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) { protected Map<LocalCollection<?>, WebDavCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) {
AccountSettings settings = new AccountSettings(getContext(), account); AccountSettings settings = new AccountSettings(getContext(), account);
String userName = settings.getUserName(), String userName = settings.getUserName(),
password = settings.getPassword(); password = settings.getPassword();
@ -65,9 +65,9 @@ public class ContactsSyncAdapterService extends Service {
try { try {
LocalCollection<?> database = new LocalAddressBook(account, provider, settings); LocalCollection<?> database = new LocalAddressBook(account, provider, settings);
RemoteCollection<?> dav = new CardDavAddressBook(settings, httpClient, addressBookURL, userName, password, preemptive); WebDavCollection<?> dav = new CardDavAddressBook(settings, httpClient, addressBookURL, userName, password, preemptive);
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>(); Map<LocalCollection<?>, WebDavCollection<?>> map = new HashMap<>();
map.put(database, dav); map.put(database, dav);
return map; return map;

View File

@ -41,7 +41,7 @@ import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.LocalStorageException; import at.bitfire.davdroid.resource.LocalStorageException;
import at.bitfire.davdroid.resource.RemoteCollection; import at.bitfire.davdroid.resource.WebDavCollection;
import at.bitfire.davdroid.ui.settings.AccountActivity; import at.bitfire.davdroid.ui.settings.AccountActivity;
import at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.DavHttpClient; import at.bitfire.davdroid.webdav.DavHttpClient;
@ -102,7 +102,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
}.execute(); }.execute();
} }
protected abstract Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider); protected abstract Map<LocalCollection<?>, WebDavCollection<?>> getSyncPairs(Account account, ContentProviderClient provider);
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override @Override
@ -128,12 +128,12 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
Intent exceptionIntent = null; // what shall happen when clicking on the exception notification Intent exceptionIntent = null; // what shall happen when clicking on the exception notification
try { try {
// get local <-> remote collection pairs // get local <-> remote collection pairs
Map<LocalCollection<?>, RemoteCollection<?>> syncCollections = getSyncPairs(account, provider); Map<LocalCollection<?>, WebDavCollection<?>> syncCollections = getSyncPairs(account, provider);
if (syncCollections == null) if (syncCollections == null)
Log.i(TAG, "Nothing to synchronize"); Log.i(TAG, "Nothing to synchronize");
else else
try { try {
for (Map.Entry<LocalCollection<?>, RemoteCollection<?>> entry : syncCollections.entrySet()) for (Map.Entry<LocalCollection<?>, WebDavCollection<?>> entry : syncCollections.entrySet())
new SyncManager(entry.getKey(), entry.getValue()).synchronize(extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL), syncResult); new SyncManager(entry.getKey(), entry.getValue()).synchronize(extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL), syncResult);
} catch (DavException ex) { } catch (DavException ex) {

View File

@ -19,13 +19,14 @@ import at.bitfire.davdroid.ArrayUtils;
import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.LocalStorageException; import at.bitfire.davdroid.resource.LocalStorageException;
import at.bitfire.davdroid.resource.RecordNotFoundException; import at.bitfire.davdroid.resource.RecordNotFoundException;
import at.bitfire.davdroid.resource.RemoteCollection; import at.bitfire.davdroid.resource.WebDavCollection;
import at.bitfire.davdroid.resource.Resource; import at.bitfire.davdroid.resource.Resource;
import at.bitfire.davdroid.webdav.ConflictException; import at.bitfire.davdroid.webdav.ConflictException;
import at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.HttpException; import at.bitfire.davdroid.webdav.HttpException;
import at.bitfire.davdroid.webdav.NotFoundException; import at.bitfire.davdroid.webdav.NotFoundException;
import at.bitfire.davdroid.webdav.PreconditionFailedException; import at.bitfire.davdroid.webdav.PreconditionFailedException;
import at.bitfire.davdroid.webdav.WebDavResource;
public class SyncManager { public class SyncManager {
private static final String TAG = "davdroid.SyncManager"; private static final String TAG = "davdroid.SyncManager";
@ -33,41 +34,47 @@ public class SyncManager {
private static final int MAX_MULTIGET_RESOURCES = 35; private static final int MAX_MULTIGET_RESOURCES = 35;
final protected LocalCollection<? extends Resource> local; final protected LocalCollection<? extends Resource> local;
final protected RemoteCollection<? extends Resource> remote; final protected WebDavCollection<? extends Resource> remote;
public SyncManager(LocalCollection<? extends Resource> local, RemoteCollection<? extends Resource> remote) { public SyncManager(LocalCollection<? extends Resource> local, WebDavCollection<? extends Resource> remote) {
this.local = local; this.local = local;
this.remote = remote; this.remote = remote;
} }
public void synchronize(boolean manualSync, SyncResult syncResult) throws URISyntaxException, LocalStorageException, IOException, HttpException, DavException { public void synchronize(boolean manualSync, SyncResult syncResult) throws URISyntaxException, LocalStorageException, IOException, HttpException, DavException {
// PHASE 1: push local changes to server // PHASE 1: fetch collection properties
remote.getProperties();
final WebDavResource collectionResource = remote.getCollection();
local.updateMetaData(collectionResource.getDisplayName(), collectionResource.getColor());
// PHASE 2: push local changes to server
int deletedRemotely = pushDeleted(), int deletedRemotely = pushDeleted(),
addedRemotely = pushNew(), addedRemotely = pushNew(),
updatedRemotely = pushDirty(); updatedRemotely = pushDirty();
// PHASE 2A: check if there's a reason to do a sync with remote (= forced sync or remote CTag changed) // PHASE 3A: check if there's a reason to do a sync with remote (= forced sync or remote CTag changed)
boolean fetchCollection = (deletedRemotely + addedRemotely + updatedRemotely) > 0; boolean syncMembers = (deletedRemotely + addedRemotely + updatedRemotely) > 0;
if (manualSync) { if (manualSync) {
Log.i(TAG, "Synchronization forced"); Log.i(TAG, "Full synchronization forced");
fetchCollection = true; syncMembers = true;
} }
if (!fetchCollection) { if (!syncMembers) {
String currentCTag = remote.getCTag(), final String
currentCTag = collectionResource.getCTag(),
lastCTag = local.getCTag(); lastCTag = local.getCTag();
Log.d(TAG, "Last local CTag = " + lastCTag + "; current remote CTag = " + currentCTag); Log.d(TAG, "Last local CTag = " + lastCTag + "; current remote CTag = " + currentCTag);
if (currentCTag == null || !currentCTag.equals(lastCTag)) if (currentCTag == null || !currentCTag.equals(lastCTag))
fetchCollection = true; syncMembers = true;
} }
if (!fetchCollection) { if (!syncMembers) {
Log.i(TAG, "No local changes and CTags match, no need to sync"); Log.i(TAG, "No local changes and CTags match, no need to sync");
return; return;
} }
// PHASE 2B: detect details of remote changes // PHASE 3B: detect details of remote changes
Log.i(TAG, "Fetching remote resource list"); Log.i(TAG, "Fetching remote resource list");
Set<Resource> remotelyAdded = new HashSet<>(), Set<Resource> remotelyAdded = new HashSet<>(),
remotelyUpdated = new HashSet<>(); remotelyUpdated = new HashSet<>();
@ -83,7 +90,7 @@ public class SyncManager {
} }
} }
// PHASE 3: pull remote changes from server // PHASE 4: pull remote changes from server
syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[remotelyAdded.size()])); syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[remotelyAdded.size()]));
syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[remotelyUpdated.size()])); syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[remotelyUpdated.size()]));
@ -94,7 +101,7 @@ public class SyncManager {
// update collection CTag // update collection CTag
Log.i(TAG, "Sync complete, fetching new CTag"); Log.i(TAG, "Sync complete, fetching new CTag");
local.setCTag(remote.getCTag()); local.setCTag(collectionResource.getCTag());
} }

View File

@ -23,7 +23,7 @@ import java.util.Map;
import at.bitfire.davdroid.resource.CalDavTaskList; import at.bitfire.davdroid.resource.CalDavTaskList;
import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.LocalTaskList; import at.bitfire.davdroid.resource.LocalTaskList;
import at.bitfire.davdroid.resource.RemoteCollection; import at.bitfire.davdroid.resource.WebDavCollection;
public class TasksSyncAdapterService extends Service { public class TasksSyncAdapterService extends Service {
private static SyncAdapter syncAdapter; private static SyncAdapter syncAdapter;
@ -54,17 +54,17 @@ public class TasksSyncAdapterService extends Service {
} }
@Override @Override
protected Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) { protected Map<LocalCollection<?>, WebDavCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) {
AccountSettings settings = new AccountSettings(getContext(), account); AccountSettings settings = new AccountSettings(getContext(), account);
String userName = settings.getUserName(), String userName = settings.getUserName(),
password = settings.getPassword(); password = settings.getPassword();
boolean preemptive = settings.getPreemptiveAuth(); boolean preemptive = settings.getPreemptiveAuth();
try { try {
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>(); Map<LocalCollection<?>, WebDavCollection<?>> map = new HashMap<>();
for (LocalTaskList calendar : LocalTaskList.findAll(account, provider)) { for (LocalTaskList calendar : LocalTaskList.findAll(account, provider)) {
RemoteCollection<?> dav = new CalDavTaskList(httpClient, calendar.getUrl(), userName, password, preemptive); WebDavCollection<?> dav = new CalDavTaskList(httpClient, calendar.getUrl(), userName, password, preemptive);
map.put(calendar, dav); map.put(calendar, dav);
} }
return map; return map;

View File

@ -28,7 +28,7 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBaseHC4 {
HOME_SETS, HOME_SETS,
CARDDAV_COLLECTIONS, CARDDAV_COLLECTIONS,
CALDAV_COLLECTIONS, CALDAV_COLLECTIONS,
COLLECTION_CTAG, COLLECTION_PROPERTIES,
MEMBERS_ETAG MEMBERS_ETAG
} }
@ -70,8 +70,11 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBaseHC4 {
propfind.prop.calendarTimezone = new DavProp.CalendarTimezone(); propfind.prop.calendarTimezone = new DavProp.CalendarTimezone();
propfind.prop.supportedCalendarComponentSet = new LinkedList<>(); propfind.prop.supportedCalendarComponentSet = new LinkedList<>();
break; break;
case COLLECTION_CTAG: case COLLECTION_PROPERTIES:
propfind.prop.getctag = new DavProp.GetCTag(); propfind.prop.getctag = new DavProp.GetCTag();
propfind.prop.resourcetype = new DavProp.ResourceType();
propfind.prop.displayname = new DavProp.DisplayName();
propfind.prop.calendarColor = new DavProp.CalendarColor();
break; break;
case MEMBERS_ETAG: case MEMBERS_ETAG:
depth = 1; depth = 1;