diff -r 000000000000 -r 8466d47a6819 ipsservices/ipssosplugin/src/ipsplgsmtpservice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ipsservices/ipssosplugin/src/ipsplgsmtpservice.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,672 @@ +/* +* Copyright (c) 2007 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 file implements class CIpsPlgSmtpService. +* +*/ + + +#include "emailtrace.h" +#include "ipsplgheaders.h" + +// const TInt KIpsSetUtilsCharAt = '@'; +const TInt KIpsSetUtilsCharLessThan = '<'; +const TInt KIpsSetUtilsCharMoreThan = '>'; +const TInt KIpsSetUtilsCntrCharacters = 2; + +// do we need smtp object instead set of static functions + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CIpsPlgSmtpService +// --------------------------------------------------------------------------- +// +CIpsPlgSmtpService::CIpsPlgSmtpService( + CMsvSession& aSession, + CIpsPlgSosBasePlugin& aPlugin ) : + iPlugin( aPlugin ), + iSession( aSession), + iMsgMapper( NULL ) + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::~CIpsPlgSmtpService +// --------------------------------------------------------------------------- +// +CIpsPlgSmtpService::~CIpsPlgSmtpService() + { + FUNC_LOG; + delete iMsgMapper; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::NewL +// --------------------------------------------------------------------------- +// +EXPORT_C CIpsPlgSmtpService* CIpsPlgSmtpService::NewL( + CMsvSession& aSession, + CIpsPlgSosBasePlugin& aPlugin ) + { + FUNC_LOG; + CIpsPlgSmtpService* self = CIpsPlgSmtpService::NewLC( + aSession, aPlugin ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::NewLC +// --------------------------------------------------------------------------- +// +EXPORT_C CIpsPlgSmtpService* CIpsPlgSmtpService::NewLC( + CMsvSession& aSession, + CIpsPlgSosBasePlugin& aPlugin ) + { + FUNC_LOG; + CIpsPlgSmtpService* self = new( ELeave ) CIpsPlgSmtpService( + aSession, aPlugin ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::ConstructL +// --------------------------------------------------------------------------- +// +void CIpsPlgSmtpService::ConstructL() + { + FUNC_LOG; + iMsgMapper = CIpsPlgMsgMapper::NewL( iSession, iPlugin ); + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CreateDisplayStringLC +// --------------------------------------------------------------------------- +// +HBufC* CIpsPlgSmtpService::CreateDisplayStringLC( + const TDesC& aDisplayName, + const TDesC& aEmailName ) + { + FUNC_LOG; + TInt length( aDisplayName.Length() ); + HBufC* fullName( NULL ); + + length += aEmailName.Length() + KIpsSetUtilsCntrCharacters; + fullName = HBufC::NewLC( length ); + fullName->Des().Append( aDisplayName ); + + if ( fullName->Length() ) + { + // We have display name, add angle brackets to address + fullName->Des().Append( KIpsSetUtilsCharLessThan ); + fullName->Des().Append( aEmailName ); + fullName->Des().Append( KIpsSetUtilsCharMoreThan ); + } + else + { + fullName->Des().Append( aEmailName ); + } + return fullName; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::StoreMessageL +// --------------------------------------------------------------------------- +// +void CIpsPlgSmtpService::StoreMessageL( + TFSMailMsgId /* aMailBoxId */, CFSMailMessage& aMessage ) + { + FUNC_LOG; + + // Update flags i.e. Priority + iMsgMapper->UpdateMessageFlagsL( aMessage.GetMessageId().Id(), aMessage ); + + // get message from store + CMsvEntry* cEntry = CMsvEntry::NewL( + iSession, aMessage.GetMessageId().Id(), TMsvSelectionOrdering() ); + CleanupStack::PushL( cEntry ); // << cEntry + TMsvEntry tEntry = cEntry->Entry(); + + // creating store object for editing message + CMsvStore* store = cEntry->EditStoreL(); + CleanupStack::PushL( store ); // << store + + // create symbian email header object + CImHeader* header = CImHeader::NewLC(); // << header + header->RestoreL( *store ); + + // From field, check that sender is set + if ( aMessage.GetSender() ) + { + header->SetFromL( aMessage.GetSender()->GetEmailAddress() ); + } + + // To Field + const RPointerArray& toArray + = aMessage.GetToRecipients(); + // Reseting recipient list, because our client calls us many times + // and we want to avoid duplicates + header->ToRecipients().Reset(); + // build new 'to' header + for( TInt i = 0; i < toArray.Count(); i++ ) + { + TPtrC displayName = toArray[i]->GetDisplayName(); + TPtrC emailName = toArray[i]->GetEmailAddress(); + HBufC* fullName = CreateDisplayStringLC( displayName, emailName ); // << fullName + header->ToRecipients().AppendL( *fullName ); // copy created + // only first receiver + if( i == 0 && fullName ) + { + tEntry.iDetails.Set( *fullName ); + cEntry->ChangeL( tEntry ); + // Load tEntry again + // because old instance's iDetails member gets wiped + // in PopAndDestroy below + tEntry = cEntry->Entry(); + } + CleanupStack::PopAndDestroy( fullName ); // >>> fullName + } + + // CC field + const RPointerArray& ccArray + = aMessage.GetCCRecipients(); + header->CcRecipients().Reset(); + for( TInt i = 0; i < ccArray.Count(); i++ ) + { + header->CcRecipients().AppendL( ccArray[i]->GetEmailAddress() ); // copy created + } + + // BCC field + const RPointerArray& bccArray + = aMessage.GetBCCRecipients(); + header->BccRecipients().Reset(); + for( TInt i = 0; i < bccArray.Count(); i++ ) + { + header->BccRecipients().AppendL( bccArray[i]->GetEmailAddress() ); // copy created + } + + // Subject, check null pointer + if ( &aMessage.GetSubject() ) + { + header->SetSubjectL( aMessage.GetSubject() ); + } + + // store header in cEntry's store + header->StoreWithoutCommitL(*store); + // commit header to store + store->CommitL(); + + //change preparation state and set subject to description + tEntry.SetInPreparation( EFalse ); + tEntry.iDescription.Set( aMessage.GetSubject() ); + + cEntry->ChangeL( tEntry ); + + // release store + CleanupStack::PopAndDestroy( 3, cEntry ); // >>> cEntry, header, store + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CreateNewSmtpMessageL +// --------------------------------------------------------------------------- +// +CFSMailMessage* CIpsPlgSmtpService::CreateNewSmtpMessageL( + const TFSMailMsgId& aMailBoxId ) + { + FUNC_LOG; + TMsvPartList partList( KMsvMessagePartBody ); + + CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( ); + + TMsvEntry mboxEntry; + TMsvId service; + iSession.GetEntry( aMailBoxId.Id(), service, mboxEntry ); + + // new mail creating operation. Mail is created asynchronously + CImEmailOperation* newMailOp = CImEmailOperation::CreateNewL( + wait->iStatus, + iSession, + KMsvDraftEntryId, + mboxEntry.iRelatedId, + partList, + 0, + KUidMsgTypeSMTP ); + + CleanupStack::PushL( newMailOp ); + + // wait until new mail is created + wait->Start(); + + TMsvId msgId = GetIdFromProgressL( newMailOp->FinalProgress() ); + + CleanupStack::PopAndDestroy( 2, wait ); + + return CreateFSMessageAndSetFlagsL( + msgId, KErrNotFound, aMailBoxId.Id() ); + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CreateForwardSmtpMessageL +// --------------------------------------------------------------------------- +// +CFSMailMessage* CIpsPlgSmtpService::CreateForwardSmtpMessageL( + const TFSMailMsgId& aMailBoxId, + const TFSMailMsgId& aOriginalMessageId ) + { + FUNC_LOG; + // 1. part of function checs that body text and all + // attachments are fetched + TMsvEntry orgMsg; + TMsvId service; + User::LeaveIfError( iSession.GetEntry( + aOriginalMessageId.Id(), service, orgMsg ) ); + + if ( orgMsg.Id() == KMsvNullIndexEntryIdValue ) + { + User::Leave(KErrNotFound); + } + + // In case original message is in Sent folder, it's serviceId must be + // changed before starting forward/reply msg creation operation + // (after forward msg is created, this is changed back) + TMsvId orgServiceId( 0 ); + if ( ( orgMsg.Parent() == KMsvSentEntryIdValue ) && + ( orgMsg.iMtm == KSenduiMtmSmtpUid ) ) + { + orgServiceId = orgMsg.iServiceId; + ChangeServiceIdL( orgMsg ); + } + + TMsvPartList partList( KMsvMessagePartBody | KMsvMessagePartAttachments ); + + CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( ); + CImEmailOperation* forwMailOp = CImEmailOperation::CreateForwardL( + wait->iStatus, + iSession, + orgMsg.Id(), + KMsvDraftEntryId, + partList, + 0, + KUidMsgTypeSMTP ); + + CleanupStack::PushL( forwMailOp ); + + wait->Start(); + + TMsvId msgId = GetIdFromProgressL( forwMailOp->FinalProgress() ); + + CleanupStack::PopAndDestroy( 2, wait ); + + // If original message's serviceId was changed prior to forward/reply msg + // creation op, changing it back to the original + if ( orgServiceId ) + { + ChangeServiceIdL( orgMsg, orgServiceId ); + } + + return CreateFSMessageAndSetFlagsL( msgId, orgMsg.Id(), aMailBoxId.Id() ); + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CreateReplySmtpMessageL +// --------------------------------------------------------------------------- +// +CFSMailMessage* CIpsPlgSmtpService::CreateReplySmtpMessageL( + const TFSMailMsgId& aMailBoxId, + const TFSMailMsgId& aOriginalMessageId, + TBool aReplyToAll ) + { + FUNC_LOG; + // find orginal message header and check that body is fetched + TMsvEntry orgMsg; + TMsvId service; + User::LeaveIfError( + iSession.GetEntry( aOriginalMessageId.Id(), service, orgMsg ) ); + + if ( orgMsg.Id() == KMsvNullIndexEntryIdValue ) + { + User::Leave(KErrNotFound); + } + + // In case original message is in Sent folder, it's serviceId must be + // changed before starting forward/reply msg creation operation + // (after forward msg is created, this is changed back) + TMsvId orgServiceId( 0 ); + if ( ( orgMsg.Parent() == KMsvSentEntryIdValue ) && + ( orgMsg.iMtm == KSenduiMtmSmtpUid ) ) + { + orgServiceId = orgMsg.iServiceId; + ChangeServiceIdL( orgMsg ); + } + + // partList flags control e.g. what kind of recipient set is created + TMsvPartList partList = KMsvMessagePartBody | KMsvMessagePartDescription + | KMsvMessagePartOriginator; + if( aReplyToAll ) + { + partList |= KMsvMessagePartRecipient; + } + + // Ask Symbian messaging fw to create reply message "skeleton" + CIpsPlgOperationWait* wait = CIpsPlgOperationWait::NewLC( ); + CImEmailOperation* replMailOp = CImEmailOperation::CreateReplyL( + wait->iStatus, + iSession, + orgMsg.Id(), + KMsvDraftEntryId, + partList, + 0, + KUidMsgTypeSMTP ); + CleanupStack::PushL( replMailOp ); + wait->Start(); + TMsvId msgId = GetIdFromProgressL( replMailOp->FinalProgress() ); + CleanupStack::PopAndDestroy( 2, wait ); + + // If original message's serviceId was changed prior to forward/reply msg + // creation op, changing it back to the original + if ( orgServiceId ) + { + ChangeServiceIdL( orgMsg, orgServiceId ); + } + + // Start finalising new FS style message + CFSMailMessage* fsMsg = CreateFSMessageAndSetFlagsL( + msgId, orgMsg.Id(), aMailBoxId.Id() ); + CleanupStack::PushL( fsMsg ); // *** + + // dig out new reply message's header + CMsvEntry* cEntry = iSession.GetEntryL( msgId ); + CleanupStack::PushL( cEntry ); // *** + CMsvStore* store = cEntry->ReadStoreL(); + CleanupStack::PushL( store ); // *** + if( store->IsPresentL( KUidMsgFileIMailHeader ) == EFalse ) + { + User::Leave(KErrCorrupt); + } + CImHeader* header = CImHeader::NewLC(); // *** + header->RestoreL( *store ); + + // Start handling recipients + HBufC* emailAddr( NULL ); + CFSMailAddress* fsAddr( NULL ); + // copy to recipients + for( TInt i = 0; i < header->ToRecipients().Count(); i++ ) + { + emailAddr = header->ToRecipients()[i].AllocLC(); // *** + fsAddr = CFSMailAddress::NewLC(); // *** + fsAddr->SetEmailAddress( *emailAddr ); // Copy created + fsMsg->AppendToRecipient( fsAddr ); // No copy + CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg + CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used + } + // copy cc recipients + // + TFSMailMsgId folderId; + TFSMailDetails details( EFSMsgDataEnvelope ); + CFSMailMessage* originalMessage = iPlugin.GetMessageByUidL( aMailBoxId, + folderId, aOriginalMessageId, details ); + CleanupStack::PushL( originalMessage ); + RPointerArray& originalToRecipients = + originalMessage->GetToRecipients(); + TInt originalToRecipientsCount = originalToRecipients.Count(); + TBool present = EFalse; + // + for( TInt i = 0; i < header->CcRecipients().Count(); i++ ) + { + emailAddr = header->CcRecipients()[i].AllocLC(); // *** + fsAddr = CFSMailAddress::NewLC(); // *** + fsAddr->SetEmailAddress( *emailAddr ); // Copy created + // + if( aReplyToAll ) + { + // check if CC recipient read from header was present in To field + // of original message. If so, copy it into To recipietns + present = EFalse; + for( TInt j = 0; j < originalToRecipientsCount; j++ ) + { + if( emailAddr->Find( originalToRecipients[j]->GetEmailAddress()) + != KErrNotFound ) + { + present = ETrue; + break; + } + } + if( present ) + { + fsMsg->AppendToRecipient( fsAddr ); // No copy + } + else + { + fsMsg->AppendCCRecipient( fsAddr ); // No copy + } + } + else + { + fsMsg->AppendCCRecipient( fsAddr ); // No copy + } + // + CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg + CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used + } + // + CleanupStack::PopAndDestroy( originalMessage ); + // + // copy bcc recipients + for( TInt i = 0; i < header->BccRecipients().Count(); i++ ) + { + emailAddr = header->BccRecipients()[i].AllocLC(); // *** + fsAddr = CFSMailAddress::NewLC(); // *** + fsAddr->SetEmailAddress( *emailAddr ); // Copy created + fsMsg->AppendBCCRecipient( fsAddr ); // No copy + CleanupStack::Pop( fsAddr ); // fsAddr belong now to fsMsg + CleanupStack::PopAndDestroy( emailAddr ); // emailAddr not used + } + + CleanupStack::PopAndDestroy( 3, cEntry ); // header, store, cEntry + CleanupStack::Pop( fsMsg ); // fsMsg is given to client + return fsMsg; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::ChangeServiceIdL +// --------------------------------------------------------------------------- +// +void CIpsPlgSmtpService::ChangeServiceIdL( TMsvEntry& aEntry ) + { + FUNC_LOG; + TMsvEntry serviceEntry; + TMsvId service; + CMsvEntry* cEntry = iSession.GetEntryL( aEntry.iServiceId ); + CleanupStack::PushL( cEntry ); + User::LeaveIfError( iSession.GetEntry( cEntry->EntryId(), service, serviceEntry ) ); + if( aEntry.iServiceId != serviceEntry.iRelatedId ) + { + aEntry.iServiceId = serviceEntry.iRelatedId; + cEntry->SetEntryL( aEntry.Id() ); + cEntry->ChangeL( aEntry ); + } + CleanupStack::PopAndDestroy( cEntry ); + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::ChangeServiceIdL +// --------------------------------------------------------------------------- +// +void CIpsPlgSmtpService::ChangeServiceIdL( TMsvEntry& aEntry, TMsvId aServiceId ) + { + FUNC_LOG; + CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() ); + CleanupStack::PushL( cEntry ); + aEntry.iServiceId = aServiceId; + cEntry->ChangeL( aEntry ); + CleanupStack::PopAndDestroy( cEntry ); + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::CreateFSMessageAndSetFlagsL +// --------------------------------------------------------------------------- +// +CFSMailMessage* CIpsPlgSmtpService::CreateFSMessageAndSetFlagsL( + TMsvId aMessageId, TMsvId aOriginalMsgId,TMsvId aMailboxId ) + { + FUNC_LOG; + + // Default charset + TUid charset; + charset.iUid = KCharacterSetIdentifierUtf8; + + // set in preparation flag, altought + // not known where this affects + TMsvId dummy; + TMsvEmailEntry newEmailMsg; + iSession.GetEntry( aMessageId, dummy, newEmailMsg ); + newEmailMsg.SetInPreparation( ETrue ); + + // when creating new message from scratch theres no + // orginal message, so it is set to KErrNotFound + if ( aOriginalMsgId != KErrNotFound ) + { + TMsvEntry orgMsg; + //get entry errors not handled + iSession.GetEntry( aOriginalMsgId, dummy, orgMsg ); + const TMsvEmailEntry& orgEmailMsg(orgMsg); + + // symbian not mark same priority to reply / forward messages + if ( orgEmailMsg.Priority() != newEmailMsg.Priority() ) + { + newEmailMsg.SetPriority( orgEmailMsg.Priority() ); + } + //get charset from original message + charset = GetOriginalCharsetL( aOriginalMsgId ); + } + + // set in preparation + CMsvEntry* cEntry = iSession.GetEntryL( aMessageId ); + CleanupStack::PushL( cEntry ); + cEntry->ChangeL( newEmailMsg ); + + //no need to set if we for some reason don't have it. + //system default will be used. + if ( KNullUidValue != charset.iUid ) + { + SetCharactersetL( *cEntry, charset ); + } + // delete operations we don't need anymore + CleanupStack::PopAndDestroy( cEntry ); + + // create a Freestyle mail message object and set to it all + // needed data from just created symbian mail message + CFSMailMessage* fsMsg = CFSMailMessage::NewL( + TFSMailMsgId( iPlugin.PluginId(), aMessageId ) ); + fsMsg->SetMailBoxId( TFSMailMsgId( iPlugin.PluginId(), aMailboxId ) ); + fsMsg->SetFolderId( + TFSMailMsgId( iPlugin.PluginId(), KMsvDraftEntryId ) ); + + //update flags + iMsgMapper->SetFSMessageFlagsL( newEmailMsg, *fsMsg ); + + return fsMsg; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::GetIdFromProgressL +// inline static +// --------------------------------------------------------------------------- +// +inline TMsvId CIpsPlgSmtpService::GetIdFromProgressL( const TDesC8& aProg ) + { + FUNC_LOG; + // Taken from symbian os help example code + // Create and initialise a temporary TPckg object that + // can hold a message Id. + TMsvId msgId; + TPckg param(msgId); + + // Copy the message Id returned from the ProgressL() call into the + // temporary TPckg object. + param.Copy( aProg ); + + // Check the value of the returned message Id in the TPckg object. + if ( msgId == KMsvNullIndexEntryId ) + { + // Email is not correctly created, so leave + User::Leave( KErrNotFound ); + } + return msgId; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::GetOriginalCharsetL +// --------------------------------------------------------------------------- +// +TUid CIpsPlgSmtpService::GetOriginalCharsetL( TMsvId aOriginalMsgId ) + { + FUNC_LOG; + TUid ret; + CMsvEntry* oEntry = iSession.GetEntryL( aOriginalMsgId ); + CleanupStack::PushL( oEntry ); + + CImEmailMessage* cMessage = CImEmailMessage::NewLC( *oEntry ); + + // Added check for body text because GetCharacterSetL will + // hang if there is no body text + CMsvStore* store = oEntry->EditStoreL(); + CleanupStack::PushL(store); + + TUint charId; + + if( store->HasBodyTextL() ) + { + TBool override=EFalse; + cMessage->GetCharacterSetL( aOriginalMsgId, charId, override ); + ret.iUid = charId; + } + else + { + ret.iUid = KCharacterSetIdentifierUtf8; + } + + CleanupStack::PopAndDestroy( 3, oEntry );//oEntry, cMessage, store + // + + return ret; + } + +// --------------------------------------------------------------------------- +// CIpsPlgSmtpService::SetCharactersetL +// --------------------------------------------------------------------------- +// +void CIpsPlgSmtpService::SetCharactersetL( CMsvEntry& aEntry, TUid aCharset ) + { + FUNC_LOG; + //Set character set for outgoing message. We use the one + //that was in the original message. + CMsvStore* store = aEntry.EditStoreL(); + CleanupStack::PushL(store); + + CImHeader* header = CImHeader::NewLC(); + header->RestoreL( *store ); + + TImEmailTransformingInfo info; + info.SetToDefault(ESendAsMimeEmail); + info.SetHeaderAndBodyCharset( aCharset.iUid ); + info.StoreL( *store ); + + header->StoreL( *store ); + store->CommitL(); + CleanupStack::PopAndDestroy( 2, store ); // store, header + } +// End of File +