Catchup.
// fcalendar.cpp
//
// Copyright (c) 2009 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include "caliterator.h"
#include <calsession.h>
#include <calentryview.h>
#include <calentry.h>
#include <calalarm.h>
#include <calrrule.h>
#include <caluser.h>
#include <calprogresscallback.h>
#include <fshell/ioutils.h>
using namespace IoUtils;
// Destroy the RPointerArray
void DestroyCalEntryRPointerArray(TAny* aPtr)
{
RPointerArray<CCalEntry>* self = static_cast<RPointerArray<CCalEntry>*> (aPtr);
self->ResetAndDestroy();
}
enum TCurrentOperation
{
ECONewEntryView,
ECONone
};
class CCmdCalendar : public CCommandBase, public MCalProgressCallBack
{
public:
static CCommandBase* NewLC();
~CCmdCalendar();
private:
CCmdCalendar();
void DoListEntryL();
void DoDeleteEntryL();
void DoAddEntryL();
void DoChangeEntryL();
void ReadCmdLineAmendEntryContentL(CCalEntry& aEntry);
void ListGSDetailL(const TDesC8& aGlobalId, TInt aVerboseLevel);
void PrintEntryDetailL(CCalEntry* aEntry, TInt aVerboseLevel);
void PrintAcceptedOptions();
TInt CheckAlarmAlertServer();
static const TDesC* UidName(TUid aUid);
static const TDesC* EntryMethodToString(CCalEntry::TMethod aEntryMethod);
static const TDesC* EntryStatusToString(CCalEntry::TStatus aEntryStatus);
static const TDesC* EntryTypeToString(CCalEntry::TType aEntryType);
static const TDesC* RepeatTypeToString(TCalRRule::TType aType);
void PrintTime(const TTime& aTime, TBool aNewline);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private: //MCalProgressCallBack
virtual void Progress(TInt aPercentageCompleted);
virtual void Completed(TInt aError);
virtual TBool NotifyProgress();
private:
CActiveSchedulerWait* iActiveWait;
TCurrentOperation iCurOpr;
CCalSession* iCalSes;
CCalEntryView* iEntryView;
RArray<TBool> iVerbose;
HBufC* iOptFileName; //calendar database file full path
TInt iOptLocalId; //local ID
HBufC* iOptGlobalID;
CCalEntry::TType iOptType;
HBufC* iOptSummary;
HBufC* iOptStartTime;
HBufC* iOptEndTime;
enum
{
EListEntry,
EDeleteEntry,
EAddEntry,
EChangeEntry,
} iCommand;
};
CCommandBase* CCmdCalendar::NewLC()
{
CCmdCalendar* self = new(ELeave) CCmdCalendar();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdCalendar::CCmdCalendar()
{
iCurOpr = ECONone;
iActiveWait = new (ELeave) CActiveSchedulerWait;
}
CCmdCalendar::~CCmdCalendar()
{
delete iOptFileName;
delete iOptGlobalID;
delete iOptSummary;
delete iOptStartTime;
delete iOptEndTime;
delete iEntryView;
delete iCalSes;
delete iActiveWait;
iVerbose.Close();
}
//////////////////////////////////////////////////////
//virtual
void CCmdCalendar::Progress(TInt /*aPercentageCompleted*/)
{
;
}
//virtual
void CCmdCalendar::Completed(TInt /*aError*/)
{
TBool bWaitStarted = iActiveWait->IsStarted();
ASSERT(bWaitStarted);
(void)bWaitStarted;
if (iCurOpr == ECONewEntryView)
{
iActiveWait->AsyncStop();
}
iCurOpr = ECONone;
}
TBool CCmdCalendar::NotifyProgress()
{
return ETrue;
}
const TDesC& CCmdCalendar::Name() const
{
_LIT(KName, "fcalendar");
return KName;
}
void CCmdCalendar::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArgCommand, "command");
aArguments.AppendEnumL((TInt&)iCommand, KArgCommand);
}
void CCmdCalendar::OptionsL(RCommandOptionList& aOptions)
{
_LIT(KOptVerbose, "verbose");
aOptions.AppendBoolL(iVerbose, KOptVerbose);
_LIT(KOptFile, "file");
aOptions.AppendStringL(iOptFileName, KOptFile);
_LIT(KOptLocalId, "local_id");
aOptions.AppendUintL((TUint&)iOptLocalId, KOptLocalId);
_LIT(KOptGlobalId, "global_id");
aOptions.AppendStringL(iOptGlobalID, KOptGlobalId);
_LIT(KOptType, "type");
aOptions.AppendEnumL((TInt&)iOptType, KOptType);
_LIT(KOptSummary, "summary");
aOptions.AppendStringL(iOptSummary, KOptSummary);
_LIT(KOptStartTime, "start_time");
aOptions.AppendStringL(iOptStartTime, KOptStartTime);
_LIT(KOptEndTime, "end_time");
aOptions.AppendStringL(iOptEndTime, KOptEndTime);
}
//calendar have dependency on !AlamAlertServer,
//this server is usually part of eikon and not likely to be started separately
//we need to check if this server is up and running,
//if not, no point to contiune
//
//return:
//-1 (KErrNotFound): this server is not running
//0 (KErrNone): OK
TInt CCmdCalendar::CheckAlarmAlertServer()
{
TInt Ret;
TInt Res;
TFindServer findASServer(_L("!AlarmAlertServer"));
TFullName name;
Res = findASServer.Next(name);
if (Res==KErrNotFound )
Ret = KErrNotFound;
else
Ret = KErrNone;
return Ret;
}
void CCmdCalendar::DoRunL()
{
TInt res;
res = CheckAlarmAlertServer();
LeaveIfErr(res, _L("!AlarmAlertServer not running"));
TRAPD(err, iCalSes = CCalSession::NewL() );
LeaveIfErr(err, _L("Could not connect to Calendar server"));
//open the calendar database file
if (iOptFileName && iOptFileName->Length()>0 )
{
Printf(_L("Calendar Database file: %S \r\n"), iOptFileName);
}
else
{
Printf(_L("Calendar Database file unspecified, by default S60 database file is c:Calendar\r\n"));
delete iOptFileName; iOptFileName = NULL;
iOptFileName = HBufC::NewL(128);
*iOptFileName = _L("c:Calendar");
}
//open database file
TRAP(err, iCalSes->OpenL(*iOptFileName) );
LeaveIfErr(err, _L("Could not open database file"));
//Create an entry view
iCurOpr = ECONewEntryView;
TRAP(err, iEntryView = CCalEntryView::NewL(*iCalSes, *this));
LeaveIfErr(err, _L("Could not create entry view"));
//entry view takes a long time to build index, and we must not do anything
//until we received callback, therefore, must wait here.
iActiveWait->Start();
///////////////////////////////////////////////////////////////////////////
switch (iCommand)
{
case EListEntry:
DoListEntryL();
break;
case EDeleteEntry:
DoDeleteEntryL();
break;
case EAddEntry:
DoAddEntryL();
break;
case EChangeEntry:
DoChangeEntryL();
break;
};
}
void CCmdCalendar::DoChangeEntryL()
{
//compulsory: globalid, these can not be changed later
if (!iOptGlobalID || iOptGlobalID->Length()== 0)
LeaveIfErr(KErrArgument, _L("No global id specified. Use -g to specify one"));
//type cannot be changed by calendar API, warning user of this fact
if (iOptions.IsPresent(&iOptType))
{
Printf(_L("Type is not allowed to change, this option (-t) will be ignored.\r\n"));
}
RPointerArray<CCalEntry> CalEntryArray;
CleanupStack::PushL(TCleanupItem(DestroyCalEntryRPointerArray, &CalEntryArray));
TBuf8<128> TmpGlobalId;
TmpGlobalId.Copy(*iOptGlobalID);
HBufC8* pGlobalId = HBufC8::New(128);
CleanupStack::PushL(pGlobalId);
*pGlobalId = TmpGlobalId;
//do an extra check if the same global ID is already used.
iEntryView->FetchL(*pGlobalId, CalEntryArray);
CleanupStack::PopAndDestroy(pGlobalId);
pGlobalId = NULL; //this HBufC is owned by CalEntry
TInt Cnt = CalEntryArray.Count();
if (Cnt == 0)
LeaveIfErr(KErrNotFound, _L("No such Global ID."));
Printf(_L("%d entries found\r\n"), Cnt);
CCalEntry* pEntry = CalEntryArray[0];
//amend necessary calendar entry properties
ReadCmdLineAmendEntryContentL(*pEntry);
TInt SucessfulEntryCnt = 0;
iEntryView->UpdateL(CalEntryArray, SucessfulEntryCnt);
Printf(_L("%d entries changed\r\n"), SucessfulEntryCnt);
CleanupStack::PopAndDestroy();
}
void CCmdCalendar::DoAddEntryL()
{
//compulsory: globalid, type, these can not be changed later
if (!iOptGlobalID || iOptGlobalID->Length()== 0)
LeaveIfErr(KErrArgument, _L("No global id specified. Use -g to specify one"));
if (!iOptions.IsPresent(&iOptType))
LeaveIfErr(KErrArgument, _L("No type specified. Use -t to specify one"));
RPointerArray<CCalEntry> CalEntryArray;
CleanupStack::PushL(TCleanupItem(DestroyCalEntryRPointerArray, &CalEntryArray));
TBuf8<128> TmpGlobalId;
TmpGlobalId.Copy(*iOptGlobalID);
HBufC8* pGlobalId = HBufC8::New(128);
CleanupStack::PushL(pGlobalId);
*pGlobalId = TmpGlobalId;
//do an extra check if the same global ID is already used.
//if yes, then adding with such global id is not allowed
{
iEntryView->FetchL(*pGlobalId, CalEntryArray);
TInt Cnt = CalEntryArray.Count();
if (Cnt > 0)
LeaveIfErr(KErrAlreadyExists, _L("The same Global ID is already used."));
}
CCalEntry* pEntry = CCalEntry::NewL(iOptType, pGlobalId,
CCalEntry::EMethodNone, 0);
CleanupStack::Pop(pGlobalId);
pGlobalId = NULL; //this HBufC is owned by CalEntry
CalEntryArray.Append(pEntry);
//amend necessary calendar entry properties
ReadCmdLineAmendEntryContentL(*pEntry);
TInt SucessfulEntryCnt = 0;
iEntryView->StoreL(CalEntryArray, SucessfulEntryCnt);
Printf(_L("%d entries added\r\n"), SucessfulEntryCnt);
CleanupStack::PopAndDestroy();
}
void CCmdCalendar::DoDeleteEntryL()
{
//TInt VerboseLevel = iVerbose.Count();
if (iOptGlobalID && iOptGlobalID->Length())
{
RPointerArray<CCalEntry> CalEntryArray;
CleanupStack::PushL(TCleanupItem(DestroyCalEntryRPointerArray, &CalEntryArray));
//FetchL is not Async
//and there will be new CCalEntry objects generared
//and pointer stored in CalEntryArray
TBuf8<256> GlobalID;
GlobalID.Copy(*iOptGlobalID);
iEntryView->FetchL(GlobalID, CalEntryArray);
TInt EntryCount = CalEntryArray.Count();
Printf(_L("%d Entries found\r\n"), EntryCount);
for (TInt i=0; i<EntryCount; i++)
{
CCalEntry* pEntry = CalEntryArray[0];
CalEntryArray.Remove(0);
CleanupStack::PushL(pEntry);
iEntryView->DeleteL(*pEntry);
CleanupStack::PopAndDestroy(pEntry);
}
Printf(_L("%d Entries deleted\r\n"), EntryCount);
CleanupStack::PopAndDestroy();
}
else
{
LeaveIfErr(KErrArgument, _L("No global id specified. Use -g to specify one"));
}
}
//list all agenda entry in the agenda server
void CCmdCalendar::DoListEntryL()
{
TInt VerboseLevel = iVerbose.Count();
CCalIter* pIter = CCalIter::NewL(*iCalSes);
CleanupStack::PushL(pIter);
const TDesC8* pGlb = &(pIter->FirstL());
TBuf<128> GlbId;
while(*pGlb != KNullDesC8)
{
GlbId.Copy(*pGlb);
Printf(_L("================================\r\n"));
Printf(_L("Group Scheduling Entry, Global ID: %S\r\n"), &GlbId);
ListGSDetailL(*pGlb, VerboseLevel);
pGlb = &(pIter->NextL());
}
CleanupStack::PopAndDestroy(pIter);
}
//this function read user command line options,
//and amend the corresponding Entry properties
//
void CCmdCalendar::ReadCmdLineAmendEntryContentL(CCalEntry& aEntry)
{
TInt res;
//summary is optional
if (iOptSummary && iOptSummary->Length() > 0)
aEntry.SetSummaryL(*iOptSummary);
TCalTime StartTime = aEntry.StartTimeL();
TCalTime EndTime = aEntry.EndTimeL();
if (iOptStartTime && iOptStartTime->Length() > 0)
{
TTime Tmp(Time::NullTTime());
res = Tmp.Parse(*iOptStartTime);
if (res >= 0)
{
Printf(_L("StartTime recognised as ") );
PrintTime(Tmp, ETrue);
StartTime.SetTimeUtcL(Tmp);
}
else
{
Printf(_L("Start Date/Time format not recogised.\r\n") );
}
}
if (iOptEndTime && iOptEndTime->Length() > 0)
{
TTime Tmp(Time::NullTTime());
res = Tmp.Parse(*iOptEndTime);
if (res >= 0)
{
Printf(_L("EndTime recognised as ") );
PrintTime(Tmp, ETrue);
EndTime.SetTimeUtcL(Tmp);
}
else
{
Printf(_L("End Date/Time format not recogised.\r\n") );
}
}
aEntry.SetStartAndEndTimeL(StartTime, EndTime);
if (iOptLocalId)
{
TCalLocalUid LocalId = (TCalLocalUid) iOptLocalId;
aEntry.SetLocalUidL(LocalId);
}
}
//verbose level
//-v = 1, -vv = 2
//
void CCmdCalendar::ListGSDetailL(const TDesC8& aGlobalId, TInt aVerboseLevel)
{
RPointerArray<CCalEntry> CalEntryArray;
CleanupStack::PushL(TCleanupItem(DestroyCalEntryRPointerArray, &CalEntryArray));
//FetchL is not Async
//and there will be new CCalEntry objects generared
//and pointer stored in CalEntryArray
iEntryView->FetchL(aGlobalId, CalEntryArray);
TInt Count = CalEntryArray.Count();
for (TInt i=0; i<Count; i++)
{
CCalEntry* pCalEntry= CalEntryArray[0];
CalEntryArray.Remove(0);
CleanupStack::PushL(pCalEntry);
//make sure leave does not occur inside this scope,
//or contents in CalEntryArray may not be cleaned
TRAP_IGNORE(PrintEntryDetailL(pCalEntry, aVerboseLevel));
CleanupStack::PopAndDestroy(pCalEntry);
}
CleanupStack::PopAndDestroy();
}
void CCmdCalendar::PrintEntryDetailL(CCalEntry* aEntry, TInt aVerboseLevel)
{
//this matches the Group Scheduling global ID, no need to print it out
//const TDesC8& EntryID = aEntry->UidL();
//for verbose level 0
//entry type, summery, start time, end time, priority
CCalEntry::TType EntryType = aEntry->EntryTypeL();
const TDesC& EntrySummary = aEntry->SummaryL();
TCalTime EntryStartTime = aEntry->StartTimeL();
TCalTime EntryEndTime = aEntry->EndTimeL();
TCalTime EntryCompTime = aEntry->CompletedTimeL();
TCalTime EntryModDate = aEntry->LastModifiedDateL();
TUint EntryPriority = aEntry->PriorityL();
Printf(_L("Type:%S Priority: %u Summary:%S\r\n"),
EntryTypeToString(EntryType), EntryPriority, &EntrySummary);
Printf(_L(" StartTime:"));
PrintTime(EntryStartTime.TimeUtcL(), EFalse);
Printf(_L(" EndTime:"));
PrintTime(EntryEndTime.TimeUtcL(), EFalse);
Printf(_L("\r\n"));
Printf(_L(" CompletedTime:"));
PrintTime(EntryCompTime.TimeUtcL(), EFalse);
Printf(_L(" Last Modified:"));
PrintTime(EntryModDate.TimeUtcL(), EFalse);
Printf(_L("\r\n"));
if (aVerboseLevel < 1)
return;
//local id, location, status, method, description
TCalLocalUid EntryLocalId = aEntry->LocalUidL();
const TDesC& EntryLocation = aEntry->LocationL();
CCalEntry::TStatus EntryStatus = aEntry->StatusL();
CCalEntry::TMethod EntryMethod = aEntry->MethodL();
const TDesC& EntryDesc = aEntry->DescriptionL();
TInt EntrySequenceNo = aEntry->SequenceNumberL();
Printf(_L(" LocalId:%u, SeqNo:%d,Location:%S Description:%S\r\n"),
EntryLocalId, EntrySequenceNo, &EntryLocation, &EntryDesc);
Printf(_L(" Status:%S Method:%S\r\n"),
EntryStatusToString(EntryStatus), EntryMethodToString(EntryMethod));
//alarm
CCalAlarm* pAlarm = aEntry->AlarmL();
TPtrC AlarmYesNo = (pAlarm)?_L("Yes"):_L("No");
Printf(_L(" Alarm: %S "), &AlarmYesNo);
if (pAlarm && aVerboseLevel > 1)
{
CleanupStack::PushL(pAlarm);
const TDesC& AlarmSound = pAlarm->AlarmSoundNameL();
TTimeIntervalMinutes AlarmOffset = pAlarm->TimeOffset();
Printf(_L("AlarmSound:%S, MinutesInAdvance:%d"),
&AlarmSound, AlarmOffset.Int());
//CCalContent is optional, will be included from calalarm if it's present
#ifdef __CALCONTENT_H__
CCalContent* pAlarmContent = pAlarm->AlarmAction();
if (pAlarmContent)
{
const TDesC8& AlarmContent = pAlarmContent->Content();
const TDesC8& AlarmMime = pAlarmContent->MimeType();
Printf(_L8("\r\nAlarmContent:%S, AlarmMime:%S "),
&AlarmContent, &AlarmMime);
}
#endif
CleanupStack::PopAndDestroy(pAlarm);
}
Printf(_L("\r\n"));
//repeat rules
TCalRRule RepeatRule;
TBool bRepeat = aEntry->GetRRuleL(RepeatRule);
TPtrC RepeatYesNo = (bRepeat)?_L("Yes"):_L("No");
Printf(_L(" Repeat: %S "), &RepeatYesNo);
if (bRepeat && aVerboseLevel > 1)
{
TCalRRule::TType RepeatType = RepeatRule.Type();
TInt RepeatInterval = RepeatRule.Interval();
TUint RepeatCount = RepeatRule.Count();
Printf(_L("RepeatType: %S Interval: %d Count:%u\r\n"),
RepeatTypeToString(RepeatType), RepeatInterval, RepeatCount);
TCalTime RepeatStart = RepeatRule.DtStart();
TCalTime RepeatUntil = RepeatRule.Until();
Printf(_L(" RepeatStart:"));
PrintTime(RepeatStart.TimeUtcL(), EFalse);
Printf(_L(" RepeatUntil:"));
PrintTime(RepeatUntil.TimeUtcL(), EFalse);
}
Printf(_L("\r\n"));
//attendee, in most of phone implementation it is not used
RPointerArray<CCalAttendee>& AttendeeArray = aEntry->AttendeesL();
TInt AttendeeCnt = AttendeeArray.Count();
TPtrC AttendeeYesNo = (AttendeeCnt>0)?_L("Yes"):_L("No");
Printf(_L(" Attendee: %S "), &AttendeeYesNo);
if (AttendeeCnt>0 && aVerboseLevel > 1)
{
for (TInt i=0; i<AttendeeCnt; i++)
{
CCalAttendee* pAttendee = AttendeeArray[i];
const TDesC& AttendeeName = pAttendee->CommonName();
Printf(_L("Attendee:%S "), &AttendeeName);
}
}
Printf(_L("\r\n"));
}
//print the accepted options from the command line
void CCmdCalendar::PrintAcceptedOptions()
{
}
void CCmdCalendar::PrintTime(const TTime& aTime, TBool aNewline)
{
TTime NullTime = Time::NullTTime();
if (aTime == NullTime)
{
Printf(_L("(NullTime)"));
}
else
{
_LIT8(KDateTimeFormat, "%d-%02d-%02d %02d:%02d:%02d");
TDateTime dt = aTime.DateTime();
Printf(KDateTimeFormat, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second());
}
if (aNewline) Printf(_L("\r\n"));
}
#define CASE_LIT(x) case x: { _LIT(KName, #x); return &KName; }
const TDesC* CCmdCalendar::RepeatTypeToString(TCalRRule::TType aType)
{
switch(aType)
{
CASE_LIT(TCalRRule::EInvalid)
CASE_LIT(TCalRRule::EDaily)
CASE_LIT(TCalRRule::EWeekly)
CASE_LIT(TCalRRule::EMonthly)
CASE_LIT(TCalRRule::EYearly)
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdCalendar::EntryMethodToString(CCalEntry::TMethod aEntryMethod)
{
switch(aEntryMethod)
{
CASE_LIT(CCalEntry::EMethodNone)
CASE_LIT(CCalEntry::EMethodPublish)
CASE_LIT(CCalEntry::EMethodRequest)
CASE_LIT(CCalEntry::EMethodReply)
CASE_LIT(CCalEntry::EMethodAdd)
CASE_LIT(CCalEntry::EMethodCancel)
CASE_LIT(CCalEntry::EMethodRefresh)
CASE_LIT(CCalEntry::EMethodCounter)
CASE_LIT(CCalEntry::EMethodDeclineCounter)
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdCalendar::EntryStatusToString(CCalEntry::TStatus aEntryStatus)
{
switch(aEntryStatus)
{
CASE_LIT(CCalEntry::ETentative)
CASE_LIT(CCalEntry::EConfirmed)
CASE_LIT(CCalEntry::ECancelled)
CASE_LIT(CCalEntry::ETodoNeedsAction)
CASE_LIT(CCalEntry::ETodoCompleted)
CASE_LIT(CCalEntry::ETodoInProcess)
CASE_LIT(CCalEntry::ENullStatus)
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdCalendar::EntryTypeToString(CCalEntry::TType aEntryType)
{
switch(aEntryType)
{
CASE_LIT(CCalEntry::EAppt)
CASE_LIT(CCalEntry::ETodo)
CASE_LIT(CCalEntry::EEvent)
CASE_LIT(CCalEntry::EReminder)
CASE_LIT(CCalEntry::EAnniv)
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdCalendar::UidName(TUid aUid)
{
switch (aUid.iUid)
{
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
EXE_BOILER_PLATE(CCmdCalendar)