calendarengines/caldav/src/caldavengine.cpp
branchRCL_3
changeset 86 ed599363c2d7
parent 78 356f28cd5ca0
child 87 6d3f83773253
equal deleted inserted replaced
78:356f28cd5ca0 86:ed599363c2d7
     1 /*
       
     2  * Copyright (c) 2010 Sun Microsystems, Inc. and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributor:
       
    10  * Maximilian Odendahl
       
    11  *
       
    12  * Contributors:
       
    13  * 
       
    14  * Description:  main Caldav class, all magic happens here 
       
    15  *				one engine for each configured Caldav calendar
       
    16  */
       
    17 #include "caldavengine.h"
       
    18 #include <f32file.h> 
       
    19 #include <S32FILE.H>
       
    20 #include <S32MEM.H> 
       
    21 #include <avkon.rsg>
       
    22 #include <UTF.H>
       
    23 #include <agnexportobserver.h>
       
    24 #include <calsession.h>
       
    25 #include <caliterator.h>
       
    26 #include <calentry.h>
       
    27 #include <calentryview.h>
       
    28 #include <caltime.h>
       
    29 #include <calalarm.h>
       
    30 #include <calcategory.h>
       
    31 #include <caluser.h>
       
    32 #include <calrrule.h>
       
    33 #include <calinstance.h>
       
    34 #include <calinstanceview.h>
       
    35 #include <caleninterimutils2.h> 
       
    36 #include <calenexporter.h>
       
    37 #include <calenimporter.h>
       
    38 #include <calcalendarinfo.h>
       
    39 #include "calenglobaldata.h"
       
    40 #include <xmlengdocument.h>
       
    41 #include <xmlengnode.h>
       
    42 #include <xmlengelement.h>
       
    43 #include <xmlengnodelist.h>
       
    44 #include <xmlengtext.h>
       
    45 #include "httpclient.h"
       
    46 #include <e32math.h>	// divmod
       
    47 #define MULTIGETSPLIT 			100
       
    48 #define ARRAYEXPAND				4
       
    49 #define	URLMAX					500
       
    50 #define EXPANDSIZE_SMALL		512
       
    51 #define EXPANDSIZE_BIG			1024
       
    52 _LIT(KFormatString,"\"%F%Y%M%DT000000Z\"");
       
    53 
       
    54 /**
       
    55  * SyncTickL
       
    56  * timer for basic sync interval
       
    57  */
       
    58 TInt SyncTickL(TAny *aObject)
       
    59 	{
       
    60 	CCalDavEngine* engine = ((CCalDavEngine*) aObject);
       
    61 	CPeriodic* timer = engine->Timer();
       
    62 	if (engine && timer)
       
    63 		{
       
    64 		timer->Cancel();
       
    65 		TRAP_IGNORE(engine->SyncL());
       
    66 		TInt ticktime = engine->SyncInterval().Int() == 0 ? 1
       
    67 				: engine->SyncInterval().Int();
       
    68 		const TUint64 tickInterval = 1000000 * 60 * ticktime;
       
    69 		timer->Start(tickInterval, tickInterval, TCallBack(SyncTickL, engine));
       
    70 		}
       
    71 	return 0;
       
    72 	}
       
    73 
       
    74 #ifdef _DEBUG
       
    75 void ExportToFileNameL(const TDesC8& aDes, const TDesC &aFilename)
       
    76 	{
       
    77 	RFs fsSession;
       
    78 	User::LeaveIfError(fsSession.Connect());
       
    79 	CleanupClosePushL(fsSession);
       
    80 
       
    81 	TInt err = fsSession.MkDirAll(aFilename);
       
    82 
       
    83 	RFile file;
       
    84 	User::LeaveIfError(file.Replace(fsSession, aFilename, EFileWrite));
       
    85 	CleanupClosePushL(file);
       
    86 
       
    87 	RFileWriteStream writeStream2;
       
    88 	writeStream2.Attach(file);
       
    89 	CleanupClosePushL(writeStream2);
       
    90 
       
    91 	writeStream2 << aDes;
       
    92 	writeStream2.CommitL();
       
    93 	CleanupStack::PopAndDestroy(&writeStream2);
       
    94 	CleanupStack::PopAndDestroy(&file);
       
    95 	CleanupStack::PopAndDestroy(&fsSession);
       
    96 	}
       
    97 
       
    98 void ExportToFileL(CCalEntry* aEntry, CCalenExporter *iCalExporter)
       
    99 	{
       
   100 	if (aEntry)
       
   101 		{
       
   102 		_LIT(KFileName, "C:\\logs\\caldav\\testing_export.txt");
       
   103 
       
   104 		RFs fsSession;
       
   105 		User::LeaveIfError(fsSession.Connect());
       
   106 		CleanupClosePushL(fsSession);
       
   107 
       
   108 		TInt err = fsSession.MkDirAll(KFileName);
       
   109 
       
   110 		RFile file;
       
   111 		User::LeaveIfError(file.Replace(fsSession, KFileName, EFileWrite));
       
   112 		CleanupClosePushL(file);
       
   113 
       
   114 		RFileWriteStream writeStream2;
       
   115 		writeStream2.Attach(file);
       
   116 		CleanupClosePushL(writeStream2);
       
   117 
       
   118 		iCalExporter->ExportICalL(*aEntry, writeStream2);
       
   119 		writeStream2.CommitL();
       
   120 		CleanupStack::PopAndDestroy(&writeStream2);
       
   121 		CleanupStack::PopAndDestroy(&file);
       
   122 		CleanupStack::PopAndDestroy(&fsSession);
       
   123 		}
       
   124 	}
       
   125 #endif
       
   126 
       
   127 /**
       
   128  * SearchL
       
   129  * search inside xml tree for a specific node
       
   130  */
       
   131 void SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
       
   132 		const TDesC8 &aNamespace, TXmlEngNode & aReturnNode)
       
   133 	{
       
   134 	RXmlEngNodeList<TXmlEngNode> List;
       
   135 	aTopNode.GetChildNodes(List);
       
   136 	while (List.HasNext() && aReturnNode.IsNull())
       
   137 		{
       
   138 		TXmlEngNode Node = List.Next();
       
   139 		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
       
   140 		if (Type == TXmlEngNode::EElement)
       
   141 			{
       
   142 			//todo: compare namespace ?
       
   143 			if (Node.Name() == aName)
       
   144 				{
       
   145 				aReturnNode = Node.CopyL();
       
   146 				return;
       
   147 				}
       
   148 			else
       
   149 				{
       
   150 				SearchL(Node, aName, aNamespace, aReturnNode);
       
   151 				if (!aReturnNode.IsNull())
       
   152 					return;
       
   153 				}
       
   154 			}
       
   155 		}
       
   156 	}
       
   157 
       
   158 /**
       
   159  * SearchL
       
   160  * search inside xml tree for a specific node
       
   161  */
       
   162 void SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
       
   163 		const TDesC8 &aNamespace, RBuf8 &aBuf)
       
   164 	{
       
   165 	RXmlEngNodeList<TXmlEngNode> List;
       
   166 	aTopNode.GetChildNodes(List);
       
   167 	while (List.HasNext())
       
   168 		{
       
   169 		TXmlEngNode Node = List.Next();
       
   170 		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
       
   171 		if (Type == TXmlEngNode::EElement)
       
   172 			{
       
   173 			//todo: compare namespace ?
       
   174 			if (Node.Name() == aName)
       
   175 				{
       
   176 				if (Node.IsSimpleTextContents())
       
   177 					aBuf.Create(Node.Value());
       
   178 				else
       
   179 					Node.WholeTextContentsCopyL(aBuf);
       
   180 				return;
       
   181 				}
       
   182 			else
       
   183 				{
       
   184 				SearchL(Node, aName, aNamespace, aBuf);
       
   185 				if (aBuf.Length())
       
   186 					return;
       
   187 				}
       
   188 			}
       
   189 		}
       
   190 	}
       
   191 
       
   192 /**
       
   193  * SearchL
       
   194  * search inside xml tree for a specific node
       
   195  */
       
   196 TPtrC8 SearchL(TXmlEngNode &aTopNode, const TDesC8 &aName,
       
   197 		const TDesC8 &aNamespace)
       
   198 	{
       
   199 	RXmlEngNodeList<TXmlEngNode> List;
       
   200 	aTopNode.GetChildNodes(List);
       
   201 	while (List.HasNext())
       
   202 		{
       
   203 		TXmlEngNode Node = List.Next();
       
   204 		TXmlEngNode::TXmlEngDOMNodeType Type = Node.NodeType();
       
   205 		if (Type == TXmlEngNode::EElement)
       
   206 			{
       
   207 			//todo: compare namespace ?
       
   208 			if (Node.Name() == aName)
       
   209 				return Node.Value();
       
   210 			else
       
   211 				{
       
   212 				TPtrC8 Return = SearchL(Node, aName, aNamespace);
       
   213 				if (Return != KNullDesC8)
       
   214 					return Return;
       
   215 				}
       
   216 			}
       
   217 		}
       
   218 	return KNullDesC8();
       
   219 	}
       
   220 
       
   221 /**
       
   222  * GetBoolFromPropertiesL
       
   223  * get a boolean value from CCalCalendarInfo
       
   224  */
       
   225 TBool GetBoolFromPropertiesL(CCalCalendarInfo* info, const TDesC8 &aKey)
       
   226 	{
       
   227 	TBool boolean;
       
   228 	TPckgC<TBool> pckgboolean(boolean);
       
   229 	pckgboolean.Set(info->PropertyValueL(aKey));
       
   230 	return pckgboolean();
       
   231 	}
       
   232 
       
   233 /**
       
   234  * GetTimeFromPropertiesL
       
   235  * get a time value from CCalCalendarInfo
       
   236  */
       
   237 TCalTime GetTimeFromPropertiesL(CCalCalendarInfo* info, const TDesC8 &aKey)
       
   238 	{
       
   239 	TCalTime time;
       
   240 	TPckgC<TCalTime> pckgtime(time);
       
   241 	pckgtime.Set(info->PropertyValueL(aKey));
       
   242 	return pckgtime();
       
   243 	}
       
   244 
       
   245 /**
       
   246  * PropertyExists
       
   247  * finds a property from an array
       
   248  */
       
   249 TBool PropertyExists(CDesC8Array* aArray, const TDesC8 &aKey)
       
   250 	{
       
   251 	TInt pos = 0;
       
   252 	return aArray->Find(aKey, pos, ECmpNormal) == KErrNone;
       
   253 	}
       
   254 
       
   255 /**
       
   256  * CCalDavEngine::SetCalendarInfoL
       
   257  * set key and value pair at calendar session info
       
   258  */
       
   259 void CCalDavEngine::SetCalendarInfoL(const TDesC8 &aKey, const TDesC8 &aValue)
       
   260 	{
       
   261 	TBool createdelete = !iCalSession;
       
   262 	if (createdelete)
       
   263 		{
       
   264 		iCalSession = CCalSession::NewL();
       
   265 		TRAP_IGNORE(iCalSession->OpenL(*iCalendar));
       
   266 		}
       
   267 	CCalCalendarInfo* calendarInfo = iCalSession->CalendarInfoL();
       
   268 	CleanupStack::PushL(calendarInfo);
       
   269 	TPckgC<TBool> enabled(iEnabled);
       
   270 	calendarInfo->SetPropertyL(KCaldavEnabled, enabled);
       
   271 	if (aValue != KNullDesC8)
       
   272 		calendarInfo->SetPropertyL(aKey, aValue);
       
   273 	iCalSession->SetCalendarInfoL(*calendarInfo);
       
   274 	CleanupStack::PopAndDestroy(calendarInfo);
       
   275 
       
   276 	if (createdelete)
       
   277 		{
       
   278 		delete iCalSession;
       
   279 		iCalSession = NULL;
       
   280 		}
       
   281 	}
       
   282 
       
   283 /**
       
   284  * CCalDavEngine::CCalDavEngine
       
   285  * default constructor
       
   286  */
       
   287 CCalDavEngine::CCalDavEngine() :
       
   288 	iCalSession(0), iCalIter(0), iCalEntryView(0), iCalExporter(0),
       
   289 			iCalImporter(0), iCalIntermimUtils2(0), iCalendar(0), iUrl(0),
       
   290 			iBaseUrl(0), iHome(0), iHttp(0), iSynctoken(0), iCTag(0),
       
   291 			iSyncInterval(DEFAULT_SYNC_MINUTES), iPastDays(DEFAULT_PAST_DAYS),
       
   292 			iImmediateSync(DEFAULT_IMMEDIATE_SYNC), iKeepServerEntry(
       
   293 					DEFAULT_KEEP_SERVER_ENTRY), iEnabled(EFalse), iTimer(0)
       
   294 	{
       
   295 	}
       
   296 
       
   297 /**
       
   298  * CCalDavEngine::~CCalDavEngine
       
   299  * default destructor
       
   300  */
       
   301 CCalDavEngine::~CCalDavEngine()
       
   302 	{
       
   303 	iLocalUidArray.Close();
       
   304 	iGlobalUidArray.Close();
       
   305 	iDeletedEntries.Close();
       
   306 
       
   307 	iDomParser.Close();
       
   308 	iDomImpl.Close();
       
   309 
       
   310 	if (iCalendar)
       
   311 		delete iCalendar;
       
   312 
       
   313 	if (iUrl)
       
   314 		delete iUrl;
       
   315 
       
   316 	if (iBaseUrl)
       
   317 		delete iBaseUrl;
       
   318 
       
   319 	if (iHttp)
       
   320 		delete iHttp;
       
   321 
       
   322 	DeleteCalObjects();
       
   323 
       
   324 	if (iCalIntermimUtils2)
       
   325 		delete iCalIntermimUtils2;
       
   326 
       
   327 	if (iSynctoken)
       
   328 		delete iSynctoken;
       
   329 
       
   330 	if (iCTag)
       
   331 		delete iCTag;
       
   332 
       
   333 	if (iHome)
       
   334 		delete iHome;
       
   335 
       
   336 	if (iTimer)
       
   337 		delete iTimer;
       
   338 	}
       
   339 
       
   340 /**
       
   341  * CCalDavEngine::NewLC
       
   342  * first phase construction
       
   343  */
       
   344 CCalDavEngine* CCalDavEngine::NewLC(const TDesC& aCalendar)
       
   345 	{
       
   346 	CCalDavEngine* self = new (ELeave) CCalDavEngine();
       
   347 	CleanupStack::PushL(self);
       
   348 	self->ConstructL(aCalendar);
       
   349 	return self;
       
   350 	}
       
   351 
       
   352 /**
       
   353  * CCalDavEngine::NewL
       
   354  * first phase construction
       
   355  */
       
   356 CCalDavEngine* CCalDavEngine::NewL(const TDesC& aCalendar)
       
   357 	{
       
   358 	CCalDavEngine* self = CCalDavEngine::NewLC(aCalendar);
       
   359 	CleanupStack::Pop(self); // self;
       
   360 	return self;
       
   361 	}
       
   362 
       
   363 /**
       
   364  * CCalDavEngine::
       
   365  * second phase construction
       
   366  */
       
   367 void CCalDavEngine::ConstructL(const TDesC& aCalendar)
       
   368 	{
       
   369 	iManualSync = EFalse;
       
   370 	iFirstInit = ETrue;
       
   371 	iCalendar = aCalendar.AllocL();
       
   372 
       
   373 	iHttp = CHttpClient::NewL();
       
   374 
       
   375 	iDomImpl.OpenL();
       
   376 	TInt err = iDomParser.Open(iDomImpl);
       
   377 	if (KErrNone != err)
       
   378 		User::Leave(err);
       
   379 
       
   380 	iTimer = CPeriodic::NewL(EPriorityNormal);
       
   381 	iCalIntermimUtils2 = CCalenInterimUtils2::NewL();
       
   382 	iCalSession = CCalSession::NewL();
       
   383 	TRAP_IGNORE(iCalSession->OpenL(aCalendar));
       
   384 	CalendarInfoL();
       
   385 	// we can't close the file, so delete it completly
       
   386 	delete iCalSession;
       
   387 	iCalSession = NULL;
       
   388 	}
       
   389 
       
   390 /**
       
   391  * CCalDavEngine::Progress
       
   392  * Progress callback
       
   393  */
       
   394 void CCalDavEngine::Progress(TInt /*aPercentageCompleted*/)
       
   395 	{
       
   396 	}
       
   397 
       
   398 /**
       
   399  * CCalDavEngine::RegisterL
       
   400  * register all neccessary notification callback
       
   401  */
       
   402 void CCalDavEngine::RegisterL()
       
   403 	{
       
   404 	TDateTime Start;
       
   405 	TDateTime End;
       
   406 	End.SetYear(2200);
       
   407 
       
   408 	TCalTime StartCal;
       
   409 	TCalTime EndCal;
       
   410 	StartCal.SetTimeLocalL(Start);
       
   411 	EndCal.SetTimeLocalL(End);
       
   412 	CalCommon::TCalTimeRange Range(StartCal, EndCal);
       
   413 	CCalChangeNotificationFilter *Filter = CCalChangeNotificationFilter::NewL(
       
   414 			MCalChangeCallBack2::EChangeEntryAll, true, Range);
       
   415 	iCalSession->StartChangeNotification(*this, *Filter);
       
   416 	iCalSession->StartFileChangeNotificationL(*this);
       
   417 	delete Filter;
       
   418 	}
       
   419 
       
   420 /**
       
   421  * CCalDavEngine::CalendarInfoL
       
   422  * load all properties from CalendarInfo
       
   423  */
       
   424 void CCalDavEngine::CalendarInfoL()
       
   425 	{
       
   426 	CCalCalendarInfo* calendarInfo = iCalSession->CalendarInfoL();
       
   427 	if (calendarInfo->IsValid())
       
   428 		{
       
   429 		CleanupStack::PushL(calendarInfo);
       
   430 		CDesC8Array* propertyKeys = calendarInfo->PropertyKeysL();
       
   431 		CleanupStack::PushL(propertyKeys);
       
   432 		TInt pos = 0;
       
   433 		if (propertyKeys->Find(KCaldavEnabled, pos, ECmpNormal) == KErrNone)
       
   434 			{
       
   435 			iEnabled = GetBoolFromPropertiesL(calendarInfo, KCaldavEnabled);
       
   436 			if (PropertyExists(propertyKeys, KCaldavFirstInit))
       
   437 				iFirstInit = GetBoolFromPropertiesL(calendarInfo,
       
   438 						KCaldavFirstInit);
       
   439 			if (PropertyExists(propertyKeys, KCaldavSynctoken))
       
   440 				iSynctoken
       
   441 						= calendarInfo->PropertyValueL(KCaldavSynctoken).AllocL();
       
   442 			if (PropertyExists(propertyKeys, KCaldavCtag))
       
   443 				iCTag = calendarInfo->PropertyValueL(KCaldavCtag).AllocL();
       
   444 			if (PropertyExists(propertyKeys, KCaldavManualSync))
       
   445 				iManualSync = GetBoolFromPropertiesL(calendarInfo,
       
   446 						KCaldavManualSync);
       
   447 			if (PropertyExists(propertyKeys, KCaldavTime))
       
   448 				iLastSyncTime = GetTimeFromPropertiesL(calendarInfo,
       
   449 						KCaldavTime);
       
   450 			if (PropertyExists(propertyKeys, KCaldavUrl))
       
   451 				iUrl = calendarInfo->PropertyValueL(KCaldavUrl).AllocL();
       
   452 			if (PropertyExists(propertyKeys, KCaldavUser))
       
   453 				iHttp->SetUserL(calendarInfo->PropertyValueL(KCaldavUser));
       
   454 			if (PropertyExists(propertyKeys, KCaldavPassword))
       
   455 				iHttp->SetPasswordL(calendarInfo->PropertyValueL(
       
   456 						KCaldavPassword));
       
   457 			if (PropertyExists(propertyKeys, KCaldavKeepServer))
       
   458 				iKeepServerEntry = GetBoolFromPropertiesL(calendarInfo,
       
   459 						KCaldavKeepServer);
       
   460 			if (PropertyExists(propertyKeys, KCaldavImmediateSync))
       
   461 				iImmediateSync = GetBoolFromPropertiesL(calendarInfo,
       
   462 						KCaldavImmediateSync);
       
   463 			if (PropertyExists(propertyKeys, KCaldavPastDays))
       
   464 				{
       
   465 				TPckgC<TTimeIntervalDays> pastdays(iPastDays);
       
   466 				pastdays.Set(calendarInfo->PropertyValueL(KCaldavPastDays));
       
   467 				iPastDays = pastdays();
       
   468 				}
       
   469 			if (PropertyExists(propertyKeys, KCaldavSyncInterval))
       
   470 				{
       
   471 				TPckgC<TTimeIntervalMinutes> syncinterval(iSyncInterval);
       
   472 				syncinterval.Set(calendarInfo->PropertyValueL(
       
   473 						KCaldavSyncInterval));
       
   474 				iSyncInterval = syncinterval();
       
   475 				}
       
   476 			// access point	    
       
   477 			}
       
   478 
       
   479 		CleanupStack::PopAndDestroy(propertyKeys);
       
   480 		CleanupStack::Pop(calendarInfo);
       
   481 		}
       
   482 	delete calendarInfo;
       
   483 	}
       
   484 
       
   485 /**
       
   486  * CCalDavEngine::InitL
       
   487  * check for correct url
       
   488  * load most Caldav url properties
       
   489  * do inital sync
       
   490  */
       
   491 TInt CCalDavEngine::InitL()
       
   492 	{
       
   493 	// this is only needed to find a GlobalUID from a LocalUID, used after an event was deleted
       
   494 	// also used now for uploading of local events when only GlobalUID is know 
       
   495 	LocalLoopL(ELoopActionFillArray);
       
   496 
       
   497 	if (iFirstInit)
       
   498 		{
       
   499 		TInt err = GetCalendarUrlsL(NULL);
       
   500 		if (err == KErrArgument)
       
   501 			return KErrArgument;
       
   502 		GetOptionsL();
       
   503 		SetLastSyncTimeL();
       
   504 
       
   505 		TBool success;
       
   506 		// get all server items
       
   507 		if (iOptions.sync_collection)
       
   508 			success = WebDavSyncL();
       
   509 		else
       
   510 			success = ListL() == KErrNone;
       
   511 
       
   512 		if (!success)
       
   513 			return KErrGeneral;
       
   514 
       
   515 		// upload all local entries of this calendar to server
       
   516 		LocalLoopL(ELoopActionUpload);
       
   517 
       
   518 		if (iOptions.sync_collection)
       
   519 			SetSyncTokenL(GetSyncTokenL());
       
   520 		else
       
   521 			SetCTagL(GetCTagL());
       
   522 
       
   523 		iFirstInit = EFalse;
       
   524 		iEnabled = ETrue;
       
   525 		TPckgC<TBool> firstInit(iFirstInit);
       
   526 		SetCalendarInfoL(KCaldavFirstInit, firstInit); // this will set iEnabled as well
       
   527 		}
       
   528 	else
       
   529 		{
       
   530 		TInt err = GetCalendarUrlsL(NULL);
       
   531 		if (err == KErrArgument)
       
   532 			return KErrArgument;
       
   533 		GetOptionsL();
       
   534 		SetLastSyncTimeL();
       
   535 		iEnabled = ETrue;
       
   536 		SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
       
   537 		SyncL();
       
   538 		}
       
   539 
       
   540 	return KErrNone;
       
   541 	}
       
   542 
       
   543 /**
       
   544  * CCalDavEngine::Completed
       
   545  * Completed callback
       
   546  */
       
   547 void CCalDavEngine::Completed(TInt aError)
       
   548 	{
       
   549 	if (aError == KErrNone)
       
   550 		{
       
   551 		CActiveScheduler::Stop();
       
   552 		}
       
   553 	else
       
   554 		iManualSync = true;
       
   555 	}
       
   556 
       
   557 /**
       
   558  * CCalDavEngine::NotifyProgress
       
   559  * NotifyProgress callback
       
   560  */
       
   561 TBool CCalDavEngine::NotifyProgress()
       
   562 	{
       
   563 	return EFalse;
       
   564 	}
       
   565 
       
   566 /**
       
   567  * CCalDavEngine::CalChangeNotification
       
   568  * change item callback, sync to server
       
   569  */
       
   570 void CCalDavEngine::CalChangeNotification(RArray<TCalChangeEntry> &aChangeItems)
       
   571 	{
       
   572 	for (TInt i = 0; i < aChangeItems.Count(); i++)
       
   573 		{
       
   574 		TRAP_IGNORE(HandleChangeL(aChangeItems[i].iChangeType, aChangeItems[i].iEntryType, aChangeItems[i].iEntryId));
       
   575 		}
       
   576 	}
       
   577 
       
   578 /**
       
   579  * CCalDavEngine::CalendarInfoChangeNotificationL
       
   580  * change callback, sync changed color or name to server
       
   581  */
       
   582 void CCalDavEngine::CalendarInfoChangeNotificationL(RPointerArray<
       
   583 		CCalFileChangeInfo>& aCalendarInfoChangeEntries)
       
   584 	{
       
   585 	for (TInt i = 0; i < aCalendarInfoChangeEntries.Count(); i++)
       
   586 		{
       
   587 		if ((aCalendarInfoChangeEntries[i]->FileNameL() == *iCalendar)
       
   588 				&& (aCalendarInfoChangeEntries[i]->ChangeType()
       
   589 						== MCalFileChangeObserver::ECalendarInfoUpdated))
       
   590 			{
       
   591 			TRAP_IGNORE(HandleCalendarInfoChangeL());
       
   592 			}
       
   593 		}
       
   594 	}
       
   595 
       
   596 /**
       
   597  * CCalDavEngine::HandleCalendarInfoChangeL
       
   598  * sync changed color or name to server
       
   599  */
       
   600 void CCalDavEngine::HandleCalendarInfoChangeL()
       
   601 	{
       
   602 	if (iHttp)
       
   603 		{
       
   604 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
   605 		CleanupStack::PushL(response);
       
   606 		CCalCalendarInfo* info = iCalSession->CalendarInfoL();
       
   607 		CleanupStack::PushL(info);
       
   608 
       
   609 		HBufC8* name =
       
   610 				CnvUtfConverter::ConvertFromUnicodeToUtf8L(info->NameL());
       
   611 		CleanupStack::PushL(name);
       
   612 
       
   613 		TRgb color = info->Color();
       
   614 		_LIT8(KColorformat,"#%02x%02x%02xFF");
       
   615 		TBuf8<9> colorbuf;
       
   616 		colorbuf.Format(KColorformat, color.Red(), color.Green(), color.Blue());
       
   617 
       
   618 		HBufC8* patch = HBufC8::NewLC(KColorDisplayStart().Length()
       
   619 				+ colorbuf.Length() + KColorDisplayMiddle().Length()
       
   620 				+ name->Length() + KColorDisplayEnd().Length());
       
   621 		patch->Des().Append(KColorDisplayStart);
       
   622 		patch->Des().Append(colorbuf);
       
   623 		patch->Des().Append(KColorDisplayMiddle);
       
   624 		patch->Des().Append(*name);
       
   625 		patch->Des().Append(KColorDisplayEnd);
       
   626 		iHttp->ProppatchL(*iUrl, *patch, response);
       
   627 		CleanupStack::PopAndDestroy(4); // response, info, name, patch
       
   628 		}
       
   629 	}
       
   630 
       
   631 /**
       
   632  * CCalDavEngine::HandleChangeL
       
   633  * change item callback, sync to server
       
   634  */
       
   635 void CCalDavEngine::HandleChangeL(
       
   636 		MCalChangeCallBack2::TChangeType &aChangeType,
       
   637 		MCalChangeCallBack2::TChangeEntryType &aEntryType, TCalLocalUid &aUid)
       
   638 	{
       
   639 	switch (aChangeType)
       
   640 		{
       
   641 		case MCalChangeCallBack2::EChangeAdd:
       
   642 		case MCalChangeCallBack2::EChangeModify:
       
   643 			{
       
   644 			if (iImmediateSync)
       
   645 				UploadEntryL(aUid, aChangeType, aEntryType);
       
   646 			else
       
   647 				// enable manual sync for the next sync interval
       
   648 				SyncFailedL();
       
   649 			break;
       
   650 			}
       
   651 		case MCalChangeCallBack2::EChangeDelete:
       
   652 			{
       
   653 			if (iImmediateSync)
       
   654 				DeleteEntryL(aUid);
       
   655 			else
       
   656 				{
       
   657 				iDeletedEntries.Append(aUid);
       
   658 				SyncFailedL();
       
   659 				}
       
   660 			break;
       
   661 			}
       
   662 		case MCalChangeCallBack2::EChangeUndefined:
       
   663 			{
       
   664 			// upload new and modified entries to server
       
   665 			UploadModifiedSinceDateL();
       
   666 
       
   667 			// Find locally deleted ones and delete on server
       
   668 			DeleteRemovedEntriesOnServerL();
       
   669 
       
   670 			break;
       
   671 			}
       
   672 		}
       
   673 	}
       
   674 
       
   675 /**
       
   676  * CCalDavEngine::EnableL
       
   677  * enable Caldav sync
       
   678  */
       
   679 TInt CCalDavEngine::EnableL()
       
   680 	{
       
   681 	if (!iCalEntryView) //do not use iEnabled here,might be set already in ConstructL()
       
   682 		{
       
   683 		TInt aErr = CreateCalObjectsL();
       
   684 		if ((aErr == KErrNone) && (InitL() == KErrNone))
       
   685 			{
       
   686 			iTimer->Cancel();
       
   687 			TInt ticktime = iSyncInterval.Int() == 0 ? 1 : iSyncInterval.Int();
       
   688 			const TUint64 tickInterval = 1000000 * 60 * ticktime;
       
   689 			iTimer->Start(tickInterval, tickInterval,
       
   690 					TCallBack(SyncTickL, this));
       
   691 			// register change notification
       
   692 			RegisterL();
       
   693 			return KErrNone;
       
   694 			}
       
   695 		else
       
   696 			{
       
   697 			iEnabled = EFalse;
       
   698 			SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
       
   699 			DeleteCalObjects();
       
   700 			return KErrArgument;
       
   701 			}
       
   702 		}
       
   703 	return KErrNone;
       
   704 	}
       
   705 
       
   706 /**
       
   707  * CCalDavEngine::DeleteCalObjects
       
   708  * delete all calendar objects
       
   709  */
       
   710 void CCalDavEngine::DeleteCalObjects()
       
   711 	{
       
   712 	delete iCalIter;
       
   713 	iCalIter = NULL;
       
   714 	delete iCalEntryView;
       
   715 	iCalEntryView = NULL;
       
   716 	delete iCalImporter;
       
   717 	iCalImporter = NULL;
       
   718 	delete iCalExporter;
       
   719 	iCalExporter = NULL;
       
   720 	if (iCalSession)
       
   721 		{
       
   722 		iCalSession->StopChangeNotification();
       
   723 		iCalSession->StopFileChangeNotification();
       
   724 		delete iCalSession;
       
   725 		}
       
   726 	iCalSession = NULL;
       
   727 	}
       
   728 
       
   729 /**
       
   730  * CCalDavEngine::CreateCalObjectsL
       
   731  * create all calendar objects
       
   732  */
       
   733 TInt CCalDavEngine::CreateCalObjectsL()
       
   734 	{
       
   735 	iCalSession = CCalSession::NewL();
       
   736 	TRAPD(aErr,iCalSession->OpenL(*iCalendar));
       
   737 	iCalExporter = CCalenExporter::NewL(*iCalSession);
       
   738 	iCalImporter = CCalenImporter::NewL(*iCalSession);
       
   739 	iCalEntryView = CCalEntryView::NewL(*iCalSession);
       
   740 	iCalIter = CCalIter::NewL(*iCalSession);
       
   741 	return aErr;
       
   742 	}
       
   743 
       
   744 /**
       
   745  * CCalDavEngine::DisableL
       
   746  * disable sync
       
   747  */
       
   748 void CCalDavEngine::DisableL()
       
   749 	{
       
   750 	if (iEnabled)
       
   751 		{
       
   752 		iTimer->Cancel();
       
   753 		iEnabled = EFalse;
       
   754 		SetCalendarInfoL(KCaldavEnabled, KNullDesC8);
       
   755 		DeleteCalObjects();
       
   756 		}
       
   757 	}
       
   758 
       
   759 /**
       
   760  * CCalDavEngine::EnabledSync
       
   761  * check for enabled sync
       
   762  */
       
   763 TBool CCalDavEngine::EnabledSync()
       
   764 	{
       
   765 	return iEnabled;
       
   766 	}
       
   767 
       
   768 /**
       
   769  * CCalDavEngine::TimeReportL
       
   770  * do a CalDav time report
       
   771  */
       
   772 TInt CCalDavEngine::TimeReportL(TBool VEVENT, const TDesC8 &aStart,
       
   773 		TBool aDelete)
       
   774 	{
       
   775 	CBufFlat* body = CBufFlat::NewL(EXPANDSIZE_BIG);
       
   776 	CleanupStack::PushL(body);
       
   777 
       
   778 	body->InsertL(body->Size(), VEVENT ? KTimeStartEVENT() : KTimeStartTODO());
       
   779 	body->InsertL(body->Size(), aStart); // "20090509T220000Z"/>
       
   780 	body->InsertL(body->Size(), KTimeEnd);
       
   781 
       
   782 	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
       
   783 	CleanupStack::PushL(response);
       
   784 	TInt ret = iHttp->ReportL(*iUrl, body->Ptr(0), response);
       
   785 
       
   786 	if (ret == MULTISTATUS)
       
   787 		ret = aDelete ? ParseResponsesDeleteL(response->Ptr(0))
       
   788 				: ParseResponsesL(response->Ptr(0));
       
   789 	else
       
   790 		ret = KErrGeneral;
       
   791 
       
   792 	CleanupStack::PopAndDestroy(response);
       
   793 	CleanupStack::PopAndDestroy(body);
       
   794 	return ret;
       
   795 	}
       
   796 
       
   797 /**
       
   798  * CCalDavEngine::ListL
       
   799  * get events either using time report or basic propfind
       
   800  */
       
   801 TInt CCalDavEngine::ListL()
       
   802 	{
       
   803 	if (iOptions.calendar_access)
       
   804 		{
       
   805 		TTime syncstart;
       
   806 		syncstart.HomeTime();
       
   807 		syncstart = syncstart - iPastDays;
       
   808 		TBuf<100> nowStr;
       
   809 		syncstart.FormatL(nowStr, KFormatString);
       
   810 		TBuf8<100> nowStrAdd;
       
   811 		nowStrAdd.Append(nowStr);
       
   812 
       
   813 		TInt eventreturn = KErrNone;
       
   814 		if (iOptions.VEVENT)
       
   815 			eventreturn = TimeReportL(ETrue, nowStrAdd);
       
   816 
       
   817 		TInt todoreturn = KErrNone;
       
   818 		if (iOptions.VTODO)
       
   819 			todoreturn = TimeReportL(EFalse, nowStrAdd);
       
   820 
       
   821 		return (eventreturn == KErrNone) && (todoreturn == KErrNone) ? KErrNone
       
   822 				: KErrGeneral;
       
   823 		}
       
   824 	else
       
   825 		{
       
   826 		// use PROPFIND report
       
   827 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
   828 		CleanupStack::PushL(response);
       
   829 		TInt ret = iHttp->PropfindL(*iUrl, KPropList, response, EFalse);
       
   830 		if (ret == MULTISTATUS)
       
   831 			ret = ParseResponsesL(response->Ptr(0));
       
   832 		else
       
   833 			ret = KErrGeneral;
       
   834 		CleanupStack::PopAndDestroy(response);
       
   835 		return ret;
       
   836 		}
       
   837 	}
       
   838 
       
   839 /**
       
   840  * CCalDavEngine::SyncL
       
   841  * sync a calendar
       
   842  */
       
   843 TInt CCalDavEngine::SyncL()
       
   844 	{
       
   845 	if (iUrl)
       
   846 		{
       
   847 		if (iOptions.sync_collection)
       
   848 			return WebDavSyncL();
       
   849 		else
       
   850 			return ManualSyncL();
       
   851 		}
       
   852 	return KErrGeneral;
       
   853 	}
       
   854 
       
   855 /**
       
   856  * CCalDavEngine::ManualSyncL
       
   857  * if sync failed previously, try again manually
       
   858  */
       
   859 TBool CCalDavEngine::ManualSyncL()
       
   860 	{
       
   861 	TBool client = ClientChangesL();
       
   862 	if (iOptions.sync_ctag)
       
   863 		{
       
   864 		HBufC8 *newCTag = GetCTagL();
       
   865 		TBool server = ETrue;
       
   866 		if ((CTag() != *newCTag) && (*newCTag != KNullDesC8))
       
   867 			{
       
   868 			server = ServerChangesL();
       
   869 			if (server)
       
   870 				SetCTagL(newCTag);
       
   871 			else
       
   872 				delete newCTag;
       
   873 			}
       
   874 		else
       
   875 			delete newCTag;
       
   876 
       
   877 		return client || server;
       
   878 		}
       
   879 	else
       
   880 		{
       
   881 		TBool server = ServerChangesL();
       
   882 		return client || server;
       
   883 		}
       
   884 	}
       
   885 
       
   886 /**
       
   887  * CCalDavEngine::ServerChangesL
       
   888  * sync server changes
       
   889  */
       
   890 TBool CCalDavEngine::ServerChangesL()
       
   891 	{
       
   892 	// loop over all server items to find new and modified entries
       
   893 	// uses either propfind or calendar-query
       
   894 	TInt ret = ListL();
       
   895 
       
   896 	// loop over all local items to find deleted ones on the server
       
   897 	LocalLoopL(ELoopActionDeleteLocal);
       
   898 
       
   899 	return ret == KErrNone;
       
   900 	}
       
   901 
       
   902 /**
       
   903  * CCalDavEngine::LocalLoopL
       
   904  * loop over local calendar store
       
   905  */
       
   906 TInt CCalDavEngine::LocalLoopL(TLocalLoopAction aAction)
       
   907 	{
       
   908 	TBuf8<URLMAX> iter = iCalIter->FirstL();
       
   909 	TBuf8<URLMAX> url;
       
   910 	while (iter != KNullDesC8)
       
   911 		{
       
   912 		url.Append(*iUrl);
       
   913 		url.Append(iter);
       
   914 		url.Append(KIcs);
       
   915 		switch (aAction)
       
   916 			{
       
   917 			case ELoopActionDeleteLocal:
       
   918 				{
       
   919 				if (HeadL(iter) == NOTFOUND)
       
   920 					DeleteLocalEntryL(url);
       
   921 				break;
       
   922 				}
       
   923 			case ELoopActionFillArray:
       
   924 				{
       
   925 				RPointerArray<CCalEntry> entryArray;
       
   926 				CleanupClosePushL(entryArray);
       
   927 				iCalEntryView->FetchL(iter, entryArray);
       
   928 				if (entryArray.Count())
       
   929 					{
       
   930 					iLocalUidArray.Append(entryArray[0]->LocalUidL());
       
   931 					iGlobalUidArray.Append(entryArray[0]->UidL());
       
   932 					}
       
   933 				entryArray.ResetAndDestroy();
       
   934 				CleanupStack::PopAndDestroy(&entryArray);
       
   935 
       
   936 				break;
       
   937 				}
       
   938 			case ELoopActionUpload:
       
   939 				{
       
   940 				TInt pos = iGlobalUidArray.Find(iter);
       
   941 				if ((pos != KErrNotFound) && (iLocalUidArray.Count() > pos))
       
   942 					UploadEntryL(iLocalUidArray[pos],
       
   943 							MCalChangeCallBack2::EChangeAdd,
       
   944 							MCalChangeCallBack2::EChangeEntryAll);
       
   945 				break;
       
   946 				}
       
   947 			}
       
   948 		url.Delete(0, url.Length());
       
   949 		iter = iCalIter->NextL();
       
   950 		}
       
   951 	return KErrNone;
       
   952 	}
       
   953 
       
   954 /**
       
   955  * CCalDavEngine::ParseResponsesDeleteL
       
   956  * process a recieved multistatus response
       
   957  */
       
   958 TInt CCalDavEngine::ParseResponsesDeleteL(const TDesC8 &aDocument)
       
   959 	{
       
   960 	TInt ret = KErrNone;
       
   961 	RXmlEngDocument document = iDomParser.ParseL(aDocument);
       
   962 	CleanupClosePushL(document);
       
   963 	if (document.NotNull())
       
   964 		{
       
   965 		// this method works for response as well as sync-response
       
   966 		// do not use GetElementsByTagNameL for one specific responses directly	
       
   967 		TXmlEngElement ResponseListTop;
       
   968 		SearchL(document, KMultistatus, KNullDesC8, ResponseListTop);
       
   969 
       
   970 		RXmlEngNodeList<TXmlEngNode> ResponseList;
       
   971 		CleanupClosePushL(ResponseList);
       
   972 		ResponseListTop.GetChildNodes(ResponseList);
       
   973 
       
   974 		while (ResponseList.HasNext())
       
   975 			{
       
   976 			TXmlEngNode node = ResponseList.Next();
       
   977 			if (node.NodeType() == TXmlEngNode::EElement)
       
   978 				{
       
   979 				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
       
   980 				// don't do anything with home itself
       
   981 				if ((href.Right(KIcs().Length()) == KIcs))
       
   982 					{
       
   983 					if (!DoesEntryExistL(href))
       
   984 						DeleteEntryL(href);
       
   985 					}
       
   986 				}
       
   987 			}
       
   988 		CleanupStack::PopAndDestroy(&ResponseList);
       
   989 
       
   990 		}
       
   991 	else
       
   992 		ret = KErrArgument;
       
   993 	CleanupStack::PopAndDestroy(&document);
       
   994 	return ret;
       
   995 	}
       
   996 
       
   997 /**
       
   998  * CCalDavEngine::ParseResponsesL
       
   999  * process a recieved multistatus response
       
  1000  */
       
  1001 TInt CCalDavEngine::ParseResponsesL(RXmlEngDocument &aDocument, TBool aMultiget)
       
  1002 	{
       
  1003 	TInt ret = KErrNone;
       
  1004 	if (aDocument.NotNull())
       
  1005 		{
       
  1006 		CDesC8ArrayFlat *multiget = NULL;
       
  1007 		if (iOptions.MULTIGET)
       
  1008 			{
       
  1009 			multiget = new (ELeave) CDesC8ArrayFlat(ARRAYEXPAND);
       
  1010 			CleanupStack::PushL(multiget);
       
  1011 			}
       
  1012 
       
  1013 		// this method works for response as well as sync-response
       
  1014 		// do not use GetElementsByTagNameL for one specific responses directly	
       
  1015 		TXmlEngElement ResponseListTop;
       
  1016 		SearchL(aDocument, KMultistatus, KNullDesC8, ResponseListTop);
       
  1017 
       
  1018 		RXmlEngNodeList<TXmlEngNode> ResponseList;
       
  1019 		CleanupClosePushL(ResponseList);
       
  1020 		ResponseListTop.GetChildNodes(ResponseList);
       
  1021 
       
  1022 		while (ResponseList.HasNext())
       
  1023 			{
       
  1024 			TXmlEngNode node = ResponseList.Next();
       
  1025 			if (node.NodeType() == TXmlEngNode::EElement)
       
  1026 				{
       
  1027 				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
       
  1028 				//do not use Search, only looking for first childs,
       
  1029 				//as D:propstat has D:status as well
       
  1030 				RXmlEngNodeList<TXmlEngElement> statuslist;
       
  1031 				CleanupClosePushL(statuslist);
       
  1032 				node.AsElement().GetElementsByTagNameL(statuslist, KStatus,
       
  1033 						KDav);
       
  1034 				//only one or zero item
       
  1035 				HBufC8* status =
       
  1036 						statuslist.Count() ? statuslist.Next().Value().AllocL()
       
  1037 								: KNullDesC8().AllocL();
       
  1038 				CleanupStack::PopAndDestroy(&statuslist);
       
  1039 				CleanupStack::PushL(status);
       
  1040 				status->Des().LowerCase();
       
  1041 				TPtrC8 etag = SearchL(node, KEtag, KNullDesC8);
       
  1042 				RBuf8 calendardata;
       
  1043 				SearchL(node, KCalendarData, KNullDesC8, calendardata);
       
  1044 				calendardata.CleanupClosePushL();
       
  1045 
       
  1046 				// don't do anything with home itself
       
  1047 				if (href.Right(KIcs().Length()) == KIcs)
       
  1048 					{
       
  1049 					if ((*status == KHTTP200) || (*status == KHTTP201) || (*status == KNullDesC8))
       
  1050 						{
       
  1051 						if ((calendardata == KNullDesC8))
       
  1052 							{
       
  1053 							if (aMultiget)
       
  1054 								{
       
  1055 								// ATTENTION: an empty response to a multiget should never happen
       
  1056 								// data wrapped inside CDATA, e.g. bedework ??
       
  1057 								}
       
  1058 							else
       
  1059 								//TOOD: if this is a webdav sync response, we should skip the etag check
       
  1060 								AddModifyLocalEntryL(href, etag, multiget);
       
  1061 							}
       
  1062 						else
       
  1063 							{
       
  1064 							// response to a multiget or time-range report, we now already have everything we need
       
  1065 							StoreEntryL(calendardata, etag);
       
  1066 							}
       
  1067 						}
       
  1068 					else if (*status == KHTTP404)
       
  1069 						{
       
  1070 						if (iOptions.sync_collection)
       
  1071 							{
       
  1072 							// if this is an initial sync without token, 
       
  1073 							// this should be ignored, Sun Server bug!!!
       
  1074 							if (SyncToken() != KNullDesC8)
       
  1075 								DeleteLocalEntryL(href);
       
  1076 							}
       
  1077 						else
       
  1078 							{
       
  1079 							//multiget answer, but deleted in the meantime, should delete locally as well
       
  1080 							DeleteLocalEntryL(href);
       
  1081 							}
       
  1082 						}
       
  1083 					}
       
  1084 				CleanupStack::PopAndDestroy(&calendardata);
       
  1085 				CleanupStack::PopAndDestroy(status);
       
  1086 				}
       
  1087 			}
       
  1088 		CleanupStack::PopAndDestroy(&ResponseList);
       
  1089 
       
  1090 		if (iOptions.MULTIGET)
       
  1091 			{
       
  1092 			if (multiget->Count())
       
  1093 				{
       
  1094 				DownloadEntryL(multiget);
       
  1095 				multiget->Reset();
       
  1096 				}
       
  1097 			CleanupStack::PopAndDestroy(multiget);
       
  1098 			}
       
  1099 		}
       
  1100 	else
       
  1101 		ret = KErrArgument;
       
  1102 
       
  1103 	return ret;
       
  1104 	}
       
  1105 
       
  1106 /**
       
  1107  * CCalDavEngine::ParseResponsesL
       
  1108  * process a recieved multistatus response
       
  1109  */
       
  1110 TInt CCalDavEngine::ParseResponsesL(const TDesC8 &aDocument, TBool aMultiget)
       
  1111 	{
       
  1112 #ifdef _DEBUG
       
  1113 	_LIT(KFilename,"c:\\logs\\caldav\\parseresonseslatest.txt");
       
  1114 	ExportToFileNameL(aDocument, KFilename);
       
  1115 #endif
       
  1116 
       
  1117 	RXmlEngDocument document = iDomParser.ParseL(aDocument);
       
  1118 	CleanupClosePushL(document);
       
  1119 	TInt ret = ParseResponsesL(document, aMultiget);
       
  1120 	CleanupStack::PopAndDestroy(&document);
       
  1121 	return ret;
       
  1122 	}
       
  1123 
       
  1124 /**
       
  1125  * CCalDavEngine::StoreEntryL
       
  1126  * store event in local store
       
  1127  */
       
  1128 #ifdef ETAG
       
  1129 TInt CCalDavEngine::StoreEntryL(const TDesC8 &aBuf, const TDesC8 &aEtag)
       
  1130 #else
       
  1131 TInt CCalDavEngine::StoreEntryL(const TDesC8 &aBuf, const TDesC8 &/*aEtag*/)
       
  1132 #endif
       
  1133 	{
       
  1134 #ifdef _DEBUG
       
  1135 	_LIT(KFileName2, "C:\\logs\\caldav\\testing_import.txt");
       
  1136 	ExportToFileNameL(aBuf, KFileName2);
       
  1137 #endif
       
  1138 
       
  1139 	HBufC8* buffer = HBufC8::NewL(aBuf.Length() + 500);
       
  1140 	buffer->Des().Append(aBuf);
       
  1141 	TPtr8 ptr = buffer->Des();
       
  1142 	CalDavUtils::FixImportIssues(ptr);
       
  1143 
       
  1144 	RPointerArray<CCalEntry> Array;
       
  1145 	CleanupClosePushL(Array);
       
  1146 	RDesReadStream ReadStream;
       
  1147 	ReadStream.Open(ptr);
       
  1148 	CleanupClosePushL(ReadStream);
       
  1149 #ifdef _DEBUG
       
  1150 	_LIT(KFileName, "C:\\logs\\caldav\\testing_import_fixed.txt");
       
  1151 	ExportToFileNameL(ptr, KFileName);
       
  1152 #endif
       
  1153 	TRAPD(error, iCalImporter->ImportICalendarL(ReadStream,Array));
       
  1154 	CleanupStack::PopAndDestroy(&ReadStream); // calls close on rSteam												
       
  1155 	if ((error == KErrNone) && (Array.Count()))
       
  1156 		{
       
  1157 		iCalIntermimUtils2->StoreL(*iCalEntryView, *Array[0], ETrue); // or should last one be EFalse??
       
  1158 		TInt pos = iLocalUidArray.Find(Array[0]->LocalUidL());
       
  1159 		if (pos == KErrNotFound)
       
  1160 			{
       
  1161 			iLocalUidArray.Append(Array[0]->LocalUidL());
       
  1162 			iGlobalUidArray.Append(Array[0]->UidL());
       
  1163 			}
       
  1164 #ifdef ETAG
       
  1165 		Array[0]->SetETag(aEtag);
       
  1166 #endif
       
  1167 		}
       
  1168 	Array.ResetAndDestroy();
       
  1169 	CleanupStack::PopAndDestroy(&Array);
       
  1170 
       
  1171 	delete buffer;
       
  1172 	return error;
       
  1173 	}
       
  1174 
       
  1175 /**
       
  1176  * CCalDavEngine::WebDavSyncReportL
       
  1177  * webdav sync report
       
  1178  * http://tools.ietf.org/html/draft-daboo-webdav-sync-02
       
  1179  */
       
  1180 TInt CCalDavEngine::WebDavSyncReportL(TBool aSynctoken)
       
  1181 	{
       
  1182 	HBufC8 *Buf = HBufC8::NewL(KSync().Length() + SyncToken().Length());
       
  1183 	TPtrC8 token = SyncToken();
       
  1184 	if (aSynctoken)
       
  1185 		Buf->Des().Format(KSync, &token);
       
  1186 	else
       
  1187 		Buf->Des().Format(KSync, &KNullDesC8());
       
  1188 	CleanupStack::PushL(Buf);
       
  1189 
       
  1190 	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
       
  1191 	CleanupStack::PushL(response);
       
  1192 	TInt ret = iHttp->ReportL(*iUrl, *Buf, response);
       
  1193 
       
  1194 	if (ret == MULTISTATUS)
       
  1195 		{
       
  1196 		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  1197 		CleanupClosePushL(document);
       
  1198 		if (document.NotNull())
       
  1199 			{
       
  1200 			TPtrC8 Token = SearchL(document, KSynctoken, KNullDesC8);
       
  1201 			if ((Token != KNullDesC8) && (Token != SyncToken()))
       
  1202 				{
       
  1203 				ret = ParseResponsesL(document);
       
  1204 				//store newest token
       
  1205 				if (ret == KErrNone)
       
  1206 					SetSyncTokenL(Token.AllocL());
       
  1207 				}
       
  1208 			else
       
  1209 				ret = KErrNone;
       
  1210 			}
       
  1211 		else
       
  1212 			ret = KErrGeneral;
       
  1213 		CleanupStack::PopAndDestroy(&document);
       
  1214 		}
       
  1215 	CleanupStack::PopAndDestroy(response);
       
  1216 	CleanupStack::PopAndDestroy(Buf);
       
  1217 	return ret;
       
  1218 	}
       
  1219 
       
  1220 /**
       
  1221  * CCalDavEngine::WebDavSyncL
       
  1222  * sync using webdav sync
       
  1223  * http://tools.ietf.org/html/draft-daboo-webdav-sync-02
       
  1224  */
       
  1225 TBool CCalDavEngine::WebDavSyncL()
       
  1226 	{
       
  1227 	if (iHttp)
       
  1228 		{
       
  1229 		// commit any left over client changes
       
  1230 		TBool RetClient = ClientChangesL();
       
  1231 		// get all changes from server
       
  1232 		TInt ret = WebDavSyncReportL(ETrue);
       
  1233 		if (ret == CONFLICT)
       
  1234 			ret = WebDavSyncReportL(EFalse);
       
  1235 		return (ret == KErrNone) && RetClient;
       
  1236 		}
       
  1237 	return EFalse;
       
  1238 	}
       
  1239 
       
  1240 /**
       
  1241  * CCalDavEngine::GetUIDByUrl
       
  1242  * parse url to find UID
       
  1243  */
       
  1244 TPtrC8 CCalDavEngine::GetUIDByUrl(const TDesC8 &aUrl)
       
  1245 	{
       
  1246 	TPtrC8 UID;
       
  1247 	TInt Pos = aUrl.LocateReverse('/');
       
  1248 	TInt Pos2 = aUrl.Find(KIcs);
       
  1249 
       
  1250 	if ((Pos != KErrNotFound) && (Pos2 != KErrNotFound))
       
  1251 		UID.Set(aUrl.Mid(Pos + 1, Pos2 - Pos - 1));
       
  1252 	else
       
  1253 		{
       
  1254 		if (Pos != KErrNotFound)
       
  1255 			UID.Set(aUrl.Mid(Pos + 1, aUrl.Length() - Pos - 1));
       
  1256 		else if (Pos2 != KErrNotFound)
       
  1257 			UID.Set(aUrl.Left(aUrl.Length() - KIcs().Length()));
       
  1258 		else
       
  1259 			UID.Set(aUrl);
       
  1260 		}
       
  1261 
       
  1262 	return UID;
       
  1263 	}
       
  1264 
       
  1265 /**
       
  1266  * CCalDavEngine::DoesEntryExistL
       
  1267  * check if entry exists in local store
       
  1268  */
       
  1269 unsigned long CCalDavEngine::DoesEntryExistL(const TDesC8 &aUrl)
       
  1270 	{
       
  1271 	// check if we already have it locally by uid
       
  1272 	RPointerArray<CCalEntry> entryArray;
       
  1273 	CleanupClosePushL(entryArray);
       
  1274 	iCalEntryView->FetchL(GetUIDByUrl(aUrl), entryArray);
       
  1275 	// get parent 
       
  1276 	CCalEntry *entry = entryArray.Count() ? entryArray[0] : NULL;
       
  1277 	TInt ret = entry ? entry->LocalUidL() : 0;
       
  1278 	entryArray.ResetAndDestroy();
       
  1279 	CleanupStack::PopAndDestroy(&entryArray);
       
  1280 	return ret;
       
  1281 	}
       
  1282 
       
  1283 /**
       
  1284  * CCalDavEngine::ETagMatchL
       
  1285  * checks for equal ETag
       
  1286  */
       
  1287 TBool CCalDavEngine::ETagMatchL(const TDesC8& /*aUrl*/, const TDesC8& /*aETag*/)
       
  1288 	{
       
  1289 #ifdef ETAG
       
  1290 	// check if we already have it locally by uid
       
  1291 	RPointerArray<CCalEntry> entryArray;
       
  1292 	CleanupClosePushL(entryArray);
       
  1293 	iCalEntryView->FetchL(GetUIDByUrl(aUrl), entryArray);
       
  1294 	// get parent 
       
  1295 	CCalEntry *entry = entryArray.Count() ? entryArray[0] : NULL;
       
  1296 	TBool ret = entry ? entry->ETag() == aETag : EFalse;
       
  1297 	entryArray.ResetAndDestroy();
       
  1298 	CleanupStack::PopAndDestroy(&entryArray);
       
  1299 	return ret;
       
  1300 #else
       
  1301 	return EFalse;
       
  1302 #endif
       
  1303 	}
       
  1304 
       
  1305 /**
       
  1306  * CCalDavEngine::AddModifyLocalEntryL
       
  1307  * add or modify existing event
       
  1308  */
       
  1309 TInt CCalDavEngine::AddModifyLocalEntryL(const TDesC8 &aUrl,
       
  1310 		const TDesC8 &aETag, CDesC8ArrayFlat* aArray)
       
  1311 	{
       
  1312 	// check if we have the entry locally
       
  1313 	// check for etag if we have the latest version, if not, download and import or add to multiget request
       
  1314 	if (!ETagMatchL(aUrl, aETag))
       
  1315 		{
       
  1316 		if (aArray)
       
  1317 			aArray->AppendL(aUrl);
       
  1318 		else
       
  1319 			DownloadEntryL(aUrl);
       
  1320 		}
       
  1321 	return KErrNone;
       
  1322 	}
       
  1323 
       
  1324 /**
       
  1325  * CCalDavEngine::DownloadEntryL
       
  1326  * download entries using multiget from server
       
  1327  */
       
  1328 TInt CCalDavEngine::DownloadEntryL(CDesC8Array* aArray)
       
  1329 	{
       
  1330 	TInt ret = KErrNone;
       
  1331 	TInt64 remainder;
       
  1332 	TInt64 result = Math::DivMod64(aArray->Count(), MULTIGETSPLIT, remainder);
       
  1333 
       
  1334 	// split large multigets request into several smaller ones
       
  1335 	for (TInt64 l = 0; l <= result; l++)
       
  1336 		{
       
  1337 		// do the multiget request and pass it to parserepsonses again to read in the data
       
  1338 		CBufFlat* body = CBufFlat::NewL(EXPANDSIZE_BIG);
       
  1339 		CleanupStack::PushL(body);
       
  1340 
       
  1341 		body->InsertL(body->Size(), KMultistart);
       
  1342 		for (TInt64 i = 0; i <= ((l == result) ? remainder - 1 : MULTIGETSPLIT
       
  1343 				- 1); i++)
       
  1344 			{
       
  1345 			body->InsertL(body->Size(), KHrefstart);
       
  1346 			body->InsertL(body->Size(), (*aArray)[MULTIGETSPLIT * l + i]);
       
  1347 			body->InsertL(body->Size(), KHrefend);
       
  1348 			}
       
  1349 		body->InsertL(body->Size(), KMultiend);
       
  1350 
       
  1351 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_BIG);
       
  1352 		CleanupStack::PushL(response);
       
  1353 		TInt Return = iHttp->ReportL(*iUrl, body->Ptr(0), response);
       
  1354 
       
  1355 		if (Return == MULTISTATUS)
       
  1356 			{
       
  1357 			TInt parsereturn = ParseResponsesL(response->Ptr(0), ETrue);
       
  1358 			// if it failed before, we do not want to override this error
       
  1359 			ret = (ret == KErrNone) ? parsereturn : ret;
       
  1360 			}
       
  1361 		else
       
  1362 			ret = KErrGeneral;
       
  1363 		CleanupStack::PopAndDestroy(response);
       
  1364 		CleanupStack::PopAndDestroy(body);
       
  1365 
       
  1366 		}
       
  1367 	return ret;
       
  1368 	}
       
  1369 
       
  1370 /**
       
  1371  * CCalDavEngine::DownloadEntryL
       
  1372  * download entry from server
       
  1373  */
       
  1374 TInt CCalDavEngine::DownloadEntryL(const TDesC8 &aUrl)
       
  1375 	{
       
  1376 	TBuf8<URLMAX> url;
       
  1377 	url.Append(*iUrl);
       
  1378 	url.Append(GetUIDByUrl(aUrl));
       
  1379 	url.Append(KIcs);
       
  1380 
       
  1381 	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1382 	CleanupStack::PushL(response);
       
  1383 	TInt ret = iHttp->GetL(url, response);
       
  1384 	if (ret == OK)
       
  1385 		ret = StoreEntryL(response->Ptr(0), iHttp->ETag());
       
  1386 	else
       
  1387 		ret = KErrGeneral;
       
  1388 	CleanupStack::PopAndDestroy(response);
       
  1389 	return ret;
       
  1390 	}
       
  1391 
       
  1392 /**
       
  1393  * CCalDavEngine::DeleteLocalEntryL
       
  1394  * delete an event from local store
       
  1395  */
       
  1396 TInt CCalDavEngine::DeleteLocalEntryL(const TDesC8 &aUID)
       
  1397 	{
       
  1398 	CDesC8ArrayFlat * Array = new (ELeave) CDesC8ArrayFlat(ARRAYEXPAND);
       
  1399 	CleanupStack::PushL(Array);
       
  1400 	Array->AppendL(GetUIDByUrl(aUID));
       
  1401 	// we could have delete it ourselves, so it is already gone
       
  1402 	TRAPD(error, iCalEntryView->DeleteL(*Array));
       
  1403 	Array->Reset();
       
  1404 	CleanupStack::PopAndDestroy(Array);
       
  1405 	return error;
       
  1406 	}
       
  1407 
       
  1408 /**
       
  1409  * CCalDavEngine::DeleteRemovedEntriesOnServerL
       
  1410  * check for removed entries on server
       
  1411  */
       
  1412 TInt CCalDavEngine::DeleteRemovedEntriesOnServerL()
       
  1413 	{
       
  1414 	if (iOptions.calendar_access)
       
  1415 		{
       
  1416 		TTime syncstart;
       
  1417 		syncstart.HomeTime();
       
  1418 		syncstart = syncstart - iPastDays;
       
  1419 		TBuf<100> nowStr;
       
  1420 		syncstart.FormatL(nowStr, KFormatString);
       
  1421 		TBuf8<100> nowStrAdd;
       
  1422 		nowStrAdd.Append(nowStr);
       
  1423 
       
  1424 		TInt eventreturn = KErrNone;
       
  1425 		if (iOptions.VEVENT)
       
  1426 			eventreturn = TimeReportL(ETrue, nowStrAdd, ETrue);
       
  1427 
       
  1428 		TInt todoreturn = KErrNone;
       
  1429 		if (iOptions.VTODO)
       
  1430 			todoreturn = TimeReportL(EFalse, nowStrAdd, ETrue);
       
  1431 
       
  1432 		return (eventreturn == KErrNone) && (todoreturn == KErrNone) ? KErrNone
       
  1433 				: KErrGeneral;
       
  1434 		}
       
  1435 	else
       
  1436 		{
       
  1437 		// use PROPFIND report
       
  1438 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1439 		CleanupStack::PushL(response);
       
  1440 		TInt ret = iHttp->PropfindL(*iUrl, KPropList, response, EFalse);
       
  1441 		if (ret == MULTISTATUS)
       
  1442 			ret = ParseResponsesDeleteL(response->Ptr(0));
       
  1443 		else
       
  1444 			ret = KErrGeneral;
       
  1445 		CleanupStack::PopAndDestroy(response);
       
  1446 		return ret;
       
  1447 		}
       
  1448 
       
  1449 	}
       
  1450 
       
  1451 /**
       
  1452  * CCalDavEngine::UploadModifiedSinceDateL
       
  1453  * check for any modified data after last sync time
       
  1454  */
       
  1455 TBool CCalDavEngine::UploadModifiedSinceDateL()
       
  1456 	{
       
  1457 	TBool manualsync = EFalse;
       
  1458 	// upload modified and newly create ones 
       
  1459 	RArray<TCalLocalUid> *Ids = new (ELeave) RArray<TCalLocalUid> (ARRAYEXPAND);
       
  1460 	iCalEntryView->GetIdsModifiedSinceDateL(iLastSyncTime, *Ids);
       
  1461 	for (TInt i = 0; i < Ids->Count(); i++)
       
  1462 		{
       
  1463 		TCalLocalUid id = (*Ids)[i];
       
  1464 		TInt ret = UploadEntryL(id, MCalChangeCallBack2::EChangeUndefined,
       
  1465 				MCalChangeCallBack2::EChangeEntryAll);
       
  1466 		// TOOD: if it fails during upload, ignore
       
  1467 		// if it fails due to internet connection, try again
       
  1468 		if (ret != KErrNone)
       
  1469 			manualsync = ETrue;
       
  1470 		}
       
  1471 	Ids->Reset();
       
  1472 	delete Ids;
       
  1473 	return manualsync;
       
  1474 	}
       
  1475 
       
  1476 /**
       
  1477  * CCalDavEngine::ClientChangesL
       
  1478  * check for left over local client changes
       
  1479  */
       
  1480 TBool CCalDavEngine::ClientChangesL()
       
  1481 	{
       
  1482 	if (iCalEntryView && iManualSync)
       
  1483 		{
       
  1484 		iManualSync = EFalse;
       
  1485 
       
  1486 		// upload modified and newly create ones 
       
  1487 		iManualSync = UploadModifiedSinceDateL();
       
  1488 
       
  1489 		// delete locally deleted entries on server 
       
  1490 		for (TInt i = iDeletedEntries.Count() - 1; i >= 0; --i)
       
  1491 			{
       
  1492 			TInt ret = DeleteEntryL(iDeletedEntries[i]);
       
  1493 			if (ret == KErrNone)
       
  1494 				iDeletedEntries.Remove(i);
       
  1495 
       
  1496 			}
       
  1497 
       
  1498 		iManualSync = iDeletedEntries.Count() ? ETrue : EFalse;
       
  1499 
       
  1500 		TPckgC<TBool> manualSync(iManualSync);
       
  1501 		SetCalendarInfoL(KCaldavManualSync, manualSync);
       
  1502 		}
       
  1503 
       
  1504 	return ETrue;
       
  1505 	}
       
  1506 
       
  1507 /**
       
  1508  * CCalDavEngine::MkcalendarL
       
  1509  * create a new calendar on the server
       
  1510  */
       
  1511 TInt CCalDavEngine::MkcalendarL(const TDesC8 &aName)
       
  1512 	{
       
  1513 	if (iOptions.MKCALENDAR)
       
  1514 		{
       
  1515 		TBuf8<URLMAX> url;
       
  1516 		url.Append(*iHome);
       
  1517 		url.Append(aName);
       
  1518 		url.Append(KSlash);
       
  1519 
       
  1520 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1521 		CleanupStack::PushL(response);
       
  1522 
       
  1523 		// TOOD: initialize with name, body etc.
       
  1524 		TInt ret = iHttp->MkCalendarL(url, KNullDesC8, response);
       
  1525 
       
  1526 		if ((ret == CREATED) || (ret == OK))
       
  1527 			ret = KErrNone;
       
  1528 		else if ((ret == NOTALLOWED) || (ret == FORBIDDEN))
       
  1529 			ret = KErrArgument;
       
  1530 		else
       
  1531 			ret = KErrGeneral;
       
  1532 		CleanupStack::PopAndDestroy(response);
       
  1533 		return ret;
       
  1534 		}
       
  1535 	else
       
  1536 		return KErrNotSupported;
       
  1537 	}
       
  1538 
       
  1539 /**
       
  1540  * CCalDavEngine::DeleteCalendarL
       
  1541  * delete a calendar on the server
       
  1542  */
       
  1543 TInt CCalDavEngine::DeleteCalendarL(const TDesC8 &aName)
       
  1544 	{
       
  1545 	if (iOptions.MKCALENDAR)
       
  1546 		{
       
  1547 		TBuf8<URLMAX> url;
       
  1548 		url.Append(*iHome);
       
  1549 		url.Append(aName);
       
  1550 		url.Append(KSlash);
       
  1551 
       
  1552 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1553 		CleanupStack::PushL(response);
       
  1554 		TInt ret = iHttp->DeleteL(url);
       
  1555 		if ((ret == NOCONTENT) || (ret == OK))
       
  1556 			ret = KErrNone;
       
  1557 		else
       
  1558 			ret = KErrGeneral;
       
  1559 		CleanupStack::PopAndDestroy(response);
       
  1560 		return ret;
       
  1561 		}
       
  1562 	else
       
  1563 		return KErrNotSupported;
       
  1564 	}
       
  1565 
       
  1566 /**
       
  1567  * CCalDavEngine::HeadL
       
  1568  * check for existence of an entry on server
       
  1569  */
       
  1570 TInt CCalDavEngine::HeadL(const TDesC8 &aUID)
       
  1571 	{
       
  1572 	// special handing for yahoo neccessary
       
  1573 	// after deleting an event, it is still there and findable with HEAD
       
  1574 	_LIT8(KYahoo,"yahoo");
       
  1575 	_LIT8(KTrash,"trash");
       
  1576 
       
  1577 	TBuf8<URLMAX> url;
       
  1578 	url.Append(*iUrl);
       
  1579 	url.Append(aUID);
       
  1580 	url.Append(KIcs);
       
  1581 	if (iUrl->Find(KYahoo) == KErrNotFound)
       
  1582 		{
       
  1583 		TInt head = iHttp->HeadL(url);
       
  1584 		return (head == NOCONTENT) || (head == OK) ? OK : head;
       
  1585 		}
       
  1586 	else
       
  1587 		{
       
  1588 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1589 		CleanupStack::PushL(response);
       
  1590 		TInt ret = iHttp->PropfindL(url, KNullDesC8, response);
       
  1591 
       
  1592 		if (ret == MULTISTATUS)
       
  1593 			{
       
  1594 			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  1595 			CleanupClosePushL(document);
       
  1596 			if (document.NotNull())
       
  1597 				{
       
  1598 				HBufC8* href = SearchL(document, KHref, KNullDesC8).AllocL();
       
  1599 				href->Des().LowerCase();
       
  1600 				ret = href->Find(KTrash) == KErrNotFound ? OK : NOTFOUND;
       
  1601 				delete href;
       
  1602 				}
       
  1603 			CleanupStack::PopAndDestroy(&document);
       
  1604 			CleanupStack::PopAndDestroy(response);
       
  1605 			return ret;
       
  1606 			}
       
  1607 		else
       
  1608 			{
       
  1609 			CleanupStack::PopAndDestroy(response);
       
  1610 			return NOTFOUND;
       
  1611 			}
       
  1612 		}
       
  1613 	}
       
  1614 
       
  1615 /**
       
  1616  * CCalDavEngine::DeleteEntryL
       
  1617  * delete entry on server
       
  1618  */
       
  1619 TInt CCalDavEngine::DeleteEntryL(const TDesC8 &aUid)
       
  1620 	{
       
  1621 	TBuf8<URLMAX> url;
       
  1622 	url.Append(*iBaseUrl);
       
  1623 	url.Append(aUid);
       
  1624 	return iHttp->DeleteL(url);
       
  1625 	}
       
  1626 
       
  1627 /**
       
  1628  * CCalDavEngine::DeleteEntryL
       
  1629  * delete entry on server
       
  1630  */
       
  1631 TInt CCalDavEngine::DeleteEntryL(const TCalLocalUid &aUid)
       
  1632 	{
       
  1633 	TInt Ret = KErrNone;
       
  1634 	// find the filename for a given local UID
       
  1635 	TInt aPos = iLocalUidArray.Find(aUid);
       
  1636 	if (aPos != KErrNotFound)
       
  1637 		{
       
  1638 		TBuf8<URLMAX> url;
       
  1639 		url.Append(*iUrl);
       
  1640 		url.Append(iGlobalUidArray[aPos]);
       
  1641 		url.Append(KIcs);
       
  1642 
       
  1643 #ifdef ETAG
       
  1644 		CCalEntry* entry = iCalEntryView->FetchL(aUid);
       
  1645 		CleanupStack::PushL(entry);
       
  1646 		TInt Return = entry ? iHttp->DeleteL(url, entry->ETag())
       
  1647 		: iHttp->DeleteL(url);
       
  1648 		CleanupStack::PopAndDestroy(entry);
       
  1649 #else
       
  1650 		TInt Return = iHttp->DeleteL(url);
       
  1651 #endif
       
  1652 
       
  1653 		if ((Return == NOCONTENT) || (Return == OK))
       
  1654 			{
       
  1655 			SetLastSyncTimeL();
       
  1656 			}
       
  1657 		else if (Return == PRECONDFAILED)
       
  1658 			{
       
  1659 			// someone modified this in the meantime
       
  1660 			// ask user if he wants the new event or still delete it
       
  1661 			TBool modify = EFalse;
       
  1662 			if (modify)
       
  1663 				DownloadEntryL(url);
       
  1664 			else
       
  1665 				iHttp->DeleteL(url);
       
  1666 			}
       
  1667 		else if (Return == NOTFOUND)
       
  1668 			{
       
  1669 			// someone deleted this already
       
  1670 			Ret = KErrGeneral;
       
  1671 			}
       
  1672 		else if (Return == FORBIDDEN)
       
  1673 			{
       
  1674 			// event read-only
       
  1675 			Ret = KErrGeneral;
       
  1676 			}
       
  1677 		else
       
  1678 			{
       
  1679 			Ret = KErrGeneral;
       
  1680 			SyncFailedL();
       
  1681 			TInt pos = iDeletedEntries.Find(aUid);
       
  1682 			if (pos == KErrNotFound)
       
  1683 				iDeletedEntries.Append(aUid);
       
  1684 			}
       
  1685 		}
       
  1686 	else
       
  1687 		Ret = KErrGeneral;
       
  1688 	return Ret;
       
  1689 	}
       
  1690 
       
  1691 /**
       
  1692  * CCalDavEngine::UploadEntryL
       
  1693  * upload entry to server
       
  1694  */
       
  1695 TInt CCalDavEngine::UploadEntryL(CCalEntry* aEntry,
       
  1696 		MCalChangeCallBack2::TChangeType aChangeType,
       
  1697 		MCalChangeCallBack2::TChangeEntryType aEntryType)
       
  1698 	{
       
  1699 	if (aEntry)
       
  1700 		{
       
  1701 		TInt ret = KErrNone;
       
  1702 		TBool upload = EFalse;
       
  1703 		switch (aEntryType)
       
  1704 			{
       
  1705 			case MCalChangeCallBack2::EChangeEntryEvent:
       
  1706 			case MCalChangeCallBack2::EChangeEntryTodo:
       
  1707 				{
       
  1708 				upload = aEntry && ((MCalChangeCallBack2::EChangeEntryEvent
       
  1709 						&& iOptions.VEVENT)
       
  1710 						|| (MCalChangeCallBack2::EChangeEntryTodo
       
  1711 								&& iOptions.VTODO));
       
  1712 				break;
       
  1713 				}
       
  1714 			case MCalChangeCallBack2::EChangeEntryAll:
       
  1715 				{
       
  1716 				if (aEntry)
       
  1717 					{
       
  1718 					switch (aEntry->EntryTypeL())
       
  1719 						{
       
  1720 						case CCalEntry::EAppt:
       
  1721 						case CCalEntry::EAnniv:
       
  1722 						case CCalEntry::EEvent:
       
  1723 						case CCalEntry::EReminder:
       
  1724 							{
       
  1725 							upload = iOptions.VEVENT;
       
  1726 							break;
       
  1727 							}
       
  1728 						case CCalEntry::ETodo:
       
  1729 							{
       
  1730 							upload = iOptions.VTODO;
       
  1731 							break;
       
  1732 							}
       
  1733 						}
       
  1734 					}
       
  1735 
       
  1736 				}
       
  1737 			}
       
  1738 		if (upload)
       
  1739 			{
       
  1740 			CBufFlat* BufFlat = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1741 			CleanupStack::PushL(BufFlat);
       
  1742 			RBufWriteStream writeStream(*BufFlat);
       
  1743 			CleanupClosePushL(writeStream);
       
  1744 			iCalExporter->ExportICalL(*aEntry, writeStream);
       
  1745 			writeStream.CommitL();
       
  1746 			CleanupStack::PopAndDestroy(&writeStream);
       
  1747 
       
  1748 			HBufC8* buffer = BufFlat->Ptr(0).AllocL();
       
  1749 			CleanupStack::PopAndDestroy(BufFlat);
       
  1750 			CleanupStack::PushL(buffer);
       
  1751 			TPtr8 ptr = buffer->Des();
       
  1752 			CalDavUtils::FixExportIssues(ptr);
       
  1753 
       
  1754 #ifdef _DEBUG
       
  1755 			ExportToFileL(aEntry, iCalExporter);
       
  1756 			_LIT(KFileName, "C:\\logs\\caldav\\testing_export_fixed.txt");
       
  1757 			ExportToFileNameL(ptr, KFileName);
       
  1758 #endif
       
  1759 
       
  1760 			TBuf8<URLMAX> url;
       
  1761 			url.Append(*iUrl);
       
  1762 			url.Append(aEntry->UidL());
       
  1763 			url.Append(KIcs);
       
  1764 
       
  1765 			CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1766 			CleanupStack::PushL(response);
       
  1767 
       
  1768 #ifdef ETAG
       
  1769 			TPtrC8 etag = aEntry->GetETag();
       
  1770 			TBool newentry = (aChangeType == MCalChangeCallBack2::EChangeAdd)
       
  1771 			|| ((aChangeType == MCalChangeCallBack2::EChangeUndefined)
       
  1772 					&& (etag == KNullDesC8));
       
  1773 			TInt Ret = newentry ? iHttp->PutL(url, *buffer, response)
       
  1774 			: iHttp->PutL(url, *buffer, response, etag);
       
  1775 #else
       
  1776 			TBool newentry = (aChangeType == MCalChangeCallBack2::EChangeAdd)
       
  1777 					|| (aChangeType == MCalChangeCallBack2::EChangeUndefined);
       
  1778 			TInt Ret = newentry ? iHttp->PutL(url, *buffer, response)
       
  1779 					: iHttp->PutL(url, *buffer, response, _L8("ETAG"));
       
  1780 #endif
       
  1781 			if ((Ret == CREATED) || (Ret == NOCONTENT) || (Ret == OK))
       
  1782 				{
       
  1783 				if (newentry)
       
  1784 					{
       
  1785 					iLocalUidArray.Append(aEntry->LocalUidL());
       
  1786 					iGlobalUidArray.Append(aEntry->UidL());
       
  1787 					}
       
  1788 #ifdef ETAG
       
  1789 				aEntry->SetETag(iHttp->ETag());
       
  1790 #endif
       
  1791 				SetLastSyncTimeL();
       
  1792 				}
       
  1793 			else if (Ret == PRECONDFAILED)
       
  1794 				{
       
  1795 				if (newentry)// same filename already exists, use a different one and upload again
       
  1796 					{
       
  1797 					TBuf8<URLMAX> nextUrl;
       
  1798 					nextUrl.Append(*iUrl);
       
  1799 					nextUrl.Append(aEntry->UidL());
       
  1800 					TTime time;
       
  1801 					time.HomeTime();
       
  1802 					_LIT(KTimeFormat,"%H%T%S");
       
  1803 					TBuf<20> StringTime;
       
  1804 					time.FormatL(StringTime, KTimeFormat);
       
  1805 					nextUrl.Append(StringTime);
       
  1806 					nextUrl.Append(_L8(".ics"));
       
  1807 					response->Reset();
       
  1808 					TInt Ret = iHttp->PutL(nextUrl, *buffer, response);
       
  1809 					if ((Ret == CREATED) || (Ret == OK))
       
  1810 						{
       
  1811 						iLocalUidArray.Append(aEntry->LocalUidL());
       
  1812 						iGlobalUidArray.Append(aEntry->UidL());
       
  1813 #ifdef ETAG
       
  1814 						aEntry->SetETag(iHttp->ETag());
       
  1815 #endif
       
  1816 						SetLastSyncTimeL();
       
  1817 						}
       
  1818 					else
       
  1819 						{
       
  1820 						SyncFailedL();
       
  1821 						ret = KErrAbort;
       
  1822 						}
       
  1823 					}
       
  1824 				else
       
  1825 					{
       
  1826 					if (!iKeepServerEntry)
       
  1827 						{
       
  1828 						response->Reset();
       
  1829 						// upload again without ETAG to overwrite server entry
       
  1830 						TInt Ret = iHttp->PutL(url, *buffer, response);
       
  1831 						if ((Ret == CREATED) || (Ret == OK))
       
  1832 							{
       
  1833 #ifdef ETAG
       
  1834 							aEntry->SetETag(iHttp->ETag());
       
  1835 #endif
       
  1836 							SetLastSyncTimeL();
       
  1837 							}
       
  1838 						else
       
  1839 							{
       
  1840 							SyncFailedL();
       
  1841 							ret = KErrAbort;
       
  1842 							}
       
  1843 						}
       
  1844 					else
       
  1845 						{
       
  1846 						// download the server event and update local store
       
  1847 						ret = DownloadEntryL(url);
       
  1848 						if (ret == KErrNone)
       
  1849 							SetLastSyncTimeL();
       
  1850 						else
       
  1851 							{
       
  1852 							SyncFailedL();
       
  1853 							ret = KErrAbort;
       
  1854 							}
       
  1855 						}
       
  1856 					}
       
  1857 				}
       
  1858 			else
       
  1859 				{
       
  1860 				SyncFailedL();
       
  1861 				ret = KErrAbort;
       
  1862 				}
       
  1863 			CleanupStack::PopAndDestroy(response);
       
  1864 			CleanupStack::PopAndDestroy(buffer);
       
  1865 			}
       
  1866 		return ret;
       
  1867 		}
       
  1868 	return KErrArgument;
       
  1869 	}
       
  1870 
       
  1871 /**
       
  1872  * CCalDavEngine::UploadEntryL
       
  1873  * upload entry to server
       
  1874  */
       
  1875 TInt CCalDavEngine::UploadEntryL(const TCalLocalUid &aUid,
       
  1876 		MCalChangeCallBack2::TChangeType aChangeType,
       
  1877 		MCalChangeCallBack2::TChangeEntryType aEntryType)
       
  1878 	{
       
  1879 	CCalEntry * aEntry = iCalEntryView->FetchL(aUid);
       
  1880 	CleanupStack::PushL(aEntry);
       
  1881 	TInt ret = UploadEntryL(aEntry, aChangeType, aEntryType);
       
  1882 	CleanupStack::PopAndDestroy(aEntry);
       
  1883 	return ret;
       
  1884 	}
       
  1885 
       
  1886 /**
       
  1887  * CCalDavEngine::GetSyncTokenL
       
  1888  * get latest Webdav Sync token
       
  1889  */
       
  1890 HBufC8* CCalDavEngine::GetSyncTokenL()
       
  1891 	{
       
  1892 	HBufC8 *aBuf = HBufC8::NewL(KSync().Length());
       
  1893 	aBuf->Des().Format(KSync, &KNullDesC8());
       
  1894 	CleanupStack::PushL(aBuf);
       
  1895 
       
  1896 	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1897 	CleanupStack::PushL(response);
       
  1898 	TInt RetServer = iHttp->ReportL(*iUrl, *aBuf, response);
       
  1899 
       
  1900 	if (RetServer)
       
  1901 		{
       
  1902 		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  1903 		CleanupClosePushL(document);
       
  1904 		if (document.NotNull())
       
  1905 			{
       
  1906 			HBufC8* ret = SearchL(document, KSynctoken, KNullDesC8).AllocL();
       
  1907 			CleanupStack::PopAndDestroy(&document);
       
  1908 			CleanupStack::PopAndDestroy(response);
       
  1909 			CleanupStack::PopAndDestroy(aBuf);
       
  1910 			return ret;
       
  1911 			}
       
  1912 		CleanupStack::PopAndDestroy(&document);
       
  1913 		}
       
  1914 	CleanupStack::PopAndDestroy(response);
       
  1915 	CleanupStack::PopAndDestroy(aBuf);
       
  1916 	return KNullDesC8().AllocL();
       
  1917 	}
       
  1918 
       
  1919 /**
       
  1920  * CCalDavEngine::CheckCalendarInfoL
       
  1921  * check for new calendar displayname and color
       
  1922  */
       
  1923 void CCalDavEngine::CheckCalendarInfoL(RXmlEngDocument &aDocument)
       
  1924 	{
       
  1925 	TBool change = EFalse;
       
  1926 	CCalCalendarInfo* info = iCalSession->CalendarInfoL();
       
  1927 	CleanupStack::PushL(info);
       
  1928 
       
  1929 	HBufC8* color = SearchL(aDocument, KCalendar_Color, KNullDesC8).AllocLC();
       
  1930 	if ((*color != KNullDesC8) && (color->Length() > 6))
       
  1931 		{
       
  1932 		TLex8 lexred(color->Des().Mid(1, 2));
       
  1933 		TInt red;
       
  1934 		lexred.Val(red);
       
  1935 		TLex8 lexgreen(color->Des().Mid(3, 2));
       
  1936 		TInt green;
       
  1937 		lexgreen.Val(green);
       
  1938 		TLex8 lexblue(color->Des().Mid(5, 2));
       
  1939 		TInt blue;
       
  1940 		lexblue.Val(blue);
       
  1941 		TRgb newcolor(red, green, blue);
       
  1942 		if (info->Color() != newcolor)
       
  1943 			{
       
  1944 			info->SetColor(newcolor);
       
  1945 			change = ETrue;
       
  1946 			}
       
  1947 		}
       
  1948 	CleanupStack::PopAndDestroy(color);
       
  1949 
       
  1950 	HBufC8* displayname =
       
  1951 			SearchL(aDocument, KDisplayname, KNullDesC8).AllocLC();
       
  1952 	if (*displayname != KNullDesC8)
       
  1953 		{
       
  1954 		HBufC16* name =
       
  1955 				CnvUtfConverter::ConvertToUnicodeFromUtf8L(*displayname);
       
  1956 		CleanupStack::PushL(name);
       
  1957 		if (info->NameL() != *name)
       
  1958 			{
       
  1959 			info->SetNameL(*name);
       
  1960 			change = ETrue;
       
  1961 			}
       
  1962 		CleanupStack::PopAndDestroy(name);
       
  1963 		change = ETrue;
       
  1964 		}
       
  1965 	CleanupStack::PopAndDestroy(displayname);
       
  1966 
       
  1967 	if (change)
       
  1968 		iCalSession->SetCalendarInfoL(*info);
       
  1969 	CleanupStack::PopAndDestroy(info);
       
  1970 
       
  1971 	}
       
  1972 
       
  1973 /**
       
  1974  * CCalDavEngine::GetCTagL
       
  1975  * get latest CTag
       
  1976  * https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-ctag.txt
       
  1977  */
       
  1978 HBufC8* CCalDavEngine::GetCTagL()
       
  1979 	{
       
  1980 	if (iHttp)
       
  1981 		{
       
  1982 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  1983 		CleanupStack::PushL(response);
       
  1984 		TInt ret = iHttp->PropfindL(*iUrl, KCtag, response);
       
  1985 
       
  1986 		if (ret == MULTISTATUS)
       
  1987 			{
       
  1988 			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  1989 			CleanupClosePushL(document);
       
  1990 			if (document.NotNull())
       
  1991 				{
       
  1992 				HBufC8* status =
       
  1993 						SearchL(document, KStatus, KNullDesC8).AllocLC();
       
  1994 				HBufC8* ctag =
       
  1995 						SearchL(document, KGetctag, KNullDesC8).AllocLC();
       
  1996 				status->Des().LowerCase();
       
  1997 				if ((*ctag != KNullDesC8) && (*status == KHTTP200))
       
  1998 					{
       
  1999 					CleanupStack::Pop(ctag);
       
  2000 					CleanupStack::PopAndDestroy(status);
       
  2001 					CleanupStack::PopAndDestroy(&document);
       
  2002 					CleanupStack::PopAndDestroy(response);
       
  2003 					return ctag;
       
  2004 					}
       
  2005 				else
       
  2006 					CleanupStack::PopAndDestroy(ctag);
       
  2007 				CleanupStack::PopAndDestroy(status);
       
  2008 				}
       
  2009 			CleanupStack::PopAndDestroy(&document);
       
  2010 
       
  2011 			}
       
  2012 		CleanupStack::PopAndDestroy(response);
       
  2013 		}
       
  2014 	return KNullDesC8().AllocL();
       
  2015 	}
       
  2016 
       
  2017 /**
       
  2018  * CCalDavEngine::GetOptionsL
       
  2019  * get OPTIONS from server
       
  2020  */
       
  2021 TBool CCalDavEngine::GetOptionsL()
       
  2022 	{
       
  2023 	if (iHttp)
       
  2024 		{
       
  2025 		// check DAV and allow headers
       
  2026 		iHttp->GetServerOptionsL(*iUrl, iOptions);
       
  2027 
       
  2028 		// check ctag extension
       
  2029 		HBufC8* ctag = GetCTagL();
       
  2030 		if (*ctag != KNullDesC8)
       
  2031 			iOptions.sync_ctag = true;
       
  2032 		delete ctag;
       
  2033 
       
  2034 		// check supported elements
       
  2035 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  2036 		CleanupStack::PushL(response);
       
  2037 		TInt Ret = iHttp->PropfindL(*iUrl, KSupportedSet, response);
       
  2038 
       
  2039 		if (Ret == MULTISTATUS)
       
  2040 			{
       
  2041 			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  2042 			CleanupClosePushL(document);
       
  2043 			if (document.NotNull())
       
  2044 				{
       
  2045 				CheckCalendarInfoL(document);
       
  2046 
       
  2047 				//<C:supported-calendar-component-set/>
       
  2048 				TXmlEngElement supportedelement;
       
  2049 				SearchL(document, KSupportedCalendarComponentSet, KNullDesC8,
       
  2050 						supportedelement);
       
  2051 				if (supportedelement.NotNull())
       
  2052 					{
       
  2053 					RXmlEngNodeList<TXmlEngElement> supportedelements;
       
  2054 					CleanupClosePushL(supportedelements);
       
  2055 					supportedelement.GetChildElements(supportedelements);
       
  2056 					while (supportedelements.HasNext())
       
  2057 						{
       
  2058 						TXmlEngElement element = supportedelements.Next();
       
  2059 						TPtrC8 value = element.AttributeValueL(KName);
       
  2060 						if (value == KNullDesC8)
       
  2061 							value.Set(element.AttributeValueL(KName, KCalDav));
       
  2062 						if (value == KVEVENT)
       
  2063 							iOptions.VEVENT = ETrue;
       
  2064 						else if (value == KVTODO)
       
  2065 							iOptions.VTODO = ETrue;
       
  2066 						else if (value == KVFREBUSY)
       
  2067 							iOptions.VFREEBUSY = ETrue;
       
  2068 						else if (value == KVJOURNAL)
       
  2069 							iOptions.VJOURNAL = ETrue;
       
  2070 						}
       
  2071 					CleanupStack::PopAndDestroy(&supportedelements);
       
  2072 					}
       
  2073 				}
       
  2074 			CleanupStack::PopAndDestroy(&document);
       
  2075 			}
       
  2076 		CleanupStack::PopAndDestroy(response);
       
  2077 		}
       
  2078 	return ETrue;
       
  2079 	}
       
  2080 
       
  2081 /**
       
  2082  * CCalDavEngine::SetSyncTokenL
       
  2083  * set sync token
       
  2084  */
       
  2085 void CCalDavEngine::SetSyncTokenL(HBufC8* aToken)
       
  2086 	{
       
  2087 	if (iSynctoken)
       
  2088 		{
       
  2089 		delete iSynctoken;
       
  2090 		iSynctoken = NULL;
       
  2091 		}
       
  2092 	iSynctoken = aToken;
       
  2093 	SetCalendarInfoL(KCaldavSynctoken, *iSynctoken);
       
  2094 	}
       
  2095 
       
  2096 /**
       
  2097  * CCalDavEngine::SyncToken
       
  2098  * get synctoken
       
  2099  */
       
  2100 TPtrC8 CCalDavEngine::SyncToken()
       
  2101 	{
       
  2102 	return iSynctoken ? *iSynctoken : KNullDesC8();
       
  2103 	}
       
  2104 
       
  2105 /**
       
  2106  * CCalDavEngine::SetCTagL
       
  2107  * set ctag
       
  2108  */
       
  2109 void CCalDavEngine::SetCTagL(HBufC8* aToken)
       
  2110 	{
       
  2111 	if (iCTag)
       
  2112 		{
       
  2113 		delete iCTag;
       
  2114 		iCTag = NULL;
       
  2115 		}
       
  2116 	iCTag = aToken;
       
  2117 	SetCalendarInfoL(KCaldavCtag, *iCTag);
       
  2118 	}
       
  2119 
       
  2120 /**
       
  2121  * CCalDavEngine::CTag
       
  2122  * get ctag
       
  2123  */
       
  2124 TPtrC8 CCalDavEngine::CTag()
       
  2125 	{
       
  2126 	return iCTag ? *iCTag : KNullDesC8();
       
  2127 	}
       
  2128 
       
  2129 /**
       
  2130  * CCalDavEngine::SetLastSyncTimeL
       
  2131  * set last sync time
       
  2132  */
       
  2133 void CCalDavEngine::SetLastSyncTimeL()
       
  2134 	{
       
  2135 	// only set a new last sync time, if we did not have a failed one before
       
  2136 	// otherwise, the old one would be lost
       
  2137 	if (!iManualSync)
       
  2138 		{
       
  2139 		TTime time;
       
  2140 		time.UniversalTime();
       
  2141 		iLastSyncTime.SetTimeUtcL(time);
       
  2142 		TPckgC<TCalTime> lasttime(iLastSyncTime);
       
  2143 		SetCalendarInfoL(KCaldavTime, lasttime);
       
  2144 		}
       
  2145 	}
       
  2146 
       
  2147 /**
       
  2148  * CCalDavEngine::SyncFailedL
       
  2149  * sync failed, enable manual sync
       
  2150  */
       
  2151 void CCalDavEngine::SyncFailedL()
       
  2152 	{
       
  2153 	if (!iManualSync)
       
  2154 		{
       
  2155 		iManualSync = ETrue;
       
  2156 		TPckgC<TBool> manualSync(iManualSync);
       
  2157 		SetCalendarInfoL(KCaldavManualSync, manualSync);
       
  2158 		}
       
  2159 	}
       
  2160 
       
  2161 /**
       
  2162  * CCalDavEngine::GetBaseUrl
       
  2163  * get base domain url
       
  2164  */
       
  2165 void CCalDavEngine::GetBaseUrl(const TDesC8 &aUrl)
       
  2166 	{
       
  2167 	_LIT8(http,"http://");
       
  2168 	_LIT8(https,"https://");
       
  2169 
       
  2170 	if (iBaseUrl)
       
  2171 		{
       
  2172 		delete iBaseUrl;
       
  2173 		iBaseUrl = NULL;
       
  2174 		}
       
  2175 
       
  2176 	if (aUrl.Length() > http().Length())
       
  2177 		{
       
  2178 		TInt length = aUrl.Find(https) != KErrNotFound ? https().Length()
       
  2179 				: http().Length();
       
  2180 		TInt pos = aUrl.Mid(length).Locate('/');
       
  2181 		iBaseUrl = aUrl.Left(pos + length).Alloc();
       
  2182 		}
       
  2183 	}
       
  2184 
       
  2185 /**
       
  2186  * CCalDavEngine::FindUrlsL
       
  2187  * find home, inbox and outbox property
       
  2188  */
       
  2189 void CCalDavEngine::FindUrlsL(const TDesC8 &aDes, HBufC8 *&home,
       
  2190 		HBufC8 *&inbox, HBufC8 *&outbox)
       
  2191 	{
       
  2192 	RXmlEngDocument document = iDomParser.ParseL(aDes);
       
  2193 	CleanupClosePushL(document);
       
  2194 	if (document.NotNull())
       
  2195 		{
       
  2196 		HBufC8* status = SearchL(document, KStatus, KNullDesC8).AllocLC();
       
  2197 		status->Des().LowerCase();
       
  2198 		if (*status == KHTTP200)
       
  2199 			{
       
  2200 			TXmlEngElement calendarhome, inboxhome, outboxhome;
       
  2201 
       
  2202 			SearchL(document, KCalendarHomeSet, KNullDesC8, calendarhome);
       
  2203 			if (calendarhome.NotNull())
       
  2204 				{
       
  2205 				TPtrC8 homeend = SearchL(calendarhome, KHref, KNullDesC8);
       
  2206 				home = HBufC8::NewL(iBaseUrl->Length() + homeend.Length());
       
  2207 				home->Des().Append(*iBaseUrl);
       
  2208 				home->Des().Append(homeend);
       
  2209 				}
       
  2210 
       
  2211 			SearchL(document, KInbox, KNullDesC8, inboxhome);
       
  2212 			if (inboxhome.NotNull())
       
  2213 				{
       
  2214 				TPtrC8 inboxend = SearchL(inboxhome, KHref, KNullDesC8);
       
  2215 				inbox = HBufC8::NewL(iBaseUrl->Length() + inboxend.Length());
       
  2216 				inbox->Des().Append(*iBaseUrl);
       
  2217 				inbox->Des().Append(inboxend);
       
  2218 				}
       
  2219 
       
  2220 			SearchL(document, KOutbox, KNullDesC8, outboxhome);
       
  2221 			if (outboxhome.NotNull())
       
  2222 				{
       
  2223 				TPtrC8 outboxend = SearchL(outboxhome, KHref, KNullDesC8);
       
  2224 				outbox = HBufC8::NewL(iBaseUrl->Length() + outboxend.Length());
       
  2225 				outbox->Des().Append(*iBaseUrl);
       
  2226 				outbox->Des().Append(outboxend);
       
  2227 				}
       
  2228 			}
       
  2229 		CleanupStack::PopAndDestroy(status);
       
  2230 		}
       
  2231 	CleanupStack::PopAndDestroy(&document);
       
  2232 	}
       
  2233 
       
  2234 /**
       
  2235  * CCalDavEngine::FindCalendarCollectionL
       
  2236  * find all calendar collections under home url
       
  2237  */
       
  2238 HBufC8* CCalDavEngine::FindCalendarCollectionL(const TDesC8 &aUrl,
       
  2239 		CDesC8ArrayFlat *aArray)
       
  2240 	{
       
  2241 	HBufC8* homecalendar = 0;
       
  2242 
       
  2243 	// do propfind depth:1 and find all calendar collections
       
  2244 	// right now, take the first one as default
       
  2245 	CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  2246 	CleanupStack::PushL(response);
       
  2247 	TInt retcode = iHttp->PropfindL(aUrl, KCalendarurl, response, EFalse);
       
  2248 	if (retcode == MULTISTATUS)
       
  2249 		{
       
  2250 		RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  2251 		CleanupClosePushL(document);
       
  2252 		if (document.NotNull() && document.DocumentElement().NotNull())
       
  2253 			{
       
  2254 			RXmlEngNodeList<TXmlEngElement> ResponseList;
       
  2255 			CleanupClosePushL(ResponseList);
       
  2256 			document.DocumentElement().GetElementsByTagNameL(ResponseList,
       
  2257 					KResponse, KDav);
       
  2258 			TBool FirstOneDone = EFalse;
       
  2259 			while (ResponseList.HasNext())
       
  2260 				{
       
  2261 				TXmlEngElement node = ResponseList.Next();
       
  2262 				TPtrC8 href = SearchL(node, KHref, KNullDesC8);
       
  2263 				TPtrC8 status = SearchL(node, KStatus, KNullDesC8);
       
  2264 
       
  2265 				TXmlEngElement calendar;
       
  2266 				TXmlEngElement vevent_collection;
       
  2267 				TXmlEngElement vtodo_collection;
       
  2268 				SearchL(node, KCalendar, KNullDesC8, calendar);
       
  2269 				SearchL(node, KVEventCollection, KNullDesC8, vevent_collection);
       
  2270 				SearchL(node, KVTodoCollection, KNullDesC8, vtodo_collection);
       
  2271 
       
  2272 				if (calendar.NotNull() || vevent_collection.NotNull()
       
  2273 						|| vtodo_collection.NotNull())
       
  2274 					{
       
  2275 					if (!FirstOneDone)
       
  2276 						{
       
  2277 						homecalendar = HBufC8::NewL(iBaseUrl->Length()
       
  2278 								+ href.Length());
       
  2279 						homecalendar->Des().Append(*iBaseUrl);
       
  2280 						homecalendar->Des().Append(href);
       
  2281 
       
  2282 						iOptions.VEVENT = vevent_collection.NotNull();
       
  2283 						iOptions.VTODO = vtodo_collection.NotNull();
       
  2284 
       
  2285 						FirstOneDone = ETrue;
       
  2286 						}
       
  2287 
       
  2288 					if (aArray)
       
  2289 						{
       
  2290 						TBuf8<URLMAX> url;
       
  2291 						url.Append(*iBaseUrl);
       
  2292 						url.Append(href);
       
  2293 						aArray->AppendL(url);
       
  2294 						}
       
  2295 					}
       
  2296 				}
       
  2297 			CleanupStack::PopAndDestroy(&ResponseList);
       
  2298 			}
       
  2299 		CleanupStack::PopAndDestroy(&document);
       
  2300 		}
       
  2301 	CleanupStack::PopAndDestroy(response);
       
  2302 	return homecalendar;
       
  2303 	}
       
  2304 
       
  2305 /**
       
  2306  * CCalDavEngine::GetCalendarUrlsL
       
  2307  * find calendar url based on any url
       
  2308  * could be principal url, home or direct calendar url
       
  2309  */
       
  2310 TInt CCalDavEngine::GetCalendarUrlsL(CDesC8ArrayFlat *aArray)
       
  2311 	{
       
  2312 	if (iHttp && iUrl)
       
  2313 		{
       
  2314 		HBufC8 *principal = 0;
       
  2315 		HBufC8 *home = 0;
       
  2316 		HBufC8 *homecalendar = 0;
       
  2317 		HBufC8 *inbox = 0;
       
  2318 		HBufC8 *outbox = 0;
       
  2319 
       
  2320 		GetBaseUrl(*iUrl);
       
  2321 
       
  2322 		// TODO: does this really find groupdav collection?
       
  2323 
       
  2324 		// find out if this is a caldav or groupdav calendar collection
       
  2325 		CBufFlat* response = CBufFlat::NewL(EXPANDSIZE_SMALL);
       
  2326 		CleanupStack::PushL(response);
       
  2327 		TInt retcode = iHttp->PropfindL(*iUrl, KCalendarurl, response);
       
  2328 		if (retcode == MULTISTATUS)
       
  2329 			{
       
  2330 			RXmlEngDocument document = iDomParser.ParseL(response->Ptr(0));
       
  2331 			CleanupClosePushL(document);
       
  2332 			if (document.NotNull())
       
  2333 				{
       
  2334 				HBufC8* status =
       
  2335 						SearchL(document, KStatus, KNullDesC8).AllocLC();
       
  2336 				status->Des().LowerCase();
       
  2337 				TXmlEngElement calendar;
       
  2338 				SearchL(document, KCalendar, KNullDesC8, calendar);
       
  2339 				// it should be <owner><href>value</href></owner>
       
  2340 				// but oracle beehive server does <owner>value</owner>
       
  2341 				TXmlEngElement owner;
       
  2342 				SearchL(document, KOwner, KNullDesC8, owner);
       
  2343 				TPtrC8 ownerref1 = SearchL(owner, KHref, KNullDesC8);
       
  2344 				TPtrC8 ownerref2 = owner.Value();
       
  2345 				TPtrC8 ownerref;
       
  2346 				ownerref.Set(ownerref1 != KNullDesC8 ? ownerref1 : ownerref2);
       
  2347 
       
  2348 				if (calendar.NotNull() && (ownerref != KNullDesC8) && (*status
       
  2349 						== KHTTP200))
       
  2350 					{
       
  2351 					// this is a calendar collection and we know the principal as well now
       
  2352 					homecalendar = iUrl->AllocL();
       
  2353 					_LIT8(KHTTP,"http");
       
  2354 					HBufC8* http = ownerref.Left(KHTTP().Length()).AllocLC();
       
  2355 					if (*http == KHTTP)
       
  2356 						{
       
  2357 						// sogo server does not return relative, but principal url
       
  2358 						principal = ownerref.AllocL();
       
  2359 						}
       
  2360 					else
       
  2361 						{
       
  2362 						principal = HBufC8::NewL(iBaseUrl->Length()
       
  2363 								+ ownerref.Length());
       
  2364 						principal->Des().Append(*iBaseUrl);
       
  2365 						principal->Des().Append(ownerref);
       
  2366 						}
       
  2367 					CleanupStack::PopAndDestroy(http);
       
  2368 					}
       
  2369 				CleanupStack::PopAndDestroy(status);
       
  2370 				}
       
  2371 			CleanupStack::PopAndDestroy(&document);
       
  2372 			}
       
  2373 
       
  2374 		// if we have principal, ask for home, otherwise see if principal was given in the first place
       
  2375 		if (principal)
       
  2376 			{
       
  2377 			response->Reset();
       
  2378 			TInt retcode =
       
  2379 					iHttp->PropfindL(*principal, KPrincipalurl, response);
       
  2380 			if (retcode == MULTISTATUS)
       
  2381 				{
       
  2382 				FindUrlsL(response->Ptr(0), home, inbox, outbox);
       
  2383 				}
       
  2384 			}
       
  2385 		else
       
  2386 			{
       
  2387 			response->Reset();
       
  2388 			TInt retcode = iHttp->PropfindL(*iUrl, KPrincipalurl, response);
       
  2389 			if (retcode == MULTISTATUS)
       
  2390 				{
       
  2391 				FindUrlsL(response->Ptr(0), home, inbox, outbox);
       
  2392 				}
       
  2393 			}
       
  2394 
       
  2395 		home = CalDavUtils::EnsureSlashL(home);
       
  2396 		inbox = CalDavUtils::EnsureSlashL(inbox);
       
  2397 		outbox = CalDavUtils::EnsureSlashL(outbox);
       
  2398 
       
  2399 		// find out all calendar collections under home
       
  2400 		if (home)
       
  2401 			{
       
  2402 			// TODO: temporary? we already have homecalendar...
       
  2403 			if (!homecalendar)
       
  2404 				{
       
  2405 				homecalendar = FindCalendarCollectionL(*home, aArray);
       
  2406 				}
       
  2407 			}
       
  2408 		else
       
  2409 			{
       
  2410 			// have not found out home nor a groupdav collection, maybe we are home ourselves
       
  2411 			homecalendar = FindCalendarCollectionL(*iUrl, aArray);
       
  2412 			if (homecalendar)
       
  2413 				home = iUrl->AllocL();
       
  2414 			}
       
  2415 
       
  2416 		CleanupStack::PopAndDestroy(response);
       
  2417 		delete principal;
       
  2418 		delete inbox;
       
  2419 		delete outbox;
       
  2420 
       
  2421 		if (home)
       
  2422 			iHome = CalDavUtils::EnsureSlashL(home);
       
  2423 		if (homecalendar)
       
  2424 			{
       
  2425 			delete iUrl;
       
  2426 			iUrl = NULL;
       
  2427 			iUrl = CalDavUtils::EnsureSlashL(homecalendar);
       
  2428 			return KErrNone;
       
  2429 			}
       
  2430 		else
       
  2431 			return KErrArgument;
       
  2432 		}
       
  2433 	return KErrArgument;
       
  2434 	}
       
  2435 
       
  2436 /**
       
  2437  * CCalDavEngine::CalendarName
       
  2438  * get calendar name
       
  2439  */
       
  2440 TPtrC CCalDavEngine::CalendarName() const
       
  2441 	{
       
  2442 	return iCalendar ? *iCalendar : KNullDesC();
       
  2443 	}
       
  2444 
       
  2445 /**
       
  2446  * CCalDavEngine::Home
       
  2447  * get home
       
  2448  */
       
  2449 TPtrC8 CCalDavEngine::Home() const
       
  2450 	{
       
  2451 	return iHome ? *iHome : KNullDesC8();
       
  2452 	}
       
  2453 
       
  2454 /**
       
  2455  * CCalDavEngine::Url
       
  2456  * get url
       
  2457  */
       
  2458 TPtrC8 CCalDavEngine::Url() const
       
  2459 	{
       
  2460 	return iUrl ? *iUrl : KNullDesC8();
       
  2461 	}
       
  2462 
       
  2463 /**
       
  2464  * CCalDavEngine::SetUrlL
       
  2465  * set url
       
  2466  */
       
  2467 void CCalDavEngine::SetUrlL(const TDesC8 &aUrl)
       
  2468 	{
       
  2469 	if (iUrl ? *iUrl != aUrl : ETrue)
       
  2470 		{
       
  2471 		DisableL();
       
  2472 
       
  2473 		if (iUrl)
       
  2474 			{
       
  2475 			delete iUrl;
       
  2476 			iUrl = NULL;
       
  2477 			}
       
  2478 
       
  2479 		iUrl = CalDavUtils::EnsureSlashL(aUrl);
       
  2480 		SetCalendarInfoL(KCaldavUrl, *iUrl);
       
  2481 		}
       
  2482 	}
       
  2483 
       
  2484 /**
       
  2485  * CCalDavEngine::User
       
  2486  * get user
       
  2487  */
       
  2488 TPtrC8 CCalDavEngine::User() const
       
  2489 	{
       
  2490 	return iHttp->User();
       
  2491 	}
       
  2492 
       
  2493 /**
       
  2494  * CCalDavEngine::SetUserL
       
  2495  * set user
       
  2496  */
       
  2497 void CCalDavEngine::SetUserL(const TDesC8 &aUser)
       
  2498 	{
       
  2499 	if (iHttp->User() != aUser)
       
  2500 		{
       
  2501 		DisableL();
       
  2502 		SetCalendarInfoL(KCaldavUser, aUser);
       
  2503 		iHttp->SetUserL(aUser);
       
  2504 		}
       
  2505 	}
       
  2506 
       
  2507 /**
       
  2508  * CCalDavEngine::Password
       
  2509  * get password
       
  2510  */
       
  2511 TPtrC8 CCalDavEngine::Password() const
       
  2512 	{
       
  2513 	return iHttp->Password();
       
  2514 	}
       
  2515 
       
  2516 /**
       
  2517  * CCalDavEngine::SetPasswordL
       
  2518  * set password
       
  2519  */
       
  2520 void CCalDavEngine::SetPasswordL(const TDesC8 &aPassword)
       
  2521 	{
       
  2522 	if (iHttp->Password() != aPassword)
       
  2523 		{
       
  2524 		DisableL();
       
  2525 		iHttp->SetPasswordL(aPassword);
       
  2526 		SetCalendarInfoL(KCaldavPassword, aPassword);
       
  2527 		}
       
  2528 	}
       
  2529 
       
  2530 /**
       
  2531  * CCalDavEngine::SyncInterval
       
  2532  * get SyncInterval
       
  2533  */
       
  2534 TTimeIntervalMinutes CCalDavEngine::SyncInterval() const
       
  2535 	{
       
  2536 	return iSyncInterval;
       
  2537 	}
       
  2538 
       
  2539 /**
       
  2540  * CCalDavEngine::SetSyncIntervalL
       
  2541  * set SetSyncIntervalL
       
  2542  */
       
  2543 void CCalDavEngine::SetSyncIntervalL(TTimeIntervalMinutes aSyncInterval)
       
  2544 	{
       
  2545 	iSyncInterval = aSyncInterval;
       
  2546 	TPckgC<TTimeIntervalMinutes> minutes(iSyncInterval);
       
  2547 	SetCalendarInfoL(KCaldavSyncInterval, minutes);
       
  2548 	}
       
  2549 
       
  2550 /**
       
  2551  * CCalDavEngine::PastDays
       
  2552  * get past days
       
  2553  */
       
  2554 TTimeIntervalDays CCalDavEngine::PastDays() const
       
  2555 	{
       
  2556 	return iPastDays;
       
  2557 	}
       
  2558 
       
  2559 /**
       
  2560  * CCalDavEngine::SetPastDaysL
       
  2561  * Set PastDaysL
       
  2562  */
       
  2563 void CCalDavEngine::SetPastDaysL(TTimeIntervalDays aDays)
       
  2564 	{
       
  2565 	iPastDays = aDays;
       
  2566 	TPckgC<TTimeIntervalDays> days(iPastDays);
       
  2567 	SetCalendarInfoL(KCaldavPastDays, days);
       
  2568 	}
       
  2569 
       
  2570 /**
       
  2571  * CCalDavEngine::ImmediateSync
       
  2572  * get ImmediateSyncL
       
  2573  */
       
  2574 TBool CCalDavEngine::ImmediateSync() const
       
  2575 	{
       
  2576 	return iImmediateSync;
       
  2577 	}
       
  2578 
       
  2579 /**
       
  2580  * CCalDavEngine::SetImmediateSyncL
       
  2581  * Set ImmediateSyncL
       
  2582  */
       
  2583 void CCalDavEngine::SetImmediateSyncL(TBool aImmediateSyc)
       
  2584 	{
       
  2585 	iImmediateSync = aImmediateSyc;
       
  2586 	TPckgC<TBool> immediatesync(iImmediateSync);
       
  2587 	SetCalendarInfoL(KCaldavImmediateSync, immediatesync);
       
  2588 	}
       
  2589 
       
  2590 /**
       
  2591  * CCalDavEngine::KeepServerEntry
       
  2592  * get KeepServerEntryL
       
  2593  */
       
  2594 TBool CCalDavEngine::KeepServerEntry() const
       
  2595 	{
       
  2596 	return iKeepServerEntry;
       
  2597 	}
       
  2598 
       
  2599 /**
       
  2600  * CCalDavEngine::SetKeepServerEntryL
       
  2601  * Set KeepServerEntryL
       
  2602  */
       
  2603 void CCalDavEngine::SetKeepServerEntryL(TBool aKeepServerEntry)
       
  2604 	{
       
  2605 	iKeepServerEntry = aKeepServerEntry;
       
  2606 	TPckgC<TBool> keepserver(iKeepServerEntry);
       
  2607 	SetCalendarInfoL(KCaldavKeepServer, keepserver);
       
  2608 	}
       
  2609 
       
  2610 /**
       
  2611  * CCalDavEngine::Timer
       
  2612  * get timer
       
  2613  */
       
  2614 CPeriodic* CCalDavEngine::Timer()
       
  2615 	{
       
  2616 	return iTimer;
       
  2617 	}