--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingui/meetingrequestviewers/src/CMRCmdHandler.cpp Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,508 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation for meeeting request command handler
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "CMRCmdHandler.h"
+#include "MRHelpers.h"
+#include "MMRModelInterface.h"
+#include "MREntryConsultant.h"
+#include <e32std.h>
+#include <calentry.h> //CCalEntry (Calendar entry API V2)
+#include <caluser.h> //caluser and attendee
+#include "CMRUtilsInternal.h"
+#include <MsgMailUIDs.h> //uid for mail application
+#include "MRViewersPanic.h" //panic codes for meeting request viewers
+#include <mrcommands.hrh> //common constants
+#include <avkon.hrh>
+#include <aknlistquerydialog.h>
+#include <meetingrequestviewersuires.rsg>
+#include <stringloader.h> // StringLoader
+#include <aknnotewrappers.h>
+#include <cmrmailboxutils.h>
+#include <AknGlobalNote.h>
+#include "ICalUILog.h"
+
+// CONSTANTS
+/// Unnamed namespace for local definitions
+namespace {
+
+_LIT( KPanicMsg, "CMRCmdHandler" );
+
+void Panic( TPanicCode aReason )
+ {
+ User::Panic( KPanicMsg, aReason );
+ }
+
+} // namespace
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMRCmdHandler::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMRCmdHandler* CMRCmdHandler::NewL(
+ MMRModelInterface& aModel,
+ const MAgnEntryUi::TAgnEntryUiInParams& aInParams,
+ CMRMailboxUtils& aMRMailboxUtils,
+ CMRUtilsInternal& aMRUtils )
+ {
+
+ LOG("CMRCmdHandler::NewL()");
+
+ CMRCmdHandler* self = new( ELeave ) CMRCmdHandler( aModel,
+ aInParams,
+ aMRMailboxUtils,
+ aMRUtils );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+
+
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CMRCmdHandler::CMRCmdHandler
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMRCmdHandler::CMRCmdHandler(
+ MMRModelInterface& aModel,
+ const MAgnEntryUi::TAgnEntryUiInParams& aInParams,
+ CMRMailboxUtils& aMRMailboxUtils,
+ CMRUtilsInternal& aMRUtils )
+ : iModel( aModel ),
+ iInParams( aInParams ),
+ iMRUtils( aMRUtils ),
+ iMRMailboxUtils( aMRMailboxUtils )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CMRCmdHandler::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMRCmdHandler::ConstructL()
+ {
+ // Memorize original attendee list:
+ RPointerArray<CCalAttendee>& attendees =
+ iModel.CombinedEntry()->AttendeesL();
+ TInt count( 0 );
+ for ( TInt i( 0 ); i < count; ++i )
+ {
+ CCalAttendee* att = MRHelpers::CopyAttendeeLC( *( attendees[i] ) );
+ iOriginalAttendees.AppendL( att ); // ownership transferred
+ CleanupStack::Pop( att );
+ }
+ }
+
+// Destructor
+CMRCmdHandler::~CMRCmdHandler()
+ {
+ iOriginalAttendees.ResetAndDestroy();
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::SaveL
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::SaveL()
+ {
+ CCalEntry& combinedEntry = *( iModel.CombinedEntry() );
+ // we are an organizer and must set protocol fields,
+ // set entry as non-sent -> 2nd parameter == EFalse
+ SetProtocolFieldsL( combinedEntry, EFalse );
+ // save combined entry
+ return iMRUtils.StoreL( combinedEntry, EFalse );
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::SaveFromFileL
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::SaveFromFileL( const RPointerArray<CCalEntry>& aEntries )
+ {
+ TInt retVal( KErrNone );
+ CCalEntry& firstEntry = *( aEntries[0] );
+ TInt count( aEntries.Count() );
+
+ // all entries have the same method
+ if ( iModel.MethodL() == CCalEntry::EMethodReply )
+ {
+ // update first entry and take the result code
+ retVal = iMRUtils.UpdateEntryL( firstEntry );
+ // update also other entries in file, but don't care about the result
+ for ( TInt i( 1 ); i < count; ++i )
+ {
+ iMRUtils.UpdateEntryL( *( aEntries[i] ) );
+ }
+ }
+ else
+ {
+ // save first entry and take the result code
+ retVal = iMRUtils.StoreL( firstEntry, EFalse );
+
+ // save also other entries in file, but don't care about the result
+ for ( TInt i( 1 ); i < count; ++i )
+ {
+ iMRUtils.StoreL( *( aEntries[i] ), EFalse );
+ }
+ }
+ return retVal;
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::SendL
+// Send a request edited by the organizer (in Calendar application)
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::SendL( TInt aSendCmd )
+ {
+ TMsvId boxToUse = MREntryConsultant::SendingMailBoxL( iInParams,
+ iMRMailboxUtils );
+ CCalEntry& combinedEntry = *( iModel.CombinedEntry() );
+
+ TInt retVal( KErrNone );
+
+ if ( combinedEntry.SummaryL().Length() == 0 )
+ { // Confirm that sending is ok although subject is empty
+ CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+ if ( !dlg->ExecuteLD( R_SEND_CONFIRM_NO_SUBJECT ) )
+ {
+ retVal = KErrCancel;
+ }
+ }
+
+ if ( retVal == KErrNone )
+ {
+ // When saving before sending we must update protocol fields and
+ // set 2nd parameter == ETrue
+ SetProtocolFieldsL( combinedEntry, ETrue );
+ MMRUtilsTombsExt::TMRUtilsDbResult dbResult =
+ iMRUtils.StoreL( combinedEntry, EFalse );
+ // Saving may return positive values to report success
+ if ( dbResult >= MMRUtilsTombsExt::EUndefined )
+ {
+ HBufC* note =
+ StringLoader::LoadLC( R_TEXT_CALENDAR_MEETING_REQUEST_SAVED );
+ CAknConfirmationNote* dlg =
+ new( ELeave ) CAknConfirmationNote( ETrue );
+ dlg->ExecuteLD( *note );
+ CleanupStack::PopAndDestroy(); // note
+ }
+ else if ( dbResult != MMRUtilsTombsExt::EErrorIdenticalExists )
+ { // identical exists is not an error in sending scenario
+ retVal = KErrGeneral;
+ }
+ }
+
+ if ( retVal == KErrNone )
+ {
+ iMRUtils.SendWithUiL( combinedEntry, boxToUse );
+
+ if ( aSendCmd == EMRCommandSendUpdate )
+ {
+ // cancellation must be sent to removed attendees
+ CCalEntry* cancel =
+ CreateCancelForRemovedAttendeesL( combinedEntry );
+ if ( cancel )
+ {
+ CleanupStack::PushL( cancel );
+ iMRUtils.SendWithUiL( *cancel, boxToUse );
+ CleanupStack::PopAndDestroy( cancel );
+
+ // since we have now notified removed attendees we should
+ // reset the array (although shouldn't make any difference
+ // in practise)
+ iOriginalAttendees.ResetAndDestroy();
+ }
+ }
+ }
+
+ return retVal;
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::SendL
+// User may edit attendee list multiple times in one ICalUI session,
+// and may also save entry multiple times before sending it, therefore we
+// should collect attendees of an existing entry in the startup phase, and
+// then compare it to the edited list just before sending.
+// ----------------------------------------------------------------------------
+//
+CCalEntry* CMRCmdHandler::CreateCancelForRemovedAttendeesL(
+ const CCalEntry& aEntry ) const
+ {
+ CCalEntry* cancel = NULL;
+
+ RPointerArray<CCalAttendee> removedAttendees; // temporary helper array
+ CleanupClosePushL( removedAttendees ); // doesn't own its items
+ TInt originalCount( iOriginalAttendees.Count() );
+ for ( TInt i( 0 ); i < originalCount; ++i )
+ {
+ CCalAttendee* att = MREntryConsultant::EqualAttendeeL(
+ *( iOriginalAttendees[i] ), aEntry );
+ if ( !att )
+ {
+ removedAttendees.AppendL( iOriginalAttendees[i] );
+ }
+ }
+
+ TInt removedCount( removedAttendees.Count() );
+ if ( removedCount > 0 )
+ {
+ // Create a skeleton for the cancellation, use the same sequence number
+ // as aEntry (the update that was just sent) has
+ cancel = MRHelpers::CopyEntryLC( aEntry,
+ CCalEntry::EMethodCancel,
+ MRHelpers::ECopyOrganizer );
+ for ( TInt j( 0 ); j < removedCount; ++j )
+ {
+ CCalAttendee* attCopy =
+ MRHelpers::CopyAttendeeLC( *( removedAttendees[j] ) );
+ cancel->AddAttendeeL( attCopy );
+ CleanupStack::Pop(); // attCopy, ownership was transferred
+ }
+
+ CleanupStack::Pop( cancel );
+ }
+
+ CleanupStack::PopAndDestroy(); // removedAttendees, just close the array
+
+ return cancel; // may be NULL
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::CancelMRL
+// This method is only used from Calendar application, and in that case we
+// always handle just one entry at a time (entire series or one instance).
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::CancelMRL()
+ {
+ TMsvId boxToUse = MREntryConsultant::SendingMailBoxL( iInParams,
+ iMRMailboxUtils );
+ TInt retVal( KErrNone );
+ CCalEntry* combinedEntry = iModel.CombinedEntry();
+ RPointerArray<CCalEntry> entryArray( 1 );
+ entryArray.AppendL( combinedEntry );
+ CleanupClosePushL( entryArray );
+
+ retVal = iMRUtils.CancelWithUiL( entryArray, boxToUse );
+ CleanupStack::PopAndDestroy(); // entryArray, only close arary
+ return retVal;
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::DeleteMRL
+// This method is only used from Calendar application, and in that case we
+// always handle just one entry at a time (entire series or one instance).
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::DeleteMRL()
+ {
+ TMsvId boxToUse = MREntryConsultant::SendingMailBoxL( iInParams,
+ iMRMailboxUtils );
+ TInt retVal( KErrNone );
+ CCalEntry& combinedEntry = *( iModel.CombinedEntry() );
+ retVal = iMRUtils.DeleteWithUiL( combinedEntry, boxToUse );
+ return retVal;
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::CreateReplyL
+// ----------------------------------------------------------------------------
+//
+void CMRCmdHandler::CreateReplyL( TInt aReplyType )
+ {
+ __ASSERT_DEBUG( iInParams.iMessageId != KMsvNullIndexEntryId,
+ Panic( ETMsvIDNull ) );
+
+ CCalEntry& combinedEntry = *( iModel.CombinedEntry() );
+
+ CMRUtilsInternal::TMailRecipients aRecipients( CMRUtilsInternal::EAll );
+
+ switch( aReplyType )
+ {
+ case EMRCommandReplyToSender:
+ {
+ aRecipients = CMRUtilsInternal::ESender;
+ break;
+ }
+ case EMRCommandReplyToOrganiser:
+ {
+ aRecipients = CMRUtilsInternal::EOrganizer;
+ break;
+ }
+ case EMRCommandReplyToAll:
+ {
+ aRecipients = CMRUtilsInternal::EAll;
+ break;
+ }
+ }
+
+ HBufC* senderAddr = MRHelpers::SenderAddressLC(
+ *( iInParams.iMsgSession ),
+ iInParams.iMessageId,
+ EFalse );
+ TMsvId boxToUse = MREntryConsultant::SendingMailBoxL( iInParams,
+ iMRMailboxUtils );
+ iMRUtils.ReplyToL( aRecipients, combinedEntry, *senderAddr, boxToUse );
+ CleanupStack::PopAndDestroy( senderAddr );
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::RemoveFromCalendarL
+//
+// ----------------------------------------------------------------------------
+//
+void CMRCmdHandler::RemoveFromCalendarL(
+ const RPointerArray<CCalEntry>& aEntries )
+ {
+ CCalEntry& firstEntry = *( aEntries[0] );
+ if ( MREntryConsultant::IsModifyingEntryL( firstEntry ) )
+ { // if entry at index 0 is modifying entry, then all entries are,
+ // that means that we remove each of them but originating remains,
+ // this branch is probably rarely, if ever, used in real life
+ TInt count( aEntries.Count() );
+ for ( TInt i( 0 ); i < count; ++i )
+ {
+ iMRUtils.DeleteL( *( aEntries[i] ) );
+ }
+ }
+ else
+ { // entry at index 0 is originating, all entries for this meeting
+ // will get deleted, this is the usual case
+ iMRUtils.DeleteL( firstEntry );
+ }
+
+ HBufC* removeNote = StringLoader::LoadL( R_QTN_CALE_NOTE_MEETING_REMOVED );
+ CleanupStack::PushL( removeNote );
+ CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
+ globalNote->ShowNoteL( EAknGlobalInformationNote, *removeNote );
+ CleanupStack::PopAndDestroy( globalNote );
+ CleanupStack::PopAndDestroy( removeNote );
+ }
+
+// ----------------------------------------------------------------------------
+// CMRCmdHandler::CreateResponseL
+// This method may be called also from mail or BVA, and in that case we may
+// have to deal with an array of entries.
+// ----------------------------------------------------------------------------
+//
+TInt CMRCmdHandler::CreateResponseL(
+ const RPointerArray<CCalEntry>& aEntries,
+ TInt aResponseCmd )
+ {
+ CCalAttendee::TCalStatus status( CCalAttendee::ENeedsAction );
+ switch ( aResponseCmd )
+ {
+ case EMRCommandRespondAccept:
+ {
+ status = CCalAttendee::EAccepted;
+ break;
+ }
+ case EMRCommandRespondTentative:
+ {
+ status = CCalAttendee::ETentative;
+ break;
+ }
+ case EMRCommandRespondDecline:
+ {
+ status = CCalAttendee::EDeclined;
+ break;
+ }
+ default:
+ {
+ User::Leave( KErrNotSupported );
+ break;
+ }
+ }
+ // TODO: Currently we are sending MR response via the mailbox which is stored
+ // in cenrep settings, but it has been discussed that actually we should send
+ // via the mailbox that is associated with ThisAttendeeL() email address.
+ TMsvId boxToUse = MREntryConsultant::SendingMailBoxL( iInParams,
+ iMRMailboxUtils );
+ return iMRUtils.RespondWithUiL( aEntries, status, boxToUse );
+ }
+
+void CMRCmdHandler::DisableAlarmL(
+ const RPointerArray<CCalEntry>& aEntries )
+ {
+ TInt count( aEntries.Count() );
+ for ( TInt i( 0 ); i < count; ++i )
+ {
+ CCalEntry& entry = *( aEntries[i] );
+ CCalEntry* dBEntry = iMRUtils.FetchEntryL( entry.UidL(),
+ entry.RecurrenceIdL() );
+ if ( dBEntry )
+ {
+ CleanupStack::PushL( dBEntry );
+ dBEntry->SetAlarmL( NULL );
+ iMRUtils.UpdateEntryL( *dBEntry );
+ CleanupStack::PopAndDestroy( dBEntry );
+ }
+ }
+ }
+
+// this method may be moved to some other class if other classes than
+// just CmdHandler need to use it.
+void CMRCmdHandler::SetProtocolFieldsL(
+ CCalEntry& aEntry,
+ TBool aWillBeSentNow ) const
+ {
+ __ASSERT_DEBUG( iMRMailboxUtils.IsOrganizerL( aEntry ),
+ Panic( ENonOrganizerSettingProtocolFields ) );
+
+ // TODO: set seq number, do we need to compare entry to db entry and
+ // what fields have changed and what type of entry it is?
+
+ // Store information whether this request / this particular entry
+ // will be sent now or just saved.
+
+ if ( aWillBeSentNow )
+ { // TODO: this will be done differently when Symbian supports other fields
+ // to indicate sending status
+ TTime currentTime;
+ currentTime.UniversalTime();
+ TCalTime dtstamp;
+ dtstamp.SetTimeUtcL( currentTime );
+ aEntry.SetDTStampL( dtstamp );
+ if ( aEntry.StatusL() == CCalEntry::ENullStatus )
+ { // If entry has had ENullStatus, we use now EConfirmed
+ // as a stamp to mark that entry has been sent at least once.
+ aEntry.SetStatusL( CCalEntry::EConfirmed );
+ }
+ }
+ else
+ {
+ TCalTime dtstamp; // initialized to null time
+ aEntry.SetDTStampL( dtstamp );
+ }
+ }
+
+// End of File
+