calendarengines/caldav/src/caldavengine.cpp
branchRCL_3
changeset 31 97232defd20e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calendarengines/caldav/src/caldavengine.cpp	Tue Sep 14 21:17:03 2010 +0300
@@ -0,0 +1,2617 @@
+/*
+ * Copyright (c) 2010 Sun Microsystems, Inc. and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributor:
+ * Maximilian Odendahl
+ *
+ * Contributors:
+ * 
+ * Description:  main Caldav class, all magic happens here 
+ *				one engine for each configured Caldav calendar
+ */
+#include "caldavengine.h"
+#include <f32file.h> 
+#include <S32FILE.H>
+#include <S32MEM.H> 
+#include <avkon.rsg>
+#include <UTF.H>
+#include <agnexportobserver.h>
+#include <calsession.h>
+#include <caliterator.h>
+#include <calentry.h>
+#include <calentryview.h>
+#include <caltime.h>
+#include <calalarm.h>
+#include <calcategory.h>
+#include <caluser.h>
+#include <calrrule.h>
+#include <calinstance.h>
+#include <calinstanceview.h>
+#include <caleninterimutils2.h> 
+#include <calenexporter.h>
+#include <calenimporter.h>
+#include <calcalendarinfo.h>
+#include "calenglobaldata.h"
+#include <xmlengdocument.h>
+#include <xmlengnode.h>
+#include <xmlengelement.h>
+#include <xmlengnodelist.h>
+#include <xmlengtext.h>
+#include "httpclient.h"
+#include <e32math.h>	// divmod
+#define MULTIGETSPLIT 			100
+#define ARRAYEXPAND				4
+#define	URLMAX					500
+#define EXPANDSIZE_SMALL		512
+#define EXPANDSIZE_BIG			1024
+_LIT(KFormatString,"\"%F%Y%M%DT000000Z\"");
+
+/**
+ * SyncTickL
+ * timer for basic sync interval
+ */
+TInt SyncTickL(TAny *aObject)
+	{
+	CCalDavEngine* engine = ((CCalDavEngine*) aObject);
+	CPeriodic* timer = engine->Timer();
+	if (engine && timer)
+		{
+		timer->Cancel();
+		TRAP_IGNORE(engine->SyncL());
+		TInt ticktime = engine->SyncInterval().Int() == 0 ? 1
+				: engine->SyncInterval().Int();
+		const TUint64 tickInterval = 1000000 * 60 * ticktime;
+		timer->Start(tickInterval, tickInterval, TCallBack(SyncTickL, engine));
+		}
+	return 0;
+	}
+
+#ifdef _DEBUG
+void ExportToFileNameL(const TDesC8& aDes, const TDesC &aFilename)
+	{
+	RFs fsSession;
+	User::LeaveIfError(fsSession.Connect());
+	CleanupClosePushL(fsSession);
+
+	TInt err = fsSession.MkDirAll(aFilename);
+
+	RFile file;
+	User::LeaveIfError(file.Replace(fsSession, aFilename, EFileWrite));
+	CleanupClosePushL(file);
+
+	RFileWriteStream writeStream2;
+	writeStream2.Attach(file);
+	CleanupClosePushL(writeStream2);
+
+	writeStream2 << aDes;
+	writeStream2.CommitL();
+	CleanupStack::PopAndDestroy(&writeStream2);
+	CleanupStack::PopAndDestroy(&file);
+	CleanupStack::PopAndDestroy(&fsSession);
+	}
+
+void ExportToFileL(CCalEntry* aEntry, CCalenExporter *iCalExporter)
+	{
+	if (aEntry)
+		{
+		_LIT(KFileName, "C:\\logs\\caldav\\testing_export.txt");
+
+		RFs fsSession;
+		User::LeaveIfError(fsSession.Connect());
+		CleanupClosePushL(fsSession);
+
+		TInt err = fsSession.MkDirAll(KFileName);
+
+		RFile file;
+		User::LeaveIfError(file.Replace(fsSession, KFileName, EFileWrite));
+		CleanupClosePushL(file);
+
+		RFileWriteStream writeStream2;
+		writeStream2.Attach(file);
+		CleanupClosePushL(writeStream2);
+
+		iCalExporter->ExportICalL(*aEntry, writeStream2);
+		writeStream2.CommitL();
+		CleanupStack::PopAndDestroy(&writeStream2);
+		CleanupStack::PopAndDestroy(&file);
+		CleanupStack::PopAndDestroy(&fsSession);
+		}
+	}
+#endif
+
+/**
+ * SearchL
+ * search inside xml tree for a specific node
+ */
+void SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
+		const TDesC8 &aNamespace, TXmlEngNode & aReturnNode)
+	{
+	RXmlEngNodeList<TXmlEngNode> List;
+	aTopNode.GetChildNodes(List);
+	while (List.HasNext() && aReturnNode.IsNull())
+		{
+		TXmlEngNode Node = List.Next();
+		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
+		if (Type == TXmlEngNode::EElement)
+			{
+			//todo: compare namespace ?
+			if (Node.Name() == aName)
+				{
+				aReturnNode = Node.CopyL();
+				return;
+				}
+			else
+				{
+				SearchL(Node, aName, aNamespace, aReturnNode);
+				if (!aReturnNode.IsNull())
+					return;
+				}
+			}
+		}
+	}
+
+/**
+ * SearchL
+ * search inside xml tree for a specific node
+ */
+void SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
+		const TDesC8 &aNamespace, RBuf8 &aBuf)
+	{
+	RXmlEngNodeList<TXmlEngNode> List;
+	aTopNode.GetChildNodes(List);
+	while (List.HasNext())
+		{
+		TXmlEngNode Node = List.Next();
+		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
+		if (Type == TXmlEngNode::EElement)
+			{
+			//todo: compare namespace ?
+			if (Node.Name() == aName)
+				{
+				if (Node.IsSimpleTextContents())
+					aBuf.Create(Node.Value());
+				else
+					Node.WholeTextContentsCopyL(aBuf);
+				return;
+				}
+			else
+				{
+				SearchL(Node, aName, aNamespace, aBuf);
+				if (aBuf.Length())
+					return;
+				}
+			}
+		}
+	}
+
+/**
+ * SearchL
+ * search inside xml tree for a specific node
+ */
+TPtrC8 SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
+		const TDesC8 &aNamespace)
+	{
+	RXmlEngNodeList<TXmlEngNode> List;
+	aTopNode.GetChildNodes(List);
+	while (List.HasNext())
+		{
+		TXmlEngNode Node = List.Next();
+		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
+		if (Type == TXmlEngNode::EElement)
+			{
+			//todo: compare namespace ?
+			if (Node.Name() == aName)
+				return Node.Value();
+			else
+				{
+				TPtrC8 Return = SearchL(Node, aName, aNamespace);
+				if (Return != KNullDesC8)
+					return Return;
+				}
+			}
+		}
+	return KNullDesC8();
+	}
+
+/**
+ * GetBoolFromPropertiesL
+ * get a boolean value from CCalCalendarInfo
+ */
+TBool GetBoolFromPropertiesL(CCalCalendarInfo* info, const TDesC8 &aKey)
+	{
+	TBool boolean;
+	TPckgC<TBool> pckgboolean(boolean);
+	pckgboolean.Set(info->PropertyValueL(aKey));
+	return pckgboolean();
+	}
+
+/**
+ * GetTimeFromPropertiesL
+ * get a time value from CCalCalendarInfo
+ */
+TCalTime GetTimeFromPropertiesL(CCalCalendarInfo* info, const TDesC8 &aKey)
+	{
+	TCalTime time;
+	TPckgC<TCalTime> pckgtime(time);
+	pckgtime.Set(info->PropertyValueL(aKey));
+	return pckgtime();
+	}
+
+/**
+ * PropertyExists
+ * finds a property from an array
+ */
+TBool PropertyExists(CDesC8Array* aArray, const TDesC8 &aKey)
+	{
+	TInt pos = 0;
+	return aArray->Find(aKey, pos, ECmpNormal) == KErrNone;
+	}
+
+/**
+ * CCalDavEngine::SetCalendarInfoL
+ * set key and value pair at calendar session info
+ */
+void CCalDavEngine::SetCalendarInfoL(const TDesC8 &aKey, const TDesC8 &aValue)
+	{
+	TBool createdelete = !iCalSession;
+	if (createdelete)
+		{
+		iCalSession = CCalSession::NewL();
+		TRAP_IGNORE(iCalSession->OpenL(*iCalendar));
+		}
+	CCalCalendarInfo* calendarInfo = iCalSession->CalendarInfoL();
+	CleanupStack::PushL(calendarInfo);
+	TPckgC<TBool> enabled(iEnabled);
+	calendarInfo->SetPropertyL(KCaldavEnabled, enabled);
+	if (aValue != KNullDesC8)
+		calendarInfo->SetPropertyL(aKey, aValue);
+	iCalSession->SetCalendarInfoL(*calendarInfo);
+	CleanupStack::PopAndDestroy(calendarInfo);
+
+	if (createdelete)
+		{
+		delete iCalSession;
+		iCalSession = NULL;
+		}
+	}
+
+/**
+ * CCalDavEngine::CCalDavEngine
+ * default constructor
+ */
+CCalDavEngine::CCalDavEngine() :
+	iCalSession(0), iCalIter(0), iCalEntryView(0), iCalExporter(0),
+			iCalImporter(0), iCalIntermimUtils2(0), iCalendar(0), iUrl(0),
+			iBaseUrl(0), iHome(0), iHttp(0), iSynctoken(0), iCTag(0),
+			iSyncInterval(DEFAULT_SYNC_MINUTES), iPastDays(DEFAULT_PAST_DAYS),
+			iImmediateSync(DEFAULT_IMMEDIATE_SYNC), iKeepServerEntry(
+					DEFAULT_KEEP_SERVER_ENTRY), iEnabled(EFalse), iTimer(0)
+	{
+	}
+
+/**
+ * CCalDavEngine::~CCalDavEngine
+ * default destructor
+ */
+CCalDavEngine::~CCalDavEngine()
+	{
+	iLocalUidArray.Close();
+	iGlobalUidArray.Close();
+	iDeletedEntries.Close();
+
+	iDomParser.Close();
+	iDomImpl.Close();
+
+	if (iCalendar)
+		delete iCalendar;
+
+	if (iUrl)
+		delete iUrl;
+
+	if (iBaseUrl)
+		delete iBaseUrl;
+
+	if (iHttp)
+		delete iHttp;
+
+	DeleteCalObjects();
+
+	if (iCalIntermimUtils2)
+		delete iCalIntermimUtils2;
+
+	if (iSynctoken)
+		delete iSynctoken;
+
+	if (iCTag)
+		delete iCTag;
+
+	if (iHome)
+		delete iHome;
+
+	if (iTimer)
+		delete iTimer;
+	}
+
+/**
+ * CCalDavEngine::NewLC
+ * first phase construction
+ */
+CCalDavEngine* CCalDavEngine::NewLC(const TDesC& aCalendar)
+	{
+	CCalDavEngine* self = new (ELeave) CCalDavEngine();
+	CleanupStack::PushL(self);
+	self->ConstructL(aCalendar);
+	return self;
+	}
+
+/**
+ * CCalDavEngine::NewL
+ * first phase construction
+ */
+CCalDavEngine* CCalDavEngine::NewL(const TDesC& aCalendar)
+	{
+	CCalDavEngine* self = CCalDavEngine::NewLC(aCalendar);
+	CleanupStack::Pop(self); // self;
+	return self;
+	}
+
+/**
+ * CCalDavEngine::
+ * second phase construction
+ */
+void CCalDavEngine::ConstructL(const TDesC& aCalendar)
+	{
+	iManualSync = EFalse;
+	iFirstInit = ETrue;
+	iCalendar = aCalendar.AllocL();
+
+	iHttp = CHttpClient::NewL();
+
+	iDomImpl.OpenL();
+	TInt err = iDomParser.Open(iDomImpl);
+	if (KErrNone != err)
+		User::Leave(err);
+
+	iTimer = CPeriodic::NewL(EPriorityNormal);
+	iCalIntermimUtils2 = CCalenInterimUtils2::NewL();
+	iCalSession = CCalSession::NewL();
+	TRAP_IGNORE(iCalSession->OpenL(aCalendar));
+	CalendarInfoL();
+	// we can't close the file, so delete it completly
+	delete iCalSession;
+	iCalSession = NULL;
+	}
+
+/**
+ * CCalDavEngine::Progress
+ * Progress callback
+ */
+void CCalDavEngine::Progress(TInt /*aPercentageCompleted*/)
+	{
+	}
+
+/**
+ * CCalDavEngine::RegisterL
+ * register all neccessary notification callback
+ */
+void CCalDavEngine::RegisterL()
+	{
+	TDateTime Start;
+	TDateTime End;
+	End.SetYear(2200);
+
+	TCalTime StartCal;
+	TCalTime EndCal;
+	StartCal.SetTimeLocalL(Start);
+	EndCal.SetTimeLocalL(End);
+	CalCommon::TCalTimeRange Range(StartCal, EndCal);
+	CCalChangeNotificationFilter *Filter = CCalChangeNotificationFilter::NewL(
+			MCalChangeCallBack2::EChangeEntryAll, true, Range);
+	iCalSession->StartChangeNotification(*this, *Filter);
+	iCalSession->StartFileChangeNotificationL(*this);
+	delete Filter;
+	}
+
+/**
+ * CCalDavEngine::CalendarInfoL
+ * load all properties from CalendarInfo
+ */
+void CCalDavEngine::CalendarInfoL()
+	{
+	CCalCalendarInfo* calendarInfo = iCalSession->CalendarInfoL();
+	if (calendarInfo->IsValid())
+		{
+		CleanupStack::PushL(calendarInfo);
+		CDesC8Array* propertyKeys = calendarInfo->PropertyKeysL();
+		CleanupStack::PushL(propertyKeys);
+		TInt pos = 0;
+		if (propertyKeys->Find(KCaldavEnabled, pos, ECmpNormal) == KErrNone)
+			{
+			iEnabled = GetBoolFromPropertiesL(calendarInfo, KCaldavEnabled);
+			if (PropertyExists(propertyKeys, KCaldavFirstInit))
+				iFirstInit = GetBoolFromPropertiesL(calendarInfo,
+						KCaldavFirstInit);
+			if (PropertyExists(propertyKeys, KCaldavSynctoken))
+				iSynctoken
+						= calendarInfo->PropertyValueL(KCaldavSynctoken).AllocL();
+			if (PropertyExists(propertyKeys, KCaldavCtag))
+				iCTag = calendarInfo->PropertyValueL(KCaldavCtag).AllocL();
+			if (PropertyExists(propertyKeys, KCaldavManualSync))
+				iManualSync = GetBoolFromPropertiesL(calendarInfo,
+						KCaldavManualSync);
+			if (PropertyExists(propertyKeys, KCaldavTime))
+				iLastSyncTime = GetTimeFromPropertiesL(calendarInfo,
+						KCaldavTime);
+			if (PropertyExists(propertyKeys, KCaldavUrl))
+				iUrl = calendarInfo->PropertyValueL(KCaldavUrl).AllocL();
+			if (PropertyExists(propertyKeys, KCaldavUser))
+				iHttp->SetUserL(calendarInfo->PropertyValueL(KCaldavUser));
+			if (PropertyExists(propertyKeys, KCaldavPassword))
+				iHttp->SetPasswordL(calendarInfo->PropertyValueL(
+						KCaldavPassword));
+			if (PropertyExists(propertyKeys, KCaldavKeepServer))
+				iKeepServerEntry = GetBoolFromPropertiesL(calendarInfo,
+						KCaldavKeepServer);
+			if (PropertyExists(propertyKeys, KCaldavImmediateSync))
+				iImmediateSync = GetBoolFromPropertiesL(calendarInfo,
+						KCaldavImmediateSync);
+			if (PropertyExists(propertyKeys, KCaldavPastDays))
+				{
+				TPckgC<TTimeIntervalDays> pastdays(iPastDays);
+				pastdays.Set(calendarInfo->PropertyValueL(KCaldavPastDays));
+				iPastDays = pastdays();
+				}
+			if (PropertyExists(propertyKeys, KCaldavSyncInterval))
+				{
+				TPckgC<TTimeIntervalMinutes> syncinterval(iSyncInterval);
+				syncinterval.Set(calendarInfo->PropertyValueL(
+						KCaldavSyncInterval));
+				iSyncInterval = syncinterval();
+				}
+			// access point	    
+			}
+
+		CleanupStack::PopAndDestroy(propertyKeys);
+		CleanupStack::Pop(calendarInfo);
+		}
+	delete calendarInfo;
+	}
+
+/**
+ * CCalDavEngine::InitL
+ * check for correct url
+ * load most Caldav url properties
+ * do inital sync
+ */
+TInt CCalDavEngine::InitL()
+	{
+	// this is only needed to find a GlobalUID from a LocalUID, used after an event was deleted
+	// also used now for uploading of local events when only GlobalUID is know 
+	LocalLoopL(ELoopActionFillArray);
+
+	if (iFirstInit)
+		{
+		TInt err = GetCalendarUrlsL(NULL);
+		if (err == KErrArgument)
+			return KErrArgument;
+		GetOptionsL();
+		SetLastSyncTimeL();
+
+		TBool success;
+		// get all server items
+		if (iOptions.sync_collection)
+			success = WebDavSyncL();
+		else
+			success = ListL() == KErrNone;
+
+		if (!success)
+			return KErrGeneral;
+
+		// upload all local entries of this calendar to server
+		LocalLoopL(ELoopActionUpload);
+
+		if (iOptions.sync_collection)
+			SetSyncTokenL(GetSyncTokenL());
+		else
+			SetCTagL(GetCTagL());
+
+		iFirstInit = EFalse;
+		iEnabled = ETrue;
+		TPckgC<TBool> firstInit(iFirstInit);
+		SetCalendarInfoL(KCaldavFirstInit, firstInit); // this will set iEnabled as well
+		}
+	else
+		{
+		TInt err = GetCalendarUrlsL(NULL);
+		if (err == KErrArgument)
+			return KErrArgument;
+		GetOptionsL();
+		SetLastSyncTimeL();
+		iEnabled = ETrue;
+		SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
+		SyncL();
+		}
+
+	return KErrNone;
+	}
+
+/**
+ * CCalDavEngine::Completed
+ * Completed callback
+ */
+void CCalDavEngine::Completed(TInt aError)
+	{
+	if (aError == KErrNone)
+		{
+		CActiveScheduler::Stop();
+		}
+	else
+		iManualSync = true;
+	}
+
+/**
+ * CCalDavEngine::NotifyProgress
+ * NotifyProgress callback
+ */
+TBool CCalDavEngine::NotifyProgress()
+	{
+	return EFalse;
+	}
+
+/**
+ * CCalDavEngine::CalChangeNotification
+ * change item callback, sync to server
+ */
+void CCalDavEngine::CalChangeNotification(RArray<TCalChangeEntry> &aChangeItems)
+	{
+	for (TInt i = 0; i < aChangeItems.Count(); i++)
+		{
+		TRAP_IGNORE(HandleChangeL(aChangeItems[i].iChangeType, aChangeItems[i].iEntryType, aChangeItems[i].iEntryId));
+		}
+	}
+
+/**
+ * CCalDavEngine::CalendarInfoChangeNotificationL
+ * change callback, sync changed color or name to server
+ */
+void CCalDavEngine::CalendarInfoChangeNotificationL(RPointerArray<
+		CCalFileChangeInfo>& aCalendarInfoChangeEntries)
+	{
+	for (TInt i = 0; i < aCalendarInfoChangeEntries.Count(); i++)
+		{
+		if ((aCalendarInfoChangeEntries[i]->FileNameL() == *iCalendar)
+				&& (aCalendarInfoChangeEntries[i]->ChangeType()
+						== MCalFileChangeObserver::ECalendarInfoUpdated))
+			{
+			TRAP_IGNORE(HandleCalendarInfoChangeL());
+			}
+		}
+	}
+
+/**
+ * CCalDavEngine::HandleCalendarInfoChangeL
+ * sync changed color or name to server
+ */
+void CCalDavEngine::HandleCalendarInfoChangeL()
+	{
+	if (iHttp)
+		{
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		CCalCalendarInfo* info = iCalSession->CalendarInfoL();
+		CleanupStack::PushL(info);
+
+		HBufC8* name =
+				CnvUtfConverter::ConvertFromUnicodeToUtf8L(info->NameL());
+		CleanupStack::PushL(name);
+
+		TRgb color = info->Color();
+		_LIT8(KColorformat,"#%02x%02x%02xFF");
+		TBuf8<9> colorbuf;
+		colorbuf.Format(KColorformat, color.Red(), color.Green(), color.Blue());
+
+		HBufC8* patch = HBufC8::NewLC(KColorDisplayStart().Length()
+				+ colorbuf.Length() + KColorDisplayMiddle().Length()
+				+ name->Length() + KColorDisplayEnd().Length());
+		patch->Des().Append(KColorDisplayStart);
+		patch->Des().Append(colorbuf);
+		patch->Des().Append(KColorDisplayMiddle);
+		patch->Des().Append(*name);
+		patch->Des().Append(KColorDisplayEnd);
+		iHttp->ProppatchL(*iUrl, *patch, response);
+		CleanupStack::PopAndDestroy(4); // response, info, name, patch
+		}
+	}
+
+/**
+ * CCalDavEngine::HandleChangeL
+ * change item callback, sync to server
+ */
+void CCalDavEngine::HandleChangeL(
+		MCalChangeCallBack2::TChangeType &aChangeType,
+		MCalChangeCallBack2::TChangeEntryType &aEntryType, TCalLocalUid &aUid)
+	{
+	switch (aChangeType)
+		{
+		case MCalChangeCallBack2::EChangeAdd:
+		case MCalChangeCallBack2::EChangeModify:
+			{
+			if (iImmediateSync)
+				UploadEntryL(aUid, aChangeType, aEntryType);
+			else
+				// enable manual sync for the next sync interval
+				SyncFailedL();
+			break;
+			}
+		case MCalChangeCallBack2::EChangeDelete:
+			{
+			if (iImmediateSync)
+				DeleteEntryL(aUid);
+			else
+				{
+				iDeletedEntries.Append(aUid);
+				SyncFailedL();
+				}
+			break;
+			}
+		case MCalChangeCallBack2::EChangeUndefined:
+			{
+			// upload new and modified entries to server
+			UploadModifiedSinceDateL();
+
+			// Find locally deleted ones and delete on server
+			DeleteRemovedEntriesOnServerL();
+
+			break;
+			}
+		}
+	}
+
+/**
+ * CCalDavEngine::EnableL
+ * enable Caldav sync
+ */
+TInt CCalDavEngine::EnableL()
+	{
+	if (!iCalEntryView) //do not use iEnabled here,might be set already in ConstructL()
+		{
+		TInt aErr = CreateCalObjectsL();
+		if ((aErr == KErrNone) && (InitL() == KErrNone))
+			{
+			iTimer->Cancel();
+			TInt ticktime = iSyncInterval.Int() == 0 ? 1 : iSyncInterval.Int();
+			const TUint64 tickInterval = 1000000 * 60 * ticktime;
+			iTimer->Start(tickInterval, tickInterval,
+					TCallBack(SyncTickL, this));
+			// register change notification
+			RegisterL();
+			return KErrNone;
+			}
+		else
+			{
+			iEnabled = EFalse;
+			SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
+			DeleteCalObjects();
+			return KErrArgument;
+			}
+		}
+	return KErrNone;
+	}
+
+/**
+ * CCalDavEngine::DeleteCalObjects
+ * delete all calendar objects
+ */
+void CCalDavEngine::DeleteCalObjects()
+	{
+	delete iCalIter;
+	iCalIter = NULL;
+	delete iCalEntryView;
+	iCalEntryView = NULL;
+	delete iCalImporter;
+	iCalImporter = NULL;
+	delete iCalExporter;
+	iCalExporter = NULL;
+	if (iCalSession)
+		{
+		iCalSession->StopChangeNotification();
+		iCalSession->StopFileChangeNotification();
+		delete iCalSession;
+		}
+	iCalSession = NULL;
+	}
+
+/**
+ * CCalDavEngine::CreateCalObjectsL
+ * create all calendar objects
+ */
+TInt CCalDavEngine::CreateCalObjectsL()
+	{
+	iCalSession = CCalSession::NewL();
+	TRAPD(aErr,iCalSession->OpenL(*iCalendar));
+	iCalExporter = CCalenExporter::NewL(*iCalSession);
+	iCalImporter = CCalenImporter::NewL(*iCalSession);
+	iCalEntryView = CCalEntryView::NewL(*iCalSession);
+	iCalIter = CCalIter::NewL(*iCalSession);
+	return aErr;
+	}
+
+/**
+ * CCalDavEngine::DisableL
+ * disable sync
+ */
+void CCalDavEngine::DisableL()
+	{
+	if (iEnabled)
+		{
+		iTimer->Cancel();
+		iEnabled = EFalse;
+		SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
+		DeleteCalObjects();
+		}
+	}
+
+/**
+ * CCalDavEngine::EnabledSync
+ * check for enabled sync
+ */
+TBool CCalDavEngine::EnabledSync()
+	{
+	return iEnabled;
+	}
+
+/**
+ * CCalDavEngine::TimeReportL
+ * do a CalDav time report
+ */
+TInt CCalDavEngine::TimeReportL(TBool VEVENT, const TDesC8 &aStart,
+		TBool aDelete)
+	{
+	CBufFlat* body = CBufFlat::NewL(EXPANDSIZE_BIG);
+	CleanupStack::PushL(body);
+
+	body->InsertL(body->Size(), VEVENT ? KTimeStartEVENT() : KTimeStartTODO());
+	body->InsertL(body->Size(), aStart); // "20090509T220000Z"/>
+	body->InsertL(body->Size(), KTimeEnd);
+
+	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
+	CleanupStack::PushL(response);
+	TInt ret = iHttp->ReportL(*iUrl, body->Ptr(0), response);
+
+	if (ret == MULTISTATUS)
+		ret = aDelete ? ParseResponsesDeleteL(response->Ptr(0))
+				: ParseResponsesL(response->Ptr(0));
+	else
+		ret = KErrGeneral;
+
+	CleanupStack::PopAndDestroy(response);
+	CleanupStack::PopAndDestroy(body);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::ListL
+ * get events either using time report or basic propfind
+ */
+TInt CCalDavEngine::ListL()
+	{
+	if (iOptions.calendar_access)
+		{
+		TTime syncstart;
+		syncstart.HomeTime();
+		syncstart = syncstart - iPastDays;
+		TBuf<100> nowStr;
+		syncstart.FormatL(nowStr, KFormatString);
+		TBuf8<100> nowStrAdd;
+		nowStrAdd.Append(nowStr);
+
+		TInt eventreturn = KErrNone;
+		if (iOptions.VEVENT)
+			eventreturn = TimeReportL(ETrue, nowStrAdd);
+
+		TInt todoreturn = KErrNone;
+		if (iOptions.VTODO)
+			todoreturn = TimeReportL(EFalse, nowStrAdd);
+
+		return (eventreturn == KErrNone) && (todoreturn == KErrNone) ? KErrNone
+				: KErrGeneral;
+		}
+	else
+		{
+		// use PROPFIND report
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt ret = iHttp->PropfindL(*iUrl, KPropList, response, EFalse);
+		if (ret == MULTISTATUS)
+			ret = ParseResponsesL(response->Ptr(0));
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(response);
+		return ret;
+		}
+	}
+
+/**
+ * CCalDavEngine::SyncL
+ * sync a calendar
+ */
+TInt CCalDavEngine::SyncL()
+	{
+	if (iUrl)
+		{
+		if (iOptions.sync_collection)
+			return WebDavSyncL();
+		else
+			return ManualSyncL();
+		}
+	return KErrGeneral;
+	}
+
+/**
+ * CCalDavEngine::ManualSyncL
+ * if sync failed previously, try again manually
+ */
+TBool CCalDavEngine::ManualSyncL()
+	{
+	TBool client = ClientChangesL();
+	if (iOptions.sync_ctag)
+		{
+		HBufC8 *newCTag = GetCTagL();
+		TBool server = ETrue;
+		if ((CTag() != *newCTag) && (*newCTag != KNullDesC8))
+			{
+			server = ServerChangesL();
+			if (server)
+				SetCTagL(newCTag);
+			else
+				delete newCTag;
+			}
+		else
+			delete newCTag;
+
+		return client || server;
+		}
+	else
+		{
+		TBool server = ServerChangesL();
+		return client || server;
+		}
+	}
+
+/**
+ * CCalDavEngine::ServerChangesL
+ * sync server changes
+ */
+TBool CCalDavEngine::ServerChangesL()
+	{
+	// loop over all server items to find new and modified entries
+	// uses either propfind or calendar-query
+	TInt ret = ListL();
+
+	// loop over all local items to find deleted ones on the server
+	LocalLoopL(ELoopActionDeleteLocal);
+
+	return ret == KErrNone;
+	}
+
+/**
+ * CCalDavEngine::LocalLoopL
+ * loop over local calendar store
+ */
+TInt CCalDavEngine::LocalLoopL(TLocalLoopAction aAction)
+	{
+	TBuf8<URLMAX> iter = iCalIter->FirstL();
+	TBuf8<URLMAX> url;
+	while (iter != KNullDesC8)
+		{
+		url.Append(*iUrl);
+		url.Append(iter);
+		url.Append(KIcs);
+		switch (aAction)
+			{
+			case ELoopActionDeleteLocal:
+				{
+				if (HeadL(iter) == NOTFOUND)
+					DeleteLocalEntryL(url);
+				break;
+				}
+			case ELoopActionFillArray:
+				{
+				RPointerArray<CCalEntry> entryArray;
+				CleanupClosePushL(entryArray);
+				iCalEntryView->FetchL(iter, entryArray);
+				if (entryArray.Count())
+					{
+					iLocalUidArray.Append(entryArray[0]->LocalUidL());
+					iGlobalUidArray.Append(entryArray[0]->UidL());
+					}
+				entryArray.ResetAndDestroy();
+				CleanupStack::PopAndDestroy(&entryArray);
+
+				break;
+				}
+			case ELoopActionUpload:
+				{
+				TInt pos = iGlobalUidArray.Find(iter);
+				if ((pos != KErrNotFound) && (iLocalUidArray.Count() > pos))
+					UploadEntryL(iLocalUidArray[pos],
+							MCalChangeCallBack2::EChangeAdd,
+							MCalChangeCallBack2::EChangeEntryAll);
+				break;
+				}
+			}
+		url.Delete(0, url.Length());
+		iter = iCalIter->NextL();
+		}
+	return KErrNone;
+	}
+
+/**
+ * CCalDavEngine::ParseResponsesDeleteL
+ * process a recieved multistatus response
+ */
+TInt CCalDavEngine::ParseResponsesDeleteL(const TDesC8 &aDocument)
+	{
+	TInt ret = KErrNone;
+	RXmlEngDocument document = iDomParser.ParseL(aDocument);
+	CleanupClosePushL(document);
+	if (document.NotNull())
+		{
+		// this method works for response as well as sync-response
+		// do not use GetElementsByTagNameL for one specific responses directly	
+		TXmlEngElement ResponseListTop;
+		SearchL(document, KMultistatus, KNullDesC8, ResponseListTop);
+
+		RXmlEngNodeList<TXmlEngNode> ResponseList;
+		CleanupClosePushL(ResponseList);
+		ResponseListTop.GetChildNodes(ResponseList);
+
+		while (ResponseList.HasNext())
+			{
+			TXmlEngNode node = ResponseList.Next();
+			if (node.NodeType() == TXmlEngNode::EElement)
+				{
+				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
+				// don't do anything with home itself
+				if ((href.Right(KIcs().Length()) == KIcs))
+					{
+					if (!DoesEntryExistL(href))
+						DeleteEntryL(href);
+					}
+				}
+			}
+		CleanupStack::PopAndDestroy(&ResponseList);
+
+		}
+	else
+		ret = KErrArgument;
+	CleanupStack::PopAndDestroy(&document);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::ParseResponsesL
+ * process a recieved multistatus response
+ */
+TInt CCalDavEngine::ParseResponsesL(RXmlEngDocument &aDocument, TBool aMultiget)
+	{
+	TInt ret = KErrNone;
+	if (aDocument.NotNull())
+		{
+		CDesC8ArrayFlat *multiget = NULL;
+		if (iOptions.MULTIGET)
+			{
+			multiget = new (ELeave) CDesC8ArrayFlat(ARRAYEXPAND);
+			CleanupStack::PushL(multiget);
+			}
+
+		// this method works for response as well as sync-response
+		// do not use GetElementsByTagNameL for one specific responses directly	
+		TXmlEngElement ResponseListTop;
+		SearchL(aDocument, KMultistatus, KNullDesC8, ResponseListTop);
+
+		RXmlEngNodeList<TXmlEngNode> ResponseList;
+		CleanupClosePushL(ResponseList);
+		ResponseListTop.GetChildNodes(ResponseList);
+
+		while (ResponseList.HasNext())
+			{
+			TXmlEngNode node = ResponseList.Next();
+			if (node.NodeType() == TXmlEngNode::EElement)
+				{
+				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
+				//do not use Search, only looking for first childs,
+				//as D:propstat has D:status as well
+				RXmlEngNodeList<TXmlEngElement> statuslist;
+				CleanupClosePushL(statuslist);
+				node.AsElement().GetElementsByTagNameL(statuslist, KStatus,
+						KDav);
+				//only one or zero item
+				HBufC8* status =
+						statuslist.Count() ? statuslist.Next().Value().AllocL()
+								: KNullDesC8().AllocL();
+				CleanupStack::PopAndDestroy(&statuslist);
+				CleanupStack::PushL(status);
+				status->Des().LowerCase();
+				TPtrC8 etag = SearchL(node, KEtag, KNullDesC8);
+				RBuf8 calendardata;
+				SearchL(node, KCalendarData, KNullDesC8, calendardata);
+				calendardata.CleanupClosePushL();
+
+				// don't do anything with home itself
+				if (href.Right(KIcs().Length()) == KIcs)
+					{
+					if ((*status == KHTTP200) || (*status == KHTTP201) || (*status == KNullDesC8))
+						{
+						if ((calendardata == KNullDesC8))
+							{
+							if (aMultiget)
+								{
+								// ATTENTION: an empty response to a multiget should never happen
+								// data wrapped inside CDATA, e.g. bedework ??
+								}
+							else
+								//TOOD: if this is a webdav sync response, we should skip the etag check
+								AddModifyLocalEntryL(href, etag, multiget);
+							}
+						else
+							{
+							// response to a multiget or time-range report, we now already have everything we need
+							StoreEntryL(calendardata, etag);
+							}
+						}
+					else if (*status == KHTTP404)
+						{
+						if (iOptions.sync_collection)
+							{
+							// if this is an initial sync without token, 
+							// this should be ignored, Sun Server bug!!!
+							if (SyncToken() != KNullDesC8)
+								DeleteLocalEntryL(href);
+							}
+						else
+							{
+							//multiget answer, but deleted in the meantime, should delete locally as well
+							DeleteLocalEntryL(href);
+							}
+						}
+					}
+				CleanupStack::PopAndDestroy(&calendardata);
+				CleanupStack::PopAndDestroy(status);
+				}
+			}
+		CleanupStack::PopAndDestroy(&ResponseList);
+
+		if (iOptions.MULTIGET)
+			{
+			if (multiget->Count())
+				{
+				DownloadEntryL(multiget);
+				multiget->Reset();
+				}
+			CleanupStack::PopAndDestroy(multiget);
+			}
+		}
+	else
+		ret = KErrArgument;
+
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::ParseResponsesL
+ * process a recieved multistatus response
+ */
+TInt CCalDavEngine::ParseResponsesL(const TDesC8 &aDocument, TBool aMultiget)
+	{
+#ifdef _DEBUG
+	_LIT(KFilename,"c:\\logs\\caldav\\parseresonseslatest.txt");
+	ExportToFileNameL(aDocument, KFilename);
+#endif
+
+	RXmlEngDocument document = iDomParser.ParseL(aDocument);
+	CleanupClosePushL(document);
+	TInt ret = ParseResponsesL(document, aMultiget);
+	CleanupStack::PopAndDestroy(&document);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::StoreEntryL
+ * store event in local store
+ */
+#ifdef ETAG
+TInt CCalDavEngine::StoreEntryL(const TDesC8 &aBuf, const TDesC8 &aEtag)
+#else
+TInt CCalDavEngine::StoreEntryL(const TDesC8 &aBuf, const TDesC8 &/*aEtag*/)
+#endif
+	{
+#ifdef _DEBUG
+	_LIT(KFileName2, "C:\\logs\\caldav\\testing_import.txt");
+	ExportToFileNameL(aBuf, KFileName2);
+#endif
+
+	HBufC8* buffer = HBufC8::NewL(aBuf.Length() + 500);
+	buffer->Des().Append(aBuf);
+	TPtr8 ptr = buffer->Des();
+	CalDavUtils::FixImportIssues(ptr);
+
+	RPointerArray<CCalEntry> Array;
+	CleanupClosePushL(Array);
+	RDesReadStream ReadStream;
+	ReadStream.Open(ptr);
+	CleanupClosePushL(ReadStream);
+#ifdef _DEBUG
+	_LIT(KFileName, "C:\\logs\\caldav\\testing_import_fixed.txt");
+	ExportToFileNameL(ptr, KFileName);
+#endif
+	TRAPD(error, iCalImporter->ImportICalendarL(ReadStream,Array));
+	CleanupStack::PopAndDestroy(&ReadStream); // calls close on rSteam												
+	if ((error == KErrNone) && (Array.Count()))
+		{
+		iCalIntermimUtils2->StoreL(*iCalEntryView, *Array[0], ETrue); // or should last one be EFalse??
+		TInt pos = iLocalUidArray.Find(Array[0]->LocalUidL());
+		if (pos == KErrNotFound)
+			{
+			iLocalUidArray.Append(Array[0]->LocalUidL());
+			iGlobalUidArray.Append(Array[0]->UidL());
+			}
+#ifdef ETAG
+		Array[0]->SetETag(aEtag);
+#endif
+		}
+	Array.ResetAndDestroy();
+	CleanupStack::PopAndDestroy(&Array);
+
+	delete buffer;
+	return error;
+	}
+
+/**
+ * CCalDavEngine::WebDavSyncReportL
+ * webdav sync report
+ * http://tools.ietf.org/html/draft-daboo-webdav-sync-02
+ */
+TInt CCalDavEngine::WebDavSyncReportL(TBool aSynctoken)
+	{
+	HBufC8 *Buf = HBufC8::NewL(KSync().Length() + SyncToken().Length());
+	TPtrC8 token = SyncToken();
+	if (aSynctoken)
+		Buf->Des().Format(KSync, &token);
+	else
+		Buf->Des().Format(KSync, &KNullDesC8());
+	CleanupStack::PushL(Buf);
+
+	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
+	CleanupStack::PushL(response);
+	TInt ret = iHttp->ReportL(*iUrl, *Buf, response);
+
+	if (ret == MULTISTATUS)
+		{
+		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+		CleanupClosePushL(document);
+		if (document.NotNull())
+			{
+			TPtrC8 Token = SearchL(document, KSynctoken, KNullDesC8);
+			if ((Token != KNullDesC8) && (Token != SyncToken()))
+				{
+				ret = ParseResponsesL(document);
+				//store newest token
+				if (ret == KErrNone)
+					SetSyncTokenL(Token.AllocL());
+				}
+			else
+				ret = KErrNone;
+			}
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(&document);
+		}
+	CleanupStack::PopAndDestroy(response);
+	CleanupStack::PopAndDestroy(Buf);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::WebDavSyncL
+ * sync using webdav sync
+ * http://tools.ietf.org/html/draft-daboo-webdav-sync-02
+ */
+TBool CCalDavEngine::WebDavSyncL()
+	{
+	if (iHttp)
+		{
+		// commit any left over client changes
+		TBool RetClient = ClientChangesL();
+		// get all changes from server
+		TInt ret = WebDavSyncReportL(ETrue);
+		if (ret == CONFLICT)
+			ret = WebDavSyncReportL(EFalse);
+		return (ret == KErrNone) && RetClient;
+		}
+	return EFalse;
+	}
+
+/**
+ * CCalDavEngine::GetUIDByUrl
+ * parse url to find UID
+ */
+TPtrC8 CCalDavEngine::GetUIDByUrl(const TDesC8 &aUrl)
+	{
+	TPtrC8 UID;
+	TInt Pos = aUrl.LocateReverse('/');
+	TInt Pos2 = aUrl.Find(KIcs);
+
+	if ((Pos != KErrNotFound) && (Pos2 != KErrNotFound))
+		UID.Set(aUrl.Mid(Pos + 1, Pos2 - Pos - 1));
+	else
+		{
+		if (Pos != KErrNotFound)
+			UID.Set(aUrl.Mid(Pos + 1, aUrl.Length() - Pos - 1));
+		else if (Pos2 != KErrNotFound)
+			UID.Set(aUrl.Left(aUrl.Length() - KIcs().Length()));
+		else
+			UID.Set(aUrl);
+		}
+
+	return UID;
+	}
+
+/**
+ * CCalDavEngine::DoesEntryExistL
+ * check if entry exists in local store
+ */
+unsigned long CCalDavEngine::DoesEntryExistL(const TDesC8 &aUrl)
+	{
+	// check if we already have it locally by uid
+	RPointerArray<CCalEntry> entryArray;
+	CleanupClosePushL(entryArray);
+	iCalEntryView->FetchL(GetUIDByUrl(aUrl), entryArray);
+	// get parent 
+	CCalEntry *entry = entryArray.Count() ? entryArray[0] : NULL;
+	TInt ret = entry ? entry->LocalUidL() : 0;
+	entryArray.ResetAndDestroy();
+	CleanupStack::PopAndDestroy(&entryArray);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::ETagMatchL
+ * checks for equal ETag
+ */
+TBool CCalDavEngine::ETagMatchL(const TDesC8& /*aUrl*/, const TDesC8& /*aETag*/)
+	{
+#ifdef ETAG
+	// check if we already have it locally by uid
+	RPointerArray<CCalEntry> entryArray;
+	CleanupClosePushL(entryArray);
+	iCalEntryView->FetchL(GetUIDByUrl(aUrl), entryArray);
+	// get parent 
+	CCalEntry *entry = entryArray.Count() ? entryArray[0] : NULL;
+	TBool ret = entry ? entry->ETag() == aETag : EFalse;
+	entryArray.ResetAndDestroy();
+	CleanupStack::PopAndDestroy(&entryArray);
+	return ret;
+#else
+	return EFalse;
+#endif
+	}
+
+/**
+ * CCalDavEngine::AddModifyLocalEntryL
+ * add or modify existing event
+ */
+TInt CCalDavEngine::AddModifyLocalEntryL(const TDesC8 &aUrl,
+		const TDesC8 &aETag, CDesC8ArrayFlat* aArray)
+	{
+	// check if we have the entry locally
+	// check for etag if we have the latest version, if not, download and import or add to multiget request
+	if (!ETagMatchL(aUrl, aETag))
+		{
+		if (aArray)
+			aArray->AppendL(aUrl);
+		else
+			DownloadEntryL(aUrl);
+		}
+	return KErrNone;
+	}
+
+/**
+ * CCalDavEngine::DownloadEntryL
+ * download entries using multiget from server
+ */
+TInt CCalDavEngine::DownloadEntryL(CDesC8Array* aArray)
+	{
+	TInt ret = KErrNone;
+	TInt64 remainder;
+	TInt64 result = Math::DivMod64(aArray->Count(), MULTIGETSPLIT, remainder);
+
+	// split large multigets request into several smaller ones
+	for (TInt64 l = 0; l <= result; l++)
+		{
+		// do the multiget request and pass it to parserepsonses again to read in the data
+		CBufFlat* body = CBufFlat::NewL(EXPANDSIZE_BIG);
+		CleanupStack::PushL(body);
+
+		body->InsertL(body->Size(), KMultistart);
+		for (TInt64 i = 0; i <= ((l == result) ? remainder - 1 : MULTIGETSPLIT
+				- 1); i++)
+			{
+			body->InsertL(body->Size(), KHrefstart);
+			body->InsertL(body->Size(), (*aArray)[MULTIGETSPLIT * l + i]);
+			body->InsertL(body->Size(), KHrefend);
+			}
+		body->InsertL(body->Size(), KMultiend);
+
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
+		CleanupStack::PushL(response);
+		TInt Return = iHttp->ReportL(*iUrl, body->Ptr(0), response);
+
+		if (Return == MULTISTATUS)
+			{
+			TInt parsereturn = ParseResponsesL(response->Ptr(0), ETrue);
+			// if it failed before, we do not want to override this error
+			ret = (ret == KErrNone) ? parsereturn : ret;
+			}
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(response);
+		CleanupStack::PopAndDestroy(body);
+
+		}
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::DownloadEntryL
+ * download entry from server
+ */
+TInt CCalDavEngine::DownloadEntryL(const TDesC8 &aUrl)
+	{
+	TBuf8<URLMAX> url;
+	url.Append(*iUrl);
+	url.Append(GetUIDByUrl(aUrl));
+	url.Append(KIcs);
+
+	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+	CleanupStack::PushL(response);
+	TInt ret = iHttp->GetL(url, response);
+	if (ret == OK)
+		ret = StoreEntryL(response->Ptr(0), iHttp->ETag());
+	else
+		ret = KErrGeneral;
+	CleanupStack::PopAndDestroy(response);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::DeleteLocalEntryL
+ * delete an event from local store
+ */
+TInt CCalDavEngine::DeleteLocalEntryL(const TDesC8 &aUID)
+	{
+	CDesC8ArrayFlat * Array = new (ELeave) CDesC8ArrayFlat(ARRAYEXPAND);
+	CleanupStack::PushL(Array);
+	Array->AppendL(GetUIDByUrl(aUID));
+	// we could have delete it ourselves, so it is already gone
+	TRAPD(error, iCalEntryView->DeleteL(*Array));
+	Array->Reset();
+	CleanupStack::PopAndDestroy(Array);
+	return error;
+	}
+
+/**
+ * CCalDavEngine::DeleteRemovedEntriesOnServerL
+ * check for removed entries on server
+ */
+TInt CCalDavEngine::DeleteRemovedEntriesOnServerL()
+	{
+	if (iOptions.calendar_access)
+		{
+		TTime syncstart;
+		syncstart.HomeTime();
+		syncstart = syncstart - iPastDays;
+		TBuf<100> nowStr;
+		syncstart.FormatL(nowStr, KFormatString);
+		TBuf8<100> nowStrAdd;
+		nowStrAdd.Append(nowStr);
+
+		TInt eventreturn = KErrNone;
+		if (iOptions.VEVENT)
+			eventreturn = TimeReportL(ETrue, nowStrAdd, ETrue);
+
+		TInt todoreturn = KErrNone;
+		if (iOptions.VTODO)
+			todoreturn = TimeReportL(EFalse, nowStrAdd, ETrue);
+
+		return (eventreturn == KErrNone) && (todoreturn == KErrNone) ? KErrNone
+				: KErrGeneral;
+		}
+	else
+		{
+		// use PROPFIND report
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt ret = iHttp->PropfindL(*iUrl, KPropList, response, EFalse);
+		if (ret == MULTISTATUS)
+			ret = ParseResponsesDeleteL(response->Ptr(0));
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(response);
+		return ret;
+		}
+
+	}
+
+/**
+ * CCalDavEngine::UploadModifiedSinceDateL
+ * check for any modified data after last sync time
+ */
+TBool CCalDavEngine::UploadModifiedSinceDateL()
+	{
+	TBool manualsync = EFalse;
+	// upload modified and newly create ones 
+	RArray<TCalLocalUid> *Ids = new (ELeave) RArray<TCalLocalUid> (ARRAYEXPAND);
+	iCalEntryView->GetIdsModifiedSinceDateL(iLastSyncTime, *Ids);
+	for (TInt i = 0; i < Ids->Count(); i++)
+		{
+		TCalLocalUid id = (*Ids)[i];
+		TInt ret = UploadEntryL(id, MCalChangeCallBack2::EChangeUndefined,
+				MCalChangeCallBack2::EChangeEntryAll);
+		// TOOD: if it fails during upload, ignore
+		// if it fails due to internet connection, try again
+		if (ret != KErrNone)
+			manualsync = ETrue;
+		}
+	Ids->Reset();
+	delete Ids;
+	return manualsync;
+	}
+
+/**
+ * CCalDavEngine::ClientChangesL
+ * check for left over local client changes
+ */
+TBool CCalDavEngine::ClientChangesL()
+	{
+	if (iCalEntryView && iManualSync)
+		{
+		iManualSync = EFalse;
+
+		// upload modified and newly create ones 
+		iManualSync = UploadModifiedSinceDateL();
+
+		// delete locally deleted entries on server 
+		for (TInt i = iDeletedEntries.Count() - 1; i >= 0; --i)
+			{
+			TInt ret = DeleteEntryL(iDeletedEntries[i]);
+			if (ret == KErrNone)
+				iDeletedEntries.Remove(i);
+
+			}
+
+		iManualSync = iDeletedEntries.Count() ? ETrue : EFalse;
+
+		TPckgC<TBool> manualSync(iManualSync);
+		SetCalendarInfoL(KCaldavManualSync, manualSync);
+		}
+
+	return ETrue;
+	}
+
+/**
+ * CCalDavEngine::MkcalendarL
+ * create a new calendar on the server
+ */
+TInt CCalDavEngine::MkcalendarL(const TDesC8 &aName)
+	{
+	if (iOptions.MKCALENDAR)
+		{
+		TBuf8<URLMAX> url;
+		url.Append(*iHome);
+		url.Append(aName);
+		url.Append(KSlash);
+
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+
+		// TOOD: initialize with name, body etc.
+		TInt ret = iHttp->MkCalendarL(url, KNullDesC8, response);
+
+		if ((ret == CREATED) || (ret == OK))
+			ret = KErrNone;
+		else if ((ret == NOTALLOWED) || (ret == FORBIDDEN))
+			ret = KErrArgument;
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(response);
+		return ret;
+		}
+	else
+		return KErrNotSupported;
+	}
+
+/**
+ * CCalDavEngine::DeleteCalendarL
+ * delete a calendar on the server
+ */
+TInt CCalDavEngine::DeleteCalendarL(const TDesC8 &aName)
+	{
+	if (iOptions.MKCALENDAR)
+		{
+		TBuf8<URLMAX> url;
+		url.Append(*iHome);
+		url.Append(aName);
+		url.Append(KSlash);
+
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt ret = iHttp->DeleteL(url);
+		if ((ret == NOCONTENT) || (ret == OK))
+			ret = KErrNone;
+		else
+			ret = KErrGeneral;
+		CleanupStack::PopAndDestroy(response);
+		return ret;
+		}
+	else
+		return KErrNotSupported;
+	}
+
+/**
+ * CCalDavEngine::HeadL
+ * check for existence of an entry on server
+ */
+TInt CCalDavEngine::HeadL(const TDesC8 &aUID)
+	{
+	// special handing for yahoo neccessary
+	// after deleting an event, it is still there and findable with HEAD
+	_LIT8(KYahoo,"yahoo");
+	_LIT8(KTrash,"trash");
+
+	TBuf8<URLMAX> url;
+	url.Append(*iUrl);
+	url.Append(aUID);
+	url.Append(KIcs);
+	if (iUrl->Find(KYahoo) == KErrNotFound)
+		{
+		TInt head = iHttp->HeadL(url);
+		return (head == NOCONTENT) || (head == OK) ? OK : head;
+		}
+	else
+		{
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt ret = iHttp->PropfindL(url, KNullDesC8, response);
+
+		if (ret == MULTISTATUS)
+			{
+			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+			CleanupClosePushL(document);
+			if (document.NotNull())
+				{
+				HBufC8* href = SearchL(document, KHref, KNullDesC8).AllocL();
+				href->Des().LowerCase();
+				ret = href->Find(KTrash) == KErrNotFound ? OK : NOTFOUND;
+				delete href;
+				}
+			CleanupStack::PopAndDestroy(&document);
+			CleanupStack::PopAndDestroy(response);
+			return ret;
+			}
+		else
+			{
+			CleanupStack::PopAndDestroy(response);
+			return NOTFOUND;
+			}
+		}
+	}
+
+/**
+ * CCalDavEngine::DeleteEntryL
+ * delete entry on server
+ */
+TInt CCalDavEngine::DeleteEntryL(const TDesC8 &aUid)
+	{
+	TBuf8<URLMAX> url;
+	url.Append(*iBaseUrl);
+	url.Append(aUid);
+	return iHttp->DeleteL(url);
+	}
+
+/**
+ * CCalDavEngine::DeleteEntryL
+ * delete entry on server
+ */
+TInt CCalDavEngine::DeleteEntryL(const TCalLocalUid &aUid)
+	{
+	TInt Ret = KErrNone;
+	// find the filename for a given local UID
+	TInt aPos = iLocalUidArray.Find(aUid);
+	if (aPos != KErrNotFound)
+		{
+		TBuf8<URLMAX> url;
+		url.Append(*iUrl);
+		url.Append(iGlobalUidArray[aPos]);
+		url.Append(KIcs);
+
+#ifdef ETAG
+		CCalEntry* entry = iCalEntryView->FetchL(aUid);
+		CleanupStack::PushL(entry);
+		TInt Return = entry ? iHttp->DeleteL(url, entry->ETag())
+		: iHttp->DeleteL(url);
+		CleanupStack::PopAndDestroy(entry);
+#else
+		TInt Return = iHttp->DeleteL(url);
+#endif
+
+		if ((Return == NOCONTENT) || (Return == OK))
+			{
+			SetLastSyncTimeL();
+			}
+		else if (Return == PRECONDFAILED)
+			{
+			// someone modified this in the meantime
+			// ask user if he wants the new event or still delete it
+			TBool modify = EFalse;
+			if (modify)
+				DownloadEntryL(url);
+			else
+				iHttp->DeleteL(url);
+			}
+		else if (Return == NOTFOUND)
+			{
+			// someone deleted this already
+			Ret = KErrGeneral;
+			}
+		else if (Return == FORBIDDEN)
+			{
+			// event read-only
+			Ret = KErrGeneral;
+			}
+		else
+			{
+			Ret = KErrGeneral;
+			SyncFailedL();
+			TInt pos = iDeletedEntries.Find(aUid);
+			if (pos == KErrNotFound)
+				iDeletedEntries.Append(aUid);
+			}
+		}
+	else
+		Ret = KErrGeneral;
+	return Ret;
+	}
+
+/**
+ * CCalDavEngine::UploadEntryL
+ * upload entry to server
+ */
+TInt CCalDavEngine::UploadEntryL(CCalEntry* aEntry,
+		MCalChangeCallBack2::TChangeType aChangeType,
+		MCalChangeCallBack2::TChangeEntryType aEntryType)
+	{
+	if (aEntry)
+		{
+		TInt ret = KErrNone;
+		TBool upload = EFalse;
+		switch (aEntryType)
+			{
+			case MCalChangeCallBack2::EChangeEntryEvent:
+			case MCalChangeCallBack2::EChangeEntryTodo:
+				{
+				upload = aEntry && ((MCalChangeCallBack2::EChangeEntryEvent
+						&& iOptions.VEVENT)
+						|| (MCalChangeCallBack2::EChangeEntryTodo
+								&& iOptions.VTODO));
+				break;
+				}
+			case MCalChangeCallBack2::EChangeEntryAll:
+				{
+				if (aEntry)
+					{
+					switch (aEntry->EntryTypeL())
+						{
+						case CCalEntry::EAppt:
+						case CCalEntry::EAnniv:
+						case CCalEntry::EEvent:
+						case CCalEntry::EReminder:
+							{
+							upload = iOptions.VEVENT;
+							break;
+							}
+						case CCalEntry::ETodo:
+							{
+							upload = iOptions.VTODO;
+							break;
+							}
+						}
+					}
+
+				}
+			}
+		if (upload)
+			{
+			CBufFlat* BufFlat = CBufFlat::NewL(EXPANDSIZE_SMALL);
+			CleanupStack::PushL(BufFlat);
+			RBufWriteStream writeStream(*BufFlat);
+			CleanupClosePushL(writeStream);
+			iCalExporter->ExportICalL(*aEntry, writeStream);
+			writeStream.CommitL();
+			CleanupStack::PopAndDestroy(&writeStream);
+
+			HBufC8* buffer = BufFlat->Ptr(0).AllocL();
+			CleanupStack::PopAndDestroy(BufFlat);
+			CleanupStack::PushL(buffer);
+			TPtr8 ptr = buffer->Des();
+			CalDavUtils::FixExportIssues(ptr);
+
+#ifdef _DEBUG
+			ExportToFileL(aEntry, iCalExporter);
+			_LIT(KFileName, "C:\\logs\\caldav\\testing_export_fixed.txt");
+			ExportToFileNameL(ptr, KFileName);
+#endif
+
+			TBuf8<URLMAX> url;
+			url.Append(*iUrl);
+			url.Append(aEntry->UidL());
+			url.Append(KIcs);
+
+			CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+			CleanupStack::PushL(response);
+
+#ifdef ETAG
+			TPtrC8 etag = aEntry->GetETag();
+			TBool newentry = (aChangeType == MCalChangeCallBack2::EChangeAdd)
+			|| ((aChangeType == MCalChangeCallBack2::EChangeUndefined)
+					&& (etag == KNullDesC8));
+			TInt Ret = newentry ? iHttp->PutL(url, *buffer, response)
+			: iHttp->PutL(url, *buffer, response, etag);
+#else
+			TBool newentry = (aChangeType == MCalChangeCallBack2::EChangeAdd)
+					|| (aChangeType == MCalChangeCallBack2::EChangeUndefined);
+			TInt Ret = newentry ? iHttp->PutL(url, *buffer, response)
+					: iHttp->PutL(url, *buffer, response, _L8("ETAG"));
+#endif
+			if ((Ret == CREATED) || (Ret == NOCONTENT) || (Ret == OK))
+				{
+				if (newentry)
+					{
+					iLocalUidArray.Append(aEntry->LocalUidL());
+					iGlobalUidArray.Append(aEntry->UidL());
+					}
+#ifdef ETAG
+				aEntry->SetETag(iHttp->ETag());
+#endif
+				SetLastSyncTimeL();
+				}
+			else if (Ret == PRECONDFAILED)
+				{
+				if (newentry)// same filename already exists, use a different one and upload again
+					{
+					TBuf8<URLMAX> nextUrl;
+					nextUrl.Append(*iUrl);
+					nextUrl.Append(aEntry->UidL());
+					TTime time;
+					time.HomeTime();
+					_LIT(KTimeFormat,"%H%T%S");
+					TBuf<20> StringTime;
+					time.FormatL(StringTime, KTimeFormat);
+					nextUrl.Append(StringTime);
+					nextUrl.Append(_L8(".ics"));
+					response->Reset();
+					TInt Ret = iHttp->PutL(nextUrl, *buffer, response);
+					if ((Ret == CREATED) || (Ret == OK))
+						{
+						iLocalUidArray.Append(aEntry->LocalUidL());
+						iGlobalUidArray.Append(aEntry->UidL());
+#ifdef ETAG
+						aEntry->SetETag(iHttp->ETag());
+#endif
+						SetLastSyncTimeL();
+						}
+					else
+						{
+						SyncFailedL();
+						ret = KErrAbort;
+						}
+					}
+				else
+					{
+					if (!iKeepServerEntry)
+						{
+						response->Reset();
+						// upload again without ETAG to overwrite server entry
+						TInt Ret = iHttp->PutL(url, *buffer, response);
+						if ((Ret == CREATED) || (Ret == OK))
+							{
+#ifdef ETAG
+							aEntry->SetETag(iHttp->ETag());
+#endif
+							SetLastSyncTimeL();
+							}
+						else
+							{
+							SyncFailedL();
+							ret = KErrAbort;
+							}
+						}
+					else
+						{
+						// download the server event and update local store
+						ret = DownloadEntryL(url);
+						if (ret == KErrNone)
+							SetLastSyncTimeL();
+						else
+							{
+							SyncFailedL();
+							ret = KErrAbort;
+							}
+						}
+					}
+				}
+			else
+				{
+				SyncFailedL();
+				ret = KErrAbort;
+				}
+			CleanupStack::PopAndDestroy(response);
+			CleanupStack::PopAndDestroy(buffer);
+			}
+		return ret;
+		}
+	return KErrArgument;
+	}
+
+/**
+ * CCalDavEngine::UploadEntryL
+ * upload entry to server
+ */
+TInt CCalDavEngine::UploadEntryL(const TCalLocalUid &aUid,
+		MCalChangeCallBack2::TChangeType aChangeType,
+		MCalChangeCallBack2::TChangeEntryType aEntryType)
+	{
+	CCalEntry * aEntry = iCalEntryView->FetchL(aUid);
+	CleanupStack::PushL(aEntry);
+	TInt ret = UploadEntryL(aEntry, aChangeType, aEntryType);
+	CleanupStack::PopAndDestroy(aEntry);
+	return ret;
+	}
+
+/**
+ * CCalDavEngine::GetSyncTokenL
+ * get latest Webdav Sync token
+ */
+HBufC8* CCalDavEngine::GetSyncTokenL()
+	{
+	HBufC8 *aBuf = HBufC8::NewL(KSync().Length());
+	aBuf->Des().Format(KSync, &KNullDesC8());
+	CleanupStack::PushL(aBuf);
+
+	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+	CleanupStack::PushL(response);
+	TInt RetServer = iHttp->ReportL(*iUrl, *aBuf, response);
+
+	if (RetServer)
+		{
+		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+		CleanupClosePushL(document);
+		if (document.NotNull())
+			{
+			HBufC8* ret = SearchL(document, KSynctoken, KNullDesC8).AllocL();
+			CleanupStack::PopAndDestroy(&document);
+			CleanupStack::PopAndDestroy(response);
+			CleanupStack::PopAndDestroy(aBuf);
+			return ret;
+			}
+		CleanupStack::PopAndDestroy(&document);
+		}
+	CleanupStack::PopAndDestroy(response);
+	CleanupStack::PopAndDestroy(aBuf);
+	return KNullDesC8().AllocL();
+	}
+
+/**
+ * CCalDavEngine::CheckCalendarInfoL
+ * check for new calendar displayname and color
+ */
+void CCalDavEngine::CheckCalendarInfoL(RXmlEngDocument &aDocument)
+	{
+	TBool change = EFalse;
+	CCalCalendarInfo* info = iCalSession->CalendarInfoL();
+	CleanupStack::PushL(info);
+
+	HBufC8* color = SearchL(aDocument, KCalendar_Color, KNullDesC8).AllocLC();
+	if ((*color != KNullDesC8) && (color->Length() > 6))
+		{
+		TLex8 lexred(color->Des().Mid(1, 2));
+		TInt red;
+		lexred.Val(red);
+		TLex8 lexgreen(color->Des().Mid(3, 2));
+		TInt green;
+		lexgreen.Val(green);
+		TLex8 lexblue(color->Des().Mid(5, 2));
+		TInt blue;
+		lexblue.Val(blue);
+		TRgb newcolor(red, green, blue);
+		if (info->Color() != newcolor)
+			{
+			info->SetColor(newcolor);
+			change = ETrue;
+			}
+		}
+	CleanupStack::PopAndDestroy(color);
+
+	HBufC8* displayname =
+			SearchL(aDocument, KDisplayname, KNullDesC8).AllocLC();
+	if (*displayname != KNullDesC8)
+		{
+		HBufC16* name =
+				CnvUtfConverter::ConvertToUnicodeFromUtf8L(*displayname);
+		CleanupStack::PushL(name);
+		if (info->NameL() != *name)
+			{
+			info->SetNameL(*name);
+			change = ETrue;
+			}
+		CleanupStack::PopAndDestroy(name);
+		change = ETrue;
+		}
+	CleanupStack::PopAndDestroy(displayname);
+
+	if (change)
+		iCalSession->SetCalendarInfoL(*info);
+	CleanupStack::PopAndDestroy(info);
+
+	}
+
+/**
+ * CCalDavEngine::GetCTagL
+ * get latest CTag
+ * https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-ctag.txt
+ */
+HBufC8* CCalDavEngine::GetCTagL()
+	{
+	if (iHttp)
+		{
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt ret = iHttp->PropfindL(*iUrl, KCtag, response);
+
+		if (ret == MULTISTATUS)
+			{
+			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+			CleanupClosePushL(document);
+			if (document.NotNull())
+				{
+				HBufC8* status =
+						SearchL(document, KStatus, KNullDesC8).AllocLC();
+				HBufC8* ctag =
+						SearchL(document, KGetctag, KNullDesC8).AllocLC();
+				status->Des().LowerCase();
+				if ((*ctag != KNullDesC8) && (*status == KHTTP200))
+					{
+					CleanupStack::Pop(ctag);
+					CleanupStack::PopAndDestroy(status);
+					CleanupStack::PopAndDestroy(&document);
+					CleanupStack::PopAndDestroy(response);
+					return ctag;
+					}
+				else
+					CleanupStack::PopAndDestroy(ctag);
+				CleanupStack::PopAndDestroy(status);
+				}
+			CleanupStack::PopAndDestroy(&document);
+
+			}
+		CleanupStack::PopAndDestroy(response);
+		}
+	return KNullDesC8().AllocL();
+	}
+
+/**
+ * CCalDavEngine::GetOptionsL
+ * get OPTIONS from server
+ */
+TBool CCalDavEngine::GetOptionsL()
+	{
+	if (iHttp)
+		{
+		// check DAV and allow headers
+		iHttp->GetServerOptionsL(*iUrl, iOptions);
+
+		// check ctag extension
+		HBufC8* ctag = GetCTagL();
+		if (*ctag != KNullDesC8)
+			iOptions.sync_ctag = true;
+		delete ctag;
+
+		// check supported elements
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt Ret = iHttp->PropfindL(*iUrl, KSupportedSet, response);
+
+		if (Ret == MULTISTATUS)
+			{
+			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+			CleanupClosePushL(document);
+			if (document.NotNull())
+				{
+				CheckCalendarInfoL(document);
+
+				//<C:supported-calendar-component-set/>
+				TXmlEngElement supportedelement;
+				SearchL(document, KSupportedCalendarComponentSet, KNullDesC8,
+						supportedelement);
+				if (supportedelement.NotNull())
+					{
+					RXmlEngNodeList<TXmlEngElement> supportedelements;
+					CleanupClosePushL(supportedelements);
+					supportedelement.GetChildElements(supportedelements);
+					while (supportedelements.HasNext())
+						{
+						TXmlEngElement element = supportedelements.Next();
+						TPtrC8 value = element.AttributeValueL(KName);
+						if (value == KNullDesC8)
+							value.Set(element.AttributeValueL(KName, KCalDav));
+						if (value == KVEVENT)
+							iOptions.VEVENT = ETrue;
+						else if (value == KVTODO)
+							iOptions.VTODO = ETrue;
+						else if (value == KVFREBUSY)
+							iOptions.VFREEBUSY = ETrue;
+						else if (value == KVJOURNAL)
+							iOptions.VJOURNAL = ETrue;
+						}
+					CleanupStack::PopAndDestroy(&supportedelements);
+					}
+				}
+			CleanupStack::PopAndDestroy(&document);
+			}
+		CleanupStack::PopAndDestroy(response);
+		}
+	return ETrue;
+	}
+
+/**
+ * CCalDavEngine::SetSyncTokenL
+ * set sync token
+ */
+void CCalDavEngine::SetSyncTokenL(HBufC8* aToken)
+	{
+	if (iSynctoken)
+		{
+		delete iSynctoken;
+		iSynctoken = NULL;
+		}
+	iSynctoken = aToken;
+	SetCalendarInfoL(KCaldavSynctoken, *iSynctoken);
+	}
+
+/**
+ * CCalDavEngine::SyncToken
+ * get synctoken
+ */
+TPtrC8 CCalDavEngine::SyncToken()
+	{
+	return iSynctoken ? *iSynctoken : KNullDesC8();
+	}
+
+/**
+ * CCalDavEngine::SetCTagL
+ * set ctag
+ */
+void CCalDavEngine::SetCTagL(HBufC8* aToken)
+	{
+	if (iCTag)
+		{
+		delete iCTag;
+		iCTag = NULL;
+		}
+	iCTag = aToken;
+	SetCalendarInfoL(KCaldavCtag, *iCTag);
+	}
+
+/**
+ * CCalDavEngine::CTag
+ * get ctag
+ */
+TPtrC8 CCalDavEngine::CTag()
+	{
+	return iCTag ? *iCTag : KNullDesC8();
+	}
+
+/**
+ * CCalDavEngine::SetLastSyncTimeL
+ * set last sync time
+ */
+void CCalDavEngine::SetLastSyncTimeL()
+	{
+	// only set a new last sync time, if we did not have a failed one before
+	// otherwise, the old one would be lost
+	if (!iManualSync)
+		{
+		TTime time;
+		time.UniversalTime();
+		iLastSyncTime.SetTimeUtcL(time);
+		TPckgC<TCalTime> lasttime(iLastSyncTime);
+		SetCalendarInfoL(KCaldavTime, lasttime);
+		}
+	}
+
+/**
+ * CCalDavEngine::SyncFailedL
+ * sync failed, enable manual sync
+ */
+void CCalDavEngine::SyncFailedL()
+	{
+	if (!iManualSync)
+		{
+		iManualSync = ETrue;
+		TPckgC<TBool> manualSync(iManualSync);
+		SetCalendarInfoL(KCaldavManualSync, manualSync);
+		}
+	}
+
+/**
+ * CCalDavEngine::GetBaseUrl
+ * get base domain url
+ */
+void CCalDavEngine::GetBaseUrl(const TDesC8 &aUrl)
+	{
+	_LIT8(http,"http://");
+	_LIT8(https,"https://");
+
+	if (iBaseUrl)
+		{
+		delete iBaseUrl;
+		iBaseUrl = NULL;
+		}
+
+	if (aUrl.Length() > http().Length())
+		{
+		TInt length = aUrl.Find(https) != KErrNotFound ? https().Length()
+				: http().Length();
+		TInt pos = aUrl.Mid(length).Locate('/');
+		iBaseUrl = aUrl.Left(pos + length).Alloc();
+		}
+	}
+
+/**
+ * CCalDavEngine::FindUrlsL
+ * find home, inbox and outbox property
+ */
+void CCalDavEngine::FindUrlsL(const TDesC8 &aDes, HBufC8 *&home,
+		HBufC8 *&inbox, HBufC8 *&outbox)
+	{
+	RXmlEngDocument document = iDomParser.ParseL(aDes);
+	CleanupClosePushL(document);
+	if (document.NotNull())
+		{
+		HBufC8* status = SearchL(document, KStatus, KNullDesC8).AllocLC();
+		status->Des().LowerCase();
+		if (*status == KHTTP200)
+			{
+			TXmlEngElement calendarhome, inboxhome, outboxhome;
+
+			SearchL(document, KCalendarHomeSet, KNullDesC8, calendarhome);
+			if (calendarhome.NotNull())
+				{
+				TPtrC8 homeend = SearchL(calendarhome, KHref, KNullDesC8);
+				home = HBufC8::NewL(iBaseUrl->Length() + homeend.Length());
+				home->Des().Append(*iBaseUrl);
+				home->Des().Append(homeend);
+				}
+
+			SearchL(document, KInbox, KNullDesC8, inboxhome);
+			if (inboxhome.NotNull())
+				{
+				TPtrC8 inboxend = SearchL(inboxhome, KHref, KNullDesC8);
+				inbox = HBufC8::NewL(iBaseUrl->Length() + inboxend.Length());
+				inbox->Des().Append(*iBaseUrl);
+				inbox->Des().Append(inboxend);
+				}
+
+			SearchL(document, KOutbox, KNullDesC8, outboxhome);
+			if (outboxhome.NotNull())
+				{
+				TPtrC8 outboxend = SearchL(outboxhome, KHref, KNullDesC8);
+				outbox = HBufC8::NewL(iBaseUrl->Length() + outboxend.Length());
+				outbox->Des().Append(*iBaseUrl);
+				outbox->Des().Append(outboxend);
+				}
+			}
+		CleanupStack::PopAndDestroy(status);
+		}
+	CleanupStack::PopAndDestroy(&document);
+	}
+
+/**
+ * CCalDavEngine::FindCalendarCollectionL
+ * find all calendar collections under home url
+ */
+HBufC8* CCalDavEngine::FindCalendarCollectionL(const TDesC8 &aUrl,
+		CDesC8ArrayFlat *aArray)
+	{
+	HBufC8* homecalendar = 0;
+
+	// do propfind depth:1 and find all calendar collections
+	// right now, take the first one as default
+	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+	CleanupStack::PushL(response);
+	TInt retcode = iHttp->PropfindL(aUrl, KCalendarurl, response, EFalse);
+	if (retcode == MULTISTATUS)
+		{
+		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+		CleanupClosePushL(document);
+		if (document.NotNull() && document.DocumentElement().NotNull())
+			{
+			RXmlEngNodeList<TXmlEngElement> ResponseList;
+			CleanupClosePushL(ResponseList);
+			document.DocumentElement().GetElementsByTagNameL(ResponseList,
+					KResponse, KDav);
+			TBool FirstOneDone = EFalse;
+			while (ResponseList.HasNext())
+				{
+				TXmlEngElement node = ResponseList.Next();
+				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
+				TPtrC8 status = SearchL(node, KStatus, KNullDesC8);
+
+				TXmlEngElement calendar;
+				TXmlEngElement vevent_collection;
+				TXmlEngElement vtodo_collection;
+				SearchL(node, KCalendar, KNullDesC8, calendar);
+				SearchL(node, KVEventCollection, KNullDesC8, vevent_collection);
+				SearchL(node, KVTodoCollection, KNullDesC8, vtodo_collection);
+
+				if (calendar.NotNull() || vevent_collection.NotNull()
+						|| vtodo_collection.NotNull())
+					{
+					if (!FirstOneDone)
+						{
+						homecalendar = HBufC8::NewL(iBaseUrl->Length()
+								+ href.Length());
+						homecalendar->Des().Append(*iBaseUrl);
+						homecalendar->Des().Append(href);
+
+						iOptions.VEVENT = vevent_collection.NotNull();
+						iOptions.VTODO = vtodo_collection.NotNull();
+
+						FirstOneDone = ETrue;
+						}
+
+					if (aArray)
+						{
+						TBuf8<URLMAX> url;
+						url.Append(*iBaseUrl);
+						url.Append(href);
+						aArray->AppendL(url);
+						}
+					}
+				}
+			CleanupStack::PopAndDestroy(&ResponseList);
+			}
+		CleanupStack::PopAndDestroy(&document);
+		}
+	CleanupStack::PopAndDestroy(response);
+	return homecalendar;
+	}
+
+/**
+ * CCalDavEngine::GetCalendarUrlsL
+ * find calendar url based on any url
+ * could be principal url, home or direct calendar url
+ */
+TInt CCalDavEngine::GetCalendarUrlsL(CDesC8ArrayFlat *aArray)
+	{
+	if (iHttp && iUrl)
+		{
+		HBufC8 *principal = 0;
+		HBufC8 *home = 0;
+		HBufC8 *homecalendar = 0;
+		HBufC8 *inbox = 0;
+		HBufC8 *outbox = 0;
+
+		GetBaseUrl(*iUrl);
+
+		// TODO: does this really find groupdav collection?
+
+		// find out if this is a caldav or groupdav calendar collection
+		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
+		CleanupStack::PushL(response);
+		TInt retcode = iHttp->PropfindL(*iUrl, KCalendarurl, response);
+		if (retcode == MULTISTATUS)
+			{
+			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
+			CleanupClosePushL(document);
+			if (document.NotNull())
+				{
+				HBufC8* status =
+						SearchL(document, KStatus, KNullDesC8).AllocLC();
+				status->Des().LowerCase();
+				TXmlEngElement calendar;
+				SearchL(document, KCalendar, KNullDesC8, calendar);
+				// it should be <owner><href>value</href></owner>
+				// but oracle beehive server does <owner>value</owner>
+				TXmlEngElement owner;
+				SearchL(document, KOwner, KNullDesC8, owner);
+				TPtrC8 ownerref1 = SearchL(owner, KHref, KNullDesC8);
+				TPtrC8 ownerref2 = owner.Value();
+				TPtrC8 ownerref;
+				ownerref.Set(ownerref1 != KNullDesC8 ? ownerref1 : ownerref2);
+
+				if (calendar.NotNull() && (ownerref != KNullDesC8) && (*status
+						== KHTTP200))
+					{
+					// this is a calendar collection and we know the principal as well now
+					homecalendar = iUrl->AllocL();
+					_LIT8(KHTTP,"http");
+					HBufC8* http = ownerref.Left(KHTTP().Length()).AllocLC();
+					if (*http == KHTTP)
+						{
+						// sogo server does not return relative, but principal url
+						principal = ownerref.AllocL();
+						}
+					else
+						{
+						principal = HBufC8::NewL(iBaseUrl->Length()
+								+ ownerref.Length());
+						principal->Des().Append(*iBaseUrl);
+						principal->Des().Append(ownerref);
+						}
+					CleanupStack::PopAndDestroy(http);
+					}
+				CleanupStack::PopAndDestroy(status);
+				}
+			CleanupStack::PopAndDestroy(&document);
+			}
+
+		// if we have principal, ask for home, otherwise see if principal was given in the first place
+		if (principal)
+			{
+			response->Reset();
+			TInt retcode =
+					iHttp->PropfindL(*principal, KPrincipalurl, response);
+			if (retcode == MULTISTATUS)
+				{
+				FindUrlsL(response->Ptr(0), home, inbox, outbox);
+				}
+			}
+		else
+			{
+			response->Reset();
+			TInt retcode = iHttp->PropfindL(*iUrl, KPrincipalurl, response);
+			if (retcode == MULTISTATUS)
+				{
+				FindUrlsL(response->Ptr(0), home, inbox, outbox);
+				}
+			}
+
+		home = CalDavUtils::EnsureSlashL(home);
+		inbox = CalDavUtils::EnsureSlashL(inbox);
+		outbox = CalDavUtils::EnsureSlashL(outbox);
+
+		// find out all calendar collections under home
+		if (home)
+			{
+			// TODO: temporary? we already have homecalendar...
+			if (!homecalendar)
+				{
+				homecalendar = FindCalendarCollectionL(*home, aArray);
+				}
+			}
+		else
+			{
+			// have not found out home nor a groupdav collection, maybe we are home ourselves
+			homecalendar = FindCalendarCollectionL(*iUrl, aArray);
+			if (homecalendar)
+				home = iUrl->AllocL();
+			}
+
+		CleanupStack::PopAndDestroy(response);
+		delete principal;
+		delete inbox;
+		delete outbox;
+
+		if (home)
+			iHome = CalDavUtils::EnsureSlashL(home);
+		if (homecalendar)
+			{
+			delete iUrl;
+			iUrl = NULL;
+			iUrl = CalDavUtils::EnsureSlashL(homecalendar);
+			return KErrNone;
+			}
+		else
+			return KErrArgument;
+		}
+	return KErrArgument;
+	}
+
+/**
+ * CCalDavEngine::CalendarName
+ * get calendar name
+ */
+TPtrC CCalDavEngine::CalendarName() const
+	{
+	return iCalendar ? *iCalendar : KNullDesC();
+	}
+
+/**
+ * CCalDavEngine::Home
+ * get home
+ */
+TPtrC8 CCalDavEngine::Home() const
+	{
+	return iHome ? *iHome : KNullDesC8();
+	}
+
+/**
+ * CCalDavEngine::Url
+ * get url
+ */
+TPtrC8 CCalDavEngine::Url() const
+	{
+	return iUrl ? *iUrl : KNullDesC8();
+	}
+
+/**
+ * CCalDavEngine::SetUrlL
+ * set url
+ */
+void CCalDavEngine::SetUrlL(const TDesC8 &aUrl)
+	{
+	if (iUrl ? *iUrl != aUrl : ETrue)
+		{
+		DisableL();
+
+		if (iUrl)
+			{
+			delete iUrl;
+			iUrl = NULL;
+			}
+
+		iUrl = CalDavUtils::EnsureSlashL(aUrl);
+		SetCalendarInfoL(KCaldavUrl, *iUrl);
+		}
+	}
+
+/**
+ * CCalDavEngine::User
+ * get user
+ */
+TPtrC8 CCalDavEngine::User() const
+	{
+	return iHttp->User();
+	}
+
+/**
+ * CCalDavEngine::SetUserL
+ * set user
+ */
+void CCalDavEngine::SetUserL(const TDesC8 &aUser)
+	{
+	if (iHttp->User() != aUser)
+		{
+		DisableL();
+		SetCalendarInfoL(KCaldavUser, aUser);
+		iHttp->SetUserL(aUser);
+		}
+	}
+
+/**
+ * CCalDavEngine::Password
+ * get password
+ */
+TPtrC8 CCalDavEngine::Password() const
+	{
+	return iHttp->Password();
+	}
+
+/**
+ * CCalDavEngine::SetPasswordL
+ * set password
+ */
+void CCalDavEngine::SetPasswordL(const TDesC8 &aPassword)
+	{
+	if (iHttp->Password() != aPassword)
+		{
+		DisableL();
+		iHttp->SetPasswordL(aPassword);
+		SetCalendarInfoL(KCaldavPassword, aPassword);
+		}
+	}
+
+/**
+ * CCalDavEngine::SyncInterval
+ * get SyncInterval
+ */
+TTimeIntervalMinutes CCalDavEngine::SyncInterval() const
+	{
+	return iSyncInterval;
+	}
+
+/**
+ * CCalDavEngine::SetSyncIntervalL
+ * set SetSyncIntervalL
+ */
+void CCalDavEngine::SetSyncIntervalL(TTimeIntervalMinutes aSyncInterval)
+	{
+	iSyncInterval = aSyncInterval;
+	TPckgC<TTimeIntervalMinutes> minutes(iSyncInterval);
+	SetCalendarInfoL(KCaldavSyncInterval, minutes);
+	}
+
+/**
+ * CCalDavEngine::PastDays
+ * get past days
+ */
+TTimeIntervalDays CCalDavEngine::PastDays() const
+	{
+	return iPastDays;
+	}
+
+/**
+ * CCalDavEngine::SetPastDaysL
+ * Set PastDaysL
+ */
+void CCalDavEngine::SetPastDaysL(TTimeIntervalDays aDays)
+	{
+	iPastDays = aDays;
+	TPckgC<TTimeIntervalDays> days(iPastDays);
+	SetCalendarInfoL(KCaldavPastDays, days);
+	}
+
+/**
+ * CCalDavEngine::ImmediateSync
+ * get ImmediateSyncL
+ */
+TBool CCalDavEngine::ImmediateSync() const
+	{
+	return iImmediateSync;
+	}
+
+/**
+ * CCalDavEngine::SetImmediateSyncL
+ * Set ImmediateSyncL
+ */
+void CCalDavEngine::SetImmediateSyncL(TBool aImmediateSyc)
+	{
+	iImmediateSync = aImmediateSyc;
+	TPckgC<TBool> immediatesync(iImmediateSync);
+	SetCalendarInfoL(KCaldavImmediateSync, immediatesync);
+	}
+
+/**
+ * CCalDavEngine::KeepServerEntry
+ * get KeepServerEntryL
+ */
+TBool CCalDavEngine::KeepServerEntry() const
+	{
+	return iKeepServerEntry;
+	}
+
+/**
+ * CCalDavEngine::SetKeepServerEntryL
+ * Set KeepServerEntryL
+ */
+void CCalDavEngine::SetKeepServerEntryL(TBool aKeepServerEntry)
+	{
+	iKeepServerEntry = aKeepServerEntry;
+	TPckgC<TBool> keepserver(iKeepServerEntry);
+	SetCalendarInfoL(KCaldavKeepServer, keepserver);
+	}
+
+/**
+ * CCalDavEngine::Timer
+ * get timer
+ */
+CPeriodic* CCalDavEngine::Timer()
+	{
+	return iTimer;
+	}