meetingui/meetingrequestviewers/src/CMRCmdHandler.cpp
changeset 0 f979ecb2b13e
--- /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
+