/*
* 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