/*
* Copyright (c) 2003 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: This module contains the implementation of CCbsDbImpTopicMessages class
* member functions.
*
*/
// INCLUDE FILES
#include <e32svr.h>
#include <shareddataclient.h>
#include "CbsServerPanic.h"
#include "CbsStreamHelper.h"
#include "CbsUtils.h"
#include "CbsDbConstants.h"
#include "CCbsDbImpTopicList.h"
#include "CCbsDbImpTopicMessages.h"
#include "CCbsRecEtel.h"
#include "CCbsReceiverHelper.h"
#include "CbsLogger.h"
// CONSTANTS
// Expected maximum number of locked messages at once.
const TInt KDefaultSpaceForLockedMessages = 1;
// CB message header size in bytes.
const TInt KCbMessageHeaderSize = 16;
// The space used for the header of messages stream
const TInt KMessageRootStreamSize = 6;
/// The space used by one message in the messages stream
const TInt KMessageEntrySize = 3;
// Default space reserved for topic messages in message stream
const TInt KDefaultSpaceForMessages = 6;
// Space for reading messages
const TInt KReadMessageSize = 92;
// ================= MEMBER FUNCTIONS =======================
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::CCbsDbImpTopicMessages
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CCbsDbImpTopicMessages::CCbsDbImpTopicMessages(
CCbsDbImpTopicList& aTopicList,
RFs& aFs )
:iTopicList( aTopicList ),
iCacheValid( EFalse ),
iCachedTopicNumber( 0 ),
iFs( aFs )
{
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::ConstructL()
{
// Allocate the default size for the message list.
iMessageList =
new ( ELeave ) CArrayFixFlat< TCbsDbImpTopicMessagesCacheItem >
( KCbsDbMaxReceivedMessages + KCbsDbMaxSavedMessages );
// Allocate the array for locked messages.
iLockedMessages = new ( ELeave ) CArrayFixFlat< TCbsDbMessageHandle >
( KDefaultSpaceForLockedMessages );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CCbsDbImpTopicMessages* CCbsDbImpTopicMessages::NewL(
CCbsDbImpTopicList& aTopicList, RFs& aFs )
{
CCbsDbImpTopicMessages* self =
new ( ELeave ) CCbsDbImpTopicMessages( aTopicList, aFs );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop();
return self;
}
// Destructor
CCbsDbImpTopicMessages::~CCbsDbImpTopicMessages()
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::~CCbsDbImpTopicMessages()");
// Invalidate cache.
InvalidateCache();
// And then delete the message list.
delete iMessageList;
// Delete locked messages.
delete iLockedMessages;
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::~CCbsDbImpTopicMessages()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::InvalidateCache
// Resets the cache to default values.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::InvalidateCache()
{
// Initialize members back to default.
iCacheValid = EFalse;
iCachedTopicNumber = 0;
// Resize the message list. After the call is made, the
// array is empty.
if ( iMessageList )
{
iMessageList->Reset();
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::InvalidateCacheIfTopic
// Resets the cache to default values.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::InvalidateCacheIfTopic(
const TCbsDbTopicNumber& aNumber )
{
// Check the handle and then invalidate
if ( iCachedTopicNumber == aNumber )
{
InvalidateCache();
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::CreateDefaultTopicMessagesStreamL
// Creates a default topic messages stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TStreamId CCbsDbImpTopicMessages::CreateDefaultTopicMessagesStreamL(
CStreamStore& aStore )
{
// Create the stream.
RStoreWriteStream outstream;
TStreamId id = outstream.CreateLC( aStore ); // on CS
// Write total amount of messages.
outstream.WriteInt16L( 0 );
// Write total amount of space for messages.
outstream.WriteInt16L( KDefaultSpaceForMessages );
for ( TInt index( 0 ); index < KDefaultSpaceForMessages; index++ )
{
// "Saved"-flag
CbsStreamHelper::WriteBoolL( outstream, EFalse );
// Write message stream id.
outstream << TStreamId( 0 );
}
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
return id;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::CreateDefaultTopicMessagesStreamL
// Delete all topics messages.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DeleteAllTopicMessagesL(
CStreamStore& aSavedStore,
CStreamStore& aUnsavedStore,
RReadStream& aIn )
{
// Read total amount of messages.
TInt total( aIn.ReadInt16L() );
// Skip space for messages.
aIn.ReadInt16L();
// Now, delete all streams..
for ( TInt index( 0 ); index < total; index++ )
{
TBool isSaved( CbsStreamHelper::ReadBoolL( aIn ) );
TStreamId id;
// Read stream id.
aIn >> id;
CStreamStore& store = isSaved ? aSavedStore : aUnsavedStore;
store.DeleteL( id );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::IsLockedMessagesInTopic
// Determines whether or not there are any locked messages in
// the topic.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCbsDbImpTopicMessages::IsLockedMessagesInTopic(
const TCbsDbTopicNumber& aNumber ) const
{
TBool result( EFalse );
// Checks whether or not there is a locked message in the topic.
TInt count( iLockedMessages->Count() );
for ( TInt index( 0 ); index < count; index++ )
{
if ( iTopicList.ExtractTopicNumber(
iLockedMessages->At( index ) ) == aNumber )
{
result = ETrue;
}
}
return result;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::IsLockedMessages
// Determines whether there is at least one locked message.
// Returns ETrue, if there are any locked messages in the
// database.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCbsDbImpTopicMessages::IsLockedMessages() const
{
return ( iLockedMessages->Count() > 0 );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::GetMessageCountL
// Returns the total amount of messages the topic contains.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::GetMessageCountL(
const TCbsDbTopicNumber& aNumber,
TInt& aCount )
{
// Load cache.
LoadCacheL( aNumber );
// and then get the message count.
aCount = iMessageList->Count();
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::GetMessageL
// Returns message information.
// Returns the message matching the given
// index value. Leaves if the index is not valid.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::GetMessageL(
const TCbsDbTopicNumber& aNumber,
TInt aIndex,
TCbsDbMessage& aMessage )
{
// Load the cache.
LoadCacheL( aNumber );
// Check if the index is not valid.
if ( ( aIndex < 0 ) || ( aIndex >= iMessageList->Count() ) )
{
User::Leave( KErrNotFound );
}
// Load the message.
LoadMessageL( aIndex, aMessage );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::FindMessageByHandleL
// Finds the message for given handle and returns it.
// Returns the message matching the given
// index value.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::FindMessageByHandleL(
const TCbsDbMessageHandle& aHandle,
TCbsDbMessage& aMessage )
{
// Load cache
LoadCacheL( iTopicList.ExtractTopicNumber( aHandle ) );
// Load message
LoadMessageL( FindMessagePositionByHandleL( aHandle ), aMessage );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::GetMessageContentsL
// Returns the contents of a message.
// Stores the contents of the message to the buffer aContents.
// If aContents is too small to contain the whole message
// body, the message body is truncated.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::GetMessageContentsL(
const TCbsDbMessageHandle& aHandle,
TPtr& aContents,
TUint aSize )
{
LoadCacheL( iTopicList.ExtractTopicNumber( aHandle ) );
TInt position( FindMessagePositionByHandleL( aHandle ) );
TCbsDbMessage message;
LoadMessageL( position, message );
LoadMessageContentsL( iMessageList->At( position ).iContentsId,
aContents, message.iPermanent, aSize );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DeleteMessageL
// Deletes a message. Leaves if the message is protected
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DeleteMessageL(
const TCbsDbMessageHandle& aHandle,
const CCbsRecEtel& aReceiver )
{
// Get the topic handle.
LoadCacheL( iTopicList.ExtractTopicNumber( aHandle ) );
// Check if the message is locked.
if ( IsMessageLocked( aHandle ) )
{
// Yes, leave.
User::Leave( KErrAccessDenied );
}
else
{
// Otherwise, delete.
TRAPD( error, DoDeleteMessageL(
FindMessagePositionByHandleL( aHandle ) ) );
if ( error != KErrNone )
{
// Failed.
RevertFileOperationL( error );
}
else
{
// Update the soft notification dialog, if topic is hotmarked
UpdateSoftNotificationL( aHandle, aReceiver );
}
}
iTopicList.NotifyTopicModifiedL(
iTopicList.ExtractTopicNumber( aHandle ) );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::AddMessageL
// Creates a new message to the topic.
// Stores a handle to the message in aHandle.
// FFS critical level check is made prior to operation.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::AddMessageL(
const TCbsDbTopicNumber& aNumber,
TCbsDbMessage& aMessage,
const TPtrC& aContents )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::AddMessageL()");
LoadCacheL( aNumber );
aMessage.iLength = aContents.Length();
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::AddMessageL(): Content length: %d.", aMessage.iLength );
// Generate a new message handle.
aMessage.iHandle = GenerateNewMessageHandle( aNumber );
// Make sure that the message is not inserted as permanent
aMessage.iPermanent = EFalse;
TRAPD( error, DoAddMessageL( aMessage, aContents ) );
if ( error != KErrNone )
{
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::AddMessageL(): DoAddMessageL() failed, error: %d.", error );
// Failed.
RevertFileOperationL( error );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::AddMessageL(): RevertFileOperationL() finished OK." );
}
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::AddMessageL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::SaveMessageL
// Saves a message.
// This operation is called "keeping" in the UI.
// The CBS server has a global limit for saved
// messages. The function leaves, if this is exceeded.
// A saved message has it's permanent-flag raised.
// FFS critical level check is made prior to the operation.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::SaveMessageL(
const TCbsDbMessageHandle& aHandle,
const CCbsRecEtel& aReceiver )
{
// Load cache.
TCbsTopicNumber topicNumber( iTopicList.ExtractTopicNumber( aHandle ) );
LoadCacheL( topicNumber );
// Now find message by handle.
TInt position( FindMessagePositionByHandleL( aHandle ) );
TCbsDbMessage message;
LoadMessageL( position, message );
TStreamId contentsId( iMessageList->At( position ).iContentsId );
// This function should not be called if the message is already permanent.
if ( message.iPermanent )
{
User::Leave( KErrAlreadyExists );
}
// Check that the limit for maximum saved messages/topic is not exceeded.
TCbsDbTopic topic;
iTopicList.FindTopicByNumberL( topicNumber, topic );
if ( iTopicList.TotalSavedMessages() >= KCbsDbMaxSavedMessages )
{
User::Leave( KErrOverflow );
}
// FFS critical level check (header is 16 bytes, message coded in Unicode)
CbsUtils::FFSCriticalLevelCheckL( KCbMessageHeaderSize +
2 * message.iLength, iFs );
// Create a temporary buffer for message body and load the contents into
// the buffer.
HBufC* buffer = HBufC::NewLC( message.iLength ); // on CS
TPtr contentPtr( buffer->Des() );
LoadMessageContentsL( contentsId, contentPtr, EFalse, message.iLength );
// Delete message's previous header and body streams.
TCbsDbImpTopicMessagesCacheItem item( iMessageList->At( position ) );
TRAPD( result, DoSaveMessageL( message, item, contentPtr, position ) );
CleanupStack::PopAndDestroy( buffer );
if ( result != KErrNone )
{
RevertFileOperationL( result );
}
else
{
iTopicList.NotifyTopicModifiedL(
iTopicList.ExtractTopicNumber( aHandle ) );
// Update the soft notification dialog, if topic is hotmarked
UpdateSoftNotificationL( aHandle, aReceiver );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoSaveMessageL
// Saves a message.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoSaveMessageL(
TCbsDbMessage& aMessage,
const TCbsDbImpTopicMessagesCacheItem& aItem,
const TDesC& aContentPtr,
TInt aPosition )
{
CFileStore* store = iTopicList.UnsavedMessagesStore();
store->Delete( aItem.iId );
store->Delete( aItem.iContentsId );
TBool needToUpdateReadCounter( EFalse );
aMessage.iPermanent = ETrue;
if ( !aMessage.iRead )
{
needToUpdateReadCounter = ETrue;
aMessage.iRead = ETrue;
}
// Create new streams for message header and body.
TStreamId contentsStream( CreateMessageContentsStreamL(
*iTopicList.TopicStoreL(), aContentPtr ) );
TStreamId messageStream( CreateMessageStreamL(
*iTopicList.TopicStoreL(), aMessage, contentsStream ) );
// Update message's cache item information.
TCbsDbImpTopicMessagesCacheItem& item = iMessageList->At( aPosition );
item.iContentsId = contentsStream;
item.iId = messageStream;
item.iIsSaved = ETrue;
item.iMessage = aMessage;
// Update topic messages stream; the cache item is saved into the stream.
UpdateTopicMessagesStreamL( EFalse );
iTopicList.InformMessageSavedL( aMessage.iHandle );
if ( needToUpdateReadCounter )
{
iTopicList.InformUnreadMessageReadL( aMessage.iHandle );
}
// Commit changes to both files.
iTopicList.CommitFilesL();
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::ReadMessageL
// Marks the message read
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::ReadMessageL(
const TCbsDbMessageHandle& aHandle,
const CCbsRecEtel& aReceiver )
{
//Checked that there is space for writing data on FFS.
CbsUtils::FFSCriticalLevelCheckL( KReadMessageSize, iFs );
// Load cache.
TCbsDbTopicNumber topicNum( iTopicList.ExtractTopicNumber( aHandle ) );
LoadCacheL( topicNum );
// Now find message by handle.
TInt position( FindMessagePositionByHandleL( aHandle ) );
TCbsDbMessage message;
LoadMessageL( position, message );
TStreamId contentsId( iMessageList->At( position ).iContentsId );
TStreamId id( iMessageList->At( position ).iId );
// Check if the message is already read, then there is nothing more to do.
if ( !message.iRead )
{
message.iRead = ETrue;
TRAPD( error, DoReadMessageL( id, message, contentsId ) );
if ( error == KErrNone )
{
iMessageList->At( position ).iMessage = message;
iTopicList.NotifyTopicModifiedL(
iTopicList.ExtractTopicNumber( aHandle ) );
// Update the soft notification dialog, if topic is hotmarked
UpdateSoftNotificationL( aHandle, aReceiver );
}
else
{
RevertFileOperationL( error );
}
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::UpdateHandlesOfTopicMessagesL
// Updates handles of messages in the topic with the number given in
// aOldTopicNumber to match new topic number.
// Traverses through the given topic processing
// each message stream encountered. Since the topic number is
// the primary key and previous message handles can be assumed
// to be unique, updating the high word of the handle to
// match the new topic number is adequate.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::UpdateHandlesOfTopicMessagesL(
const TCbsDbTopicNumber& aOldTopicNumber,
const TCbsDbTopicNumber& aNewTopicNumber )
{
LoadCacheL( aOldTopicNumber );
TInt msgs( iMessageList->Count() );
for ( TInt i( 0 ); i < msgs; i++ )
{
// Fetch message at this position
TCbsDbMessage message;
LoadMessageL( i, message );
TStreamId contentsStreamId( iMessageList->At( i ).iContentsId );
TStreamId messageStreamId( iMessageList->At( i ).iId );
// Insert new topic number as the high word of the handle
message.iHandle = ( aNewTopicNumber << 16 ) |
( message.iHandle & 0xFFFF );
DoUpdateMessageL( messageStreamId, message, contentsStreamId );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::LockMessageL
// Unlocks one message and then locks another message.
// Message that is locked can not be removed. Topic that
// contains a locked message can not be removed.
// Note that locking status is not persistent in the sense that
// when the power is switched off and turned on, no messages
// are automatically locked.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::LockMessageL(
const TCbsDbMessageHandle& aUnlock,
const TCbsDbMessageHandle& aLock )
{
// Check if the message exists: leave if not found, ignore return value
if ( aLock != 0 )
{
TCbsDbMessage message;
TInt position( FindMessagePositionByHandleL( aLock ) );
LoadMessageL( position, message );
}
TBool unlockNull( ETrue );
if ( aUnlock != 0 )
{
DeleteFromLocked( aUnlock );
unlockNull = EFalse;
}
if ( aLock != 0 )
{
InsertToLockedL( aLock ) ;
}
if ( unlockNull == EFalse )
{
LoadCacheL( iTopicList.ExtractTopicNumber( aUnlock ) );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::GetNextAndPrevMsgHandleL
// Returns the handles of the next and previous message
// when given a current message.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::GetNextAndPrevMsgHandleL(
const TCbsDbMessageHandle& aCurrentMsg,
TCbsDbMessageHandle& aNextMsg,
TCbsDbMessageHandle& aPrevMsg,
TInt& aPosition)
{
LoadCacheL( iTopicList.ExtractTopicNumber( aCurrentMsg ) );
// Load the current message
TInt index( FindMessagePositionByHandleL( aCurrentMsg ) );
// Reset position indications
aPosition = 0;
// Retrieve position indications and message handles
if ( index == 0 )
{
aPosition |= ECbsHead;
}
else
{
TCbsDbMessage prevMessage;
LoadMessageL( index - 1, prevMessage );
aPrevMsg = prevMessage.iHandle;
}
// If index points to the last element of iMessageList,
// raise flag ECbsTail.
if ( index == iMessageList->Count()-1 )
{
aPosition |= ECbsTail;
}
else
{
TCbsDbMessage nextMessage;
LoadMessageL( index+1, nextMessage );
aNextMsg = nextMessage.iHandle;
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoAddMessageL
// Inserts a message into the database.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoAddMessageL(
TCbsDbMessage& aMessage,
const TDesC& aContents )
{
// Cache is assumed to be loaded. Message is assumed not to
// already exist in the DB.
CFileStore* store = aMessage.iPermanent ?
iTopicList.TopicStoreL() : iTopicList.UnsavedMessagesStore();
if ( aMessage.iPermanent )
{
// About to write to FFS: make critical level check.
// Message is in Unicode characters, so its size
// is double the length.
CbsUtils::FFSCriticalLevelCheckL( KCbMessageHeaderSize +
2 * aMessage.iLength, iFs );
}
else
{
CbsUtils::VolumeCriticalLevelCheckL(
iTopicList.UnsavedMessagesFilename(),
KCbMessageHeaderSize + 2 * aMessage.iLength, iFs );
}
// Create stream for contents.
TStreamId contentsStream( CreateMessageContentsStreamL(
*store, aContents ) );
// Now we have to find the position to which the message should be
// inserted.
TInt positionToBeInserted( -1 );
TTime messageTime( aMessage.iDateTime );
TInt index( 0 );
// Go through all messages in topic and find the position.
TInt count( iMessageList->Count() );
for ( ; index < count && positionToBeInserted == -1; index++ )
{
TCbsDbMessage message;
LoadMessageL( index, message );
TTime tmp( message.iDateTime );
if ( tmp <= messageTime )
{
positionToBeInserted = index;
}
}
// If we looped through, append
if ( positionToBeInserted == -1 )
{
positionToBeInserted = index;
}
// Create message stream.
TStreamId messageStream( CreateMessageStreamL( *store,
aMessage, contentsStream ) );
// Add to internal cache.
TCbsDbImpTopicMessagesCacheItem item;
item.iId = messageStream;
item.iIsMessage = EFalse;
item.iIsSaved = aMessage.iPermanent;
iMessageList->InsertL( positionToBeInserted, item );
// Check if message should be deleted.
DeleteReceivedIfNecessaryL();
// Update topic messages stream.
UpdateTopicMessagesStreamL( EFalse );
// Update counters.
iTopicList.InformNewMessageReceivedL( aMessage.iHandle );
// Commit changes to both stores.
iTopicList.CommitFilesL();
// Inform observers. Done after commit to make sure there's
// a message to inform of.
iTopicList.NotifyNewMessageArrivedL( aMessage.iHandle );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoDeleteMessageL
// Deletes a message from the database.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoDeleteMessageL(
TInt aPosition )
{
TCbsDbMessage message;
LoadMessageL( aPosition, message );
// Delete the message, if it is possible.
DeleteMessageByPositionL( aPosition );
DeleteReceivedIfNecessaryL();
UpdateTopicMessagesStreamL( ETrue );
// Inform the topic list about deletion.
iTopicList.InformMessageDeletedL( message.iHandle,
message.iPermanent, message.iRead );
iTopicList.CommitFilesL();
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoUpdateMessageL
// Updates the information for a message.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoUpdateMessageL(
const TStreamId& aId,
const TCbsDbMessage& aMessage,
const TStreamId& aContentsId ) const
{
// Update the stream contents.
CFileStore* store = aMessage.iPermanent ?
iTopicList.TopicStoreL() : iTopicList.UnsavedMessagesStore();
RStoreWriteStream outstream;
outstream.ReplaceLC( *store, aId ); // on CS
WriteMessageInformationL( outstream, aMessage, aContentsId );
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoReadMessageL
// Marks a message read by updating it in the database.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoReadMessageL(
const TStreamId& aId,
const TCbsDbMessage& aMessage,
const TStreamId& aContentsId )
{
DoUpdateMessageL( aId, aMessage, aContentsId );
iTopicList.InformUnreadMessageReadL( aMessage.iHandle );
iTopicList.CommitFilesL();
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DoDeleteL
// Deletes messages that are not supposed to be in the topic.
// Because of message locking it is possible that there are more
// received messages than there should be. This method tries to
// delete this kind of message.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DoDeleteL()
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::DoDeleteL()");
// Delete temporary messages and update topic messages stream.
if ( DeleteReceivedIfNecessaryL() )
{
UpdateTopicMessagesStreamL( ETrue );
}
iTopicList.CommitFilesL();
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::DoDeleteL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::FindMessageByKeyL
// Returns a handle to a message with the given key.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCbsDbImpTopicMessages::FindMessageByKeyL(
TCbsDbTopicNumber aNumber,
TCbsDbMessageKey aKey,
TCbsDbMessage& aMessage )
{
TCbsDbMessage message;
TInt count;
TBool result( KErrNotFound );
// Find a message even if the update numbers don't match
aKey &= 0xfff0;
// Try to find a message with the same key in the topic.
LoadCacheL( aNumber );
GetMessageCountL( aNumber, count );
for ( TInt index( 0 ); ( index < count ) && ( result != KErrNone ); index++ )
{
LoadMessageL( index, message );
if ( (message.iKey & 0xfff0) == aKey )
{
aMessage = message;
result = KErrNone; // message was found
}
}
return result;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::FindMessagePositionByHandleL
// Returns the position of a message with the given handle.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCbsDbImpTopicMessages::FindMessagePositionByHandleL(
const TCbsDbMessageHandle& aHandle )
{
// Load the cache.
LoadCacheL( iTopicList.ExtractTopicNumber( aHandle ) );
// Now, find the message
TInt count( iMessageList->Count() );
TCbsDbMessage message;
TBool found( EFalse );
// Go through messages.
TInt index( 0 );
for ( ; ( index < count ) && !found; )
{
// Load the message.
LoadMessageL( index, message );
// Check if it is this one.
if ( message.iHandle == aHandle )
{
found = ETrue;
}
else
{
index++;
}
}
if ( !found )
{
User::Leave( KErrNotFound );
}
return index;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::LoadCacheL
// Loads the cache, if it is not already loaded with this topic information.
// The method does not load any message information to the cache
// - only what is really necessary.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::LoadCacheL(
const TCbsDbTopicNumber& aNumber )
{
CBSLOGSTRING2("CBSSERVER: >>> CCbsDbImpTopicMessages::LoadCacheL(), topic number: %d.", aNumber );
// Check if the cache is valid. If not, load it.
if ( !( iCacheValid && ( iCachedTopicNumber == aNumber ) ) )
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::LoadCacheL(): Calling InvalidateCache()...");
// Invalidate the old cache, if it is necessary.
InvalidateCache();
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::LoadCacheL(): InvalidateCache() called OK.");
// Load message queue ids.
TStreamId id;
iTopicList.GetTopicMessagesIdL( aNumber, id );
ReadTopicMessagesCacheItemsL( *iTopicList.TopicStoreL(),
id, *iMessageList, iSpaceForMessages );
// Cache is valid.
iCachedTopicNumber = aNumber;
iCacheValid = ETrue;
// Check if it there are more topics than there should be.
TCbsDbTopic topic;
iTopicList.FindTopicByNumberL( aNumber, topic );
if ( ( iMessageList->Count() - topic.iSavedMessages ) >
KCbsDbMaxReceivedMessages )
{
TRAPD( error, DoDeleteL() );
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::LoadCacheL(): DoDeleteL() finished with %d.", error );
if ( error != KErrNone )
{
RevertFileOperationL( error );
}
}
}
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::LoadCacheL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::LoadMessageL
// Loads the message header to the cache.
// Note that it is assumed that the index is in proper range and
// the cache is already loaded.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::LoadMessageL(
TInt aIndex,
TCbsDbMessage& aMessage )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::LoadMessageL()");
// Check that the aIndex is in proper range and.
// that the cache is valid (just for sure).
if ( aIndex < 0 || aIndex >= iMessageList->Count() ||
!iCacheValid )
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::LoadMessageL(): Leaving with KErrNotFound...");
User::Leave( KErrNotFound );
}
// Check if the message information is already loaded.
if ( iMessageList->At( aIndex ).iIsMessage )
{
// Yes, just make a fast copy.
aMessage = iMessageList->At( aIndex ).iMessage;
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::LoadMessageL(): Msg already loaded, fast copy made.");
}
else
{
TStreamId id( TStreamId( 0 ) );
// Choose the file store: saved messages are stored elsewhere
// than other messages.
CFileStore* store = iMessageList->At( aIndex ).iIsSaved ?
iTopicList.TopicStoreL() :
iTopicList.UnsavedMessagesStore();
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::LoadMessageL(): Store created.");
// Then read the message. If the message stream cannot be
// found, delete the reference to the message
TRAPD( error, ReadMessageInformationL( *store,
iMessageList->At( aIndex ).iId, aMessage, id ) );
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::LoadMessageL(): ReadMessageInformationL() finished with %d.", error );
if( error == KErrNotFound )
{
DeleteMessageByPositionL( aIndex );
UpdateTopicMessagesStreamL( ETrue );
iTopicList.CommitFilesL();
}
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::LoadMessageL(): Leaving if error code < 0: error %d...", error );
User::LeaveIfError( error );
// And copy to the internal cache.
iMessageList->At( aIndex ).iIsMessage = ETrue;
iMessageList->At( aIndex ).iContentsId = id;
iMessageList->At( aIndex ).iMessage = aMessage;
}
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::LoadMessageL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::LoadMessageContentsL
// Loads message contents (as much as it fits).
// Restores the contents of a message
// by reading a stream specified in parameter aContentsId.
// Save status of message is required because saved and unsaved
// messages are stored on separate files.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::LoadMessageContentsL(
const TStreamId& aContentsId,
TPtr& aContents,
TBool aIsSaved,
TUint aSize ) const
{
CFileStore* store = aIsSaved ?
iTopicList.TopicStoreL() :
iTopicList.UnsavedMessagesStore();
// Read data to the buffer.
RStoreReadStream instream;
instream.OpenLC( *store, aContentsId ); // on CS
// Read the data into a temporary buffer first.
// Then copy to the aContents descriptor only
// as much as it can take.
TUint length( instream.ReadInt16L() );
if ( length > KCbsMaxCharsInMessage )
{
User::Leave( KErrCorrupt );
}
HBufC* buf = HBufC::NewL( instream, length );
if ( length > aSize )
{
length = aSize;
}
aContents.Copy( buf->Ptr(), length );
delete buf;
CleanupStack::PopAndDestroy(); // instream
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::GenerateNewMessageHandle
// Generates a new, unique handle for a message.
// The generation uses topic number as
// basis and then increments the handle value until an unique
// handle is found.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TCbsDbMessageHandle CCbsDbImpTopicMessages::GenerateNewMessageHandle(
const TCbsDbTopicNumber& aNumber )
{
// Start with a reasonable seed. We'll try the number
// of messages in topic, plus one.
TUint16 handleLow( TUint16( iMessageList->Count() + 1 ) );
TCbsDbMessageHandle handle( 1 );
TInt error( KErrNone );
while ( error == KErrNone )
{
handleLow++;
if ( handleLow == 0 )
{
handleLow++;
}
// Generate a new message handle.
handle = iTopicList.GenerateMessageHandle( aNumber,
handleLow );
TRAP( error, ( FindMessagePositionByHandleL( handle ) ) );
}
return handle;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DeleteReceivedIfNecessaryL
// Checks that if there are too many received messages in the internal cache,
// then they will be deleted if they are not locked.
// Note: Count() is changed in for-loop.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCbsDbImpTopicMessages::DeleteReceivedIfNecessaryL()
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::DeleteReceivedIfNecessaryL()");
// So check if there are too many received messages in the topic.
// Thus delete if message is not locked.
__ASSERT_DEBUG( iCacheValid, CbsServerPanic( ECbsCacheNotValid ) );
TInt totalReceived( 0 );
TCbsDbMessage message;
TBool result( EFalse );
TInt index( 0 );
for ( index = 0; index < iMessageList->Count(); index++ )
{
LoadMessageL( index, message );
// Count the amount of received messages
if ( !message.iPermanent )
{
totalReceived++;
// If there are too many, then check that it can be deleted.
if ( totalReceived > KCbsDbMaxReceivedMessages &&
!IsMessageLocked( message.iHandle ) )
{
// Delete the message.
DeleteMessageByPositionL( index );
iTopicList.InformMessageDeletedL
( message.iHandle,
message.iPermanent,
message.iRead );
result = ETrue;
// They are always deleted from internal cache
index--;
totalReceived--;
}
}
}
CBSLOGSTRING2("CBSSERVER: <<< CCbsDbImpTopicMessages::DeleteReceivedIfNecessaryL(), returning %d.", result );
return result;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DeleteMessageByPositionL
// Deletes message by its position in the internal cache.
// Note that after the call the internal cache won't contain
// the item.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DeleteMessageByPositionL(
TInt aIndex )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::DeleteMessageByPositionL()");
// Delete from cache and from file.
__ASSERT_DEBUG( iCacheValid, CbsServerPanic( ECbsCacheNotValid ) );
TCbsDbImpTopicMessagesCacheItem item( iMessageList->At( aIndex ) );
// Determine the file where the message is stored.
CFileStore* store = item.iIsSaved ? iTopicList.TopicStoreL() :
iTopicList.UnsavedMessagesStore();
iMessageList->Delete( aIndex );
store->Delete( item.iId );
store->Delete( item.iContentsId );
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::DeleteMessageByPositionL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::IsMessageLocked
// Determines whether or not the message is locked.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCbsDbImpTopicMessages::IsMessageLocked(
const TCbsDbMessageHandle& aHandle ) const
{
// Find out if the message is locked.
TBool found( EFalse );
TInt count( iLockedMessages->Count() );
for ( TInt index( 0 ); ( index < count ) && !found; index++ )
{
if ( iLockedMessages->At( index ) == aHandle )
{
found = ETrue;
}
}
return found;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::DeleteFromLocked
// Deletes from the locked messages.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::DeleteFromLocked(
const TCbsDbMessageHandle& aHandle )
{
TBool deleted( EFalse );
TInt count( iLockedMessages->Count() );
for ( TInt index( 0 ); ( index < count ) && !deleted; index++ )
{
if ( iLockedMessages->At( index ) == aHandle )
{
iLockedMessages->Delete( index );
deleted = ETrue;
}
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::InsertToLockedL
// Adds a handle to the locked messages.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::InsertToLockedL(
const TCbsDbMessageHandle& aHandle )
{
// Just append to the end.
iLockedMessages->AppendL( aHandle );
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL
// Updates topic messages stream from the internal cache.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(
TBool aDeleting )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL()");
__ASSERT_DEBUG( iCacheValid, CbsServerPanic( ECbsCacheNotValid ) );
TInt neededSpace( KMessageRootStreamSize +
iMessageList->Count() * KMessageEntrySize );
RSharedDataClient sharedData;
// About to write to FFS: make critical level check
if ( aDeleting )
{
User::LeaveIfError( sharedData.Connect() );
sharedData.RequestFreeDiskSpaceLC( neededSpace ); // on CS
}
else
{
CbsUtils::FFSCriticalLevelCheckL( neededSpace, iFs );
}
// Now, first check if the information fits well to the current stream.
if ( iSpaceForMessages >= iMessageList->Count() )
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (3)");
// Write data to the old stream.
TStreamId id;
iTopicList.GetTopicMessagesIdL( iCachedTopicNumber, id );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (4)");
// Replace the existing stream.
RStoreWriteStream outstream;
outstream.ReplaceLC( *iTopicList.TopicStoreL(), id ); // on CS
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (5)");
WriteTopicMessagesStreamL( outstream );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (6)");
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
}
else
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (7)");
// Calculate the amount of space for messages.
if ( iSpaceForMessages == 0 )
{
// Zero is not very good, lets put it greater.
iSpaceForMessages = KDefaultSpaceForMessages;
}
// But no need for extra messages.
iSpaceForMessages = 2 * iSpaceForMessages;
if ( iSpaceForMessages >
( KCbsDbMaxReceivedMessages + KCbsDbMaxSavedMessages ) )
{
iSpaceForMessages =
KCbsDbMaxReceivedMessages + KCbsDbMaxSavedMessages;
}
if ( iMessageList->Count() > iSpaceForMessages )
{
iSpaceForMessages = iMessageList->Count();
}
// And finally write the data to stream.
RStoreWriteStream outstream;
TStreamId id = outstream.CreateLC( *iTopicList.TopicStoreL() );// on CS
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (8)");
WriteTopicMessagesStreamL( outstream );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (9)");
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
// And then update topic messages stream. It will also delete
// the old stream.
iTopicList.UpdateTopicMessagesIdL( iCachedTopicNumber, id );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (10)");
}
// Free the reserved space
if ( aDeleting )
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL(): (11)");
CleanupStack::PopAndDestroy(); // disk space
sharedData.Close();
}
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::UpdateTopicMessagesStreamL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::WriteTopicMessagesStreamL
// Writes topic messages stream from the internal cache.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::WriteTopicMessagesStreamL(
RWriteStream& aOut )
{
// Write total amount of messages.
TInt count( iMessageList->Count() );
aOut.WriteInt16L( count );
// Write total amount of space for messages.
aOut.WriteInt16L( iSpaceForMessages );
TInt index( 0 );
for ( ; index < count; index++ )
{
CbsStreamHelper::WriteBoolL( aOut,
iMessageList->At( index ).iIsSaved );
// Write message stream id.
aOut << iMessageList->At( index ).iId;
}
for ( ; index < iSpaceForMessages; index++ )
{
CbsStreamHelper::WriteBoolL( aOut, EFalse );
// Write null message stream id.
aOut << TStreamId( 0 );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::CreateMessageContentsStreamL
// Creates a new message content stream and writes
// the given contents into this stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TStreamId CCbsDbImpTopicMessages::CreateMessageContentsStreamL(
CStreamStore& aStore,
const TDesC& aContents )
{
// Create stream and write data to it.
RStoreWriteStream outstream;
TStreamId id( outstream.CreateLC( aStore ) ); // on CS
// Just write the contents..
TInt count( aContents.Length() );
outstream.WriteInt16L( count );
outstream << aContents;
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
return id;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::CreateMessageStreamL
// Creates a message stream and
// writes the message into that stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TStreamId CCbsDbImpTopicMessages::CreateMessageStreamL(
CStreamStore& aStore,
TCbsDbMessage& aMessage,
const TStreamId& aContents )
{
// Create stream and write data to it.
RStoreWriteStream outstream;
TStreamId id = outstream.CreateLC( aStore ); // on CS
// Write the handle.
outstream.WriteInt32L( aMessage.iHandle );
// Write the message key.
outstream.WriteInt16L( aMessage.iKey );
// Write the language.
outstream.WriteInt16L( aMessage.iLanguage );
// Write the date and time.
outstream << aMessage.iDateTime;
// Write the permanent status.
CbsStreamHelper::WriteBoolL( outstream, aMessage.iPermanent );
// Write the read status.
CbsStreamHelper::WriteBoolL( outstream, aMessage.iRead );
// Write the stream identifier to the contents.
outstream << aContents;
outstream.CommitL();
CleanupStack::PopAndDestroy(); // outstream
return id;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL
// Reads all cache items for a topic.
// Restores topic message cache from a stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(
const CStreamStore& aStore,
const TStreamId& aId,
TCbsDbImpTopicMessagesCache& aCache,
TInt& aSpace )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL()");
RStoreReadStream instream;
instream.OpenLC( aStore, aId ); // on CS
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): instream.OpenLC() OK.");
// Read total amount of messages.
TInt totalMessages( instream.ReadInt16L() );
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): totalMessages: %d.", totalMessages );
// Read total amount of space for messages.
aSpace = instream.ReadInt16L();
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): aSpace: %d.", aSpace );
// Sanity check: if the number of messages exceeds
// the worst case, leave. If the space for messages
// is smaller than number of messages, leave.
if ( totalMessages > KCbsDbMaxSavedMessages + KCbsDbMaxReceivedMessages
|| aSpace < totalMessages )
{
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): Stream corrupt, leaving with KErrCorrupt...");
User::Leave( KErrCorrupt );
}
TCbsDbImpTopicMessagesCacheItem item;
aCache.Reset();
for ( TInt index( 0 ); index < totalMessages; index++ )
{
CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): Looping msgs, i: %d.", index );
item.iIsSaved = CbsStreamHelper::ReadBoolL( instream );
// Read topic message stream id.
instream >> item.iId;
// Initialize other fields.
item.iIsMessage = EFalse;
// And finally, append the item to the array
aCache.AppendL( item );
CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL(): Msg appended to array.");
}
CleanupStack::PopAndDestroy(); // instream
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::ReadTopicMessagesCacheItemsL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::ReadMessageInformationL
// Restore a message from a stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::ReadMessageInformationL(
const CStreamStore& aStore,
const TStreamId& aId,
TCbsDbMessage& aMessage,
TStreamId& aContentsId )
{
CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicMessages::ReadMessageInformationL()");
// Open the message information stream.
RStoreReadStream instream;
instream.OpenLC( aStore, aId ); // on CS
// Read the handle.
aMessage.iHandle = instream.ReadInt32L();
// Read the message key.
aMessage.iKey = instream.ReadInt16L();
// Read the language.
aMessage.iLanguage = instream.ReadInt16L();
// Read the date and time.
TInt64 time;
instream >> time;
aMessage.iDateTime = time;
// Read the permanent status.
aMessage.iPermanent = CbsStreamHelper::ReadBoolL( instream );
// Read the read status.
aMessage.iRead = CbsStreamHelper::ReadBoolL( instream );
// Read the stream identifier to the contents.
instream >> aContentsId;
CleanupStack::PopAndDestroy(); // instream
if ( aContentsId == TStreamId( 0 ) )
{
aMessage.iLength = 0;
}
else
{
// Open message contents stream.
RStoreReadStream instreamContents;
instreamContents.OpenLC( aStore, aContentsId ); // on CS
// Read the length of the message.
aMessage.iLength = instreamContents.ReadInt16L();
CleanupStack::PopAndDestroy(); // instreamContents
}
CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicMessages::ReadMessageInformationL()");
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::WriteMessageInformationL
// Writes message information into a stream.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::WriteMessageInformationL(
RWriteStream& aOut,
const TCbsDbMessage& aMessage,
const TStreamId& aContentsId )
{
// Write the handle.
aOut.WriteInt32L( aMessage.iHandle );
// Write the message key.
aOut.WriteInt16L( aMessage.iKey );
// Write the language.
aOut.WriteInt16L( aMessage.iLanguage );
// Write the date and time.
aOut << aMessage.iDateTime;
// Write the permanent status.
CbsStreamHelper::WriteBoolL( aOut, aMessage.iPermanent );
// Write the read status.
CbsStreamHelper::WriteBoolL( aOut, aMessage.iRead );
// Write the stream identifier to the contents.
aOut << aContentsId;
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::UpdateSoftNotificationL
// Updates the soft notification (dialog) when unread message count changes.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::UpdateSoftNotificationL(
const TCbsDbMessageHandle& aHandle,
const CCbsRecEtel& aReceiver )
{
TCbsDbTopic topic;
TCbsDbTopicNumber topicNum( iTopicList.ExtractTopicNumber( aHandle ) );
iTopicList.FindTopicByNumberL( topicNum, topic );
// If topic is hotmarked, update the soft notification (dialog) ,
// since number of read messages was changed
if ( topic.iHotmarked )
{
aReceiver.Interface().LaunchMessageSoftNotificationL( EFalse );
}
}
// -----------------------------------------------------------------------------
// CCbsDbImpTopicMessages::RevertFileOperationL
// Reverts any not commited file operation in data files,
// reloads cache and then leaves with aReason.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCbsDbImpTopicMessages::RevertFileOperationL(
TInt aReason )
{
iTopicList.RevertFilesL();
InvalidateCache();
User::Leave( aReason );
}
// ========================== OTHER EXPORTED FUNCTIONS =========================
// End of File