messagingapp/msgutils/unieditorutils/unieditorplugins/unieditorsmsplugin/src/unieditorsmsplugin_p.cpp
/*
* Copyright (c) 2009 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:
*
*/
// INCLUDE FILES
// Symbian:
#include <e32base.h>
#include <txtetext.h>
#include <txtrich.h>
#include <s32mem.h>
#include <mmsvattachmentmanager.h>
#include <mmsvattachmentmanagersync.h>
#include <gsmerror.h> // KErrGsmOfflineOpNotAllowed
#include <featmgr.h>
#include <mtclreg.h>
#include <smsclnt.h>
#include <smscmds.h>
#include <smuthdr.h>
#include <csmsemailfields.h>
#include <csmsaccount.h>
#include <charconv.h>
#include <smut.h>
#include <cmsvmimeheaders.h>
#include <badesca.h>
#include <e32cmn.h>
#include <gsmuset.h>
// S60
#include <MsgMediaResolver.h>
#include <MsgMediaInfo.h>
#include <MsgTextInfo.h>
#include <mmsgenutils.h>
#include <vcard.h>
#include <SenduiMtmUids.h>
#include <MsgMimeTypes.h>
#include "UniSendingSettings.h"
#include "MessagingVariant.hrh"
#include "msgbiouids.h"
#include "unieditorsmsplugin_p.h"
#include "convergedmessage.h"
#include "convergedmessageid.h"
#include "convergedmessageattachment.h"
#include "MuiuOperationWait.h"
#include "UniEditorGenUtils.h"
#include "unidatamodelloader.h"
#include "unidatamodelplugininterface.h"
#include <hbglobal.h> // for translation support
#include <xqconversions.h>
// resources
// CONSTANTS
// Used to set msg in unparsed state
const TInt KSmsPluginBioMsgUnparsed = 0;
// Description length for sms messages
const TInt KSmsMessageEntryDescriptionAmountOfChars = 60;
//used for descriptor array containing recipients
const TInt KRecipientsArrayGranularity = 8;
// For address information separation (start)
const TUint KMsgSmsAddressStartChar ('<');
// For address information separation (end)
const TUint KMsgSmsAddressEndChar ('>');
const TUint KUniSmsStartParenthesis ('(');
const TUint KUniSmsEndParenthesis (')');
// String length for Service centre name
const TInt KUniSmsSCStringLength = 50;
const TUid KUidMsvSMSHeaderStream_COPY_FROM_SMUTHDR_CPP = {0x10001834};
// Amount of to be converted chars during extracting description
const TInt KSmsEdExtrDescReplaceCharacterCount = 3;
// Unicode char for linefeed regocnised by basic phones
const TUint KSmsEdUnicodeLFSupportedByBasicPhones = 0x000A;
// Copy max this many chars to TMsvEntry iDetails
const TInt KMaxDetailsLength = 64;
// separators for iDetails field
_LIT( KAddressSeparator, ";" );
// LOCALIZED CONSTANTS
// String to be shown in Drafts view for VCard sms
#define BUSINESS_CARD hbTrId("txt_messaging_list_business_card")
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
UniEditorSmsPluginPrivate* UniEditorSmsPluginPrivate::NewL()
{
UniEditorSmsPluginPrivate* self = new ( ELeave ) UniEditorSmsPluginPrivate();
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
UniEditorSmsPluginPrivate::~UniEditorSmsPluginPrivate()
{
if(iGenUtils)
{
delete iGenUtils;
iGenUtils = NULL;
}
if(iEmailOverSmsC)
{
delete iEmailOverSmsC;
iEmailOverSmsC = NULL;
}
if(iRecipients)
{
delete iRecipients;
iRecipients = NULL;
}
if(iRichText)
{
delete iRichText;
iRichText = NULL;
}
if(iCharFormatLayer)
{
delete iCharFormatLayer;
iCharFormatLayer = NULL;
}
if(iParaFormatLayer)
{
delete iParaFormatLayer;
iParaFormatLayer = NULL;
}
if(iSmsHeader)
{
delete iSmsHeader;
iSmsHeader = NULL;
}
if(iSmsMtm)
{
delete iSmsMtm;
iSmsMtm = NULL;
}
if(iMtmRegistry)
{
delete iMtmRegistry;
iMtmRegistry = NULL;
}
if(iSession)
{
delete iSession;
iSession = NULL;
}
}
// -----------------------------------------------------------------------------
// C++ default constructor
// -----------------------------------------------------------------------------
//
UniEditorSmsPluginPrivate::UniEditorSmsPluginPrivate() :
iSession(0),
iMtmRegistry(0),
iSmsMtm(0),
iSmsHeader(0),
iParaFormatLayer(0),
iCharFormatLayer(0),
iRichText(0),
iRecipients(0),
iBioMsg( EFalse ),
iEmailOverSmsC(0),
iUnicodeMode( EFalse ),
iOfflineSupported( EFalse ),
iCharSupportType(TUniSendingSettings::EUniCharSupportReduced),
iGenUtils(0)
{
}
// -----------------------------------------------------------------------------
// Symbian 2nd phase constructor
// -----------------------------------------------------------------------------
//
void UniEditorSmsPluginPrivate::ConstructL()
{
iSession = CMsvSession::OpenSyncL(*this);
iParaFormatLayer = CParaFormatLayer::NewL();
iCharFormatLayer = CCharFormatLayer::NewL();
iRichText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
iEmailOverSmsC = CSmsNumber::NewL();
CMsvEntry& entry = SmsMtmL()->Entry();
entry.SetEntryL( KMsvRootIndexEntryId );
TSmsUtilities::ServiceIdL( entry, iSmsServiceId );
FeatureManager::InitializeLibL();
if ( FeatureManager::FeatureSupported( KFeatureIdOfflineMode ) )
{
iOfflineSupported = ETrue;
}
else
{
iOfflineSupported = EFalse;
}
//Turkish SMS-PREQ2265 Specific
if ( FeatureManager::FeatureSupported( KFeatureIdNltSupport ) )
{
iNLTFeatureSupport = ETrue;
}
else
{
iNLTFeatureSupport = EFalse;
}
FeatureManager::UnInitializeLib();
iGenUtils = new UniEditorGenUtils();
}
// -----------------------------------------------------------------------------
// LoadHeadersL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::LoadHeadersL( CMsvStore* aStore )
{
delete iSmsHeader;
iSmsHeader = NULL;
if ( aStore && aStore->HasBodyTextL() )
{
aStore->RestoreBodyTextL( *iRichText );
}
iSmsHeader = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *iRichText );
if ( aStore && aStore->IsPresentL( KUidMsvSMSHeaderStream_COPY_FROM_SMUTHDR_CPP ) )
{
iSmsHeader->RestoreL( *aStore );
}
else
{
CSmsSettings* settings = CSmsSettings::NewLC();
CSmsAccount* account = CSmsAccount::NewLC();
account->LoadSettingsL( *settings );
CleanupStack::PopAndDestroy( account );
iSmsHeader->SetSmsSettingsL( *settings );
CleanupStack::PopAndDestroy( settings );
}
}
// -----------------------------------------------------------------------------
// ConvertFromL
// @see header
// -----------------------------------------------------------------------------
ConvergedMessage* UniEditorSmsPluginPrivate::ConvertFromL(TMsvId aId,
UniEditorPluginInterface::EditorOperation aOperation)
{
ConvergedMessageId id(aId);
ConvergedMessage* msg = new ConvergedMessage(id);
CleanupStack::PushL(msg);
DoConvertFromL(aId, msg, aOperation);
CleanupStack::Pop(msg);
return msg;
}
// -----------------------------------------------------------------------------
// DoConvertFromL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::DoConvertFromL( TMsvId aId,
ConvergedMessage* aMessage,
UniEditorPluginInterface::EditorOperation aOperation)
{
// load message for processing
SmsMtmL()->SwitchCurrentEntryL( aId );
SmsMtmL()->LoadMessageL();
aMessage->setMessageType(ConvergedMessage::Sms);
// get parent entry
TMsvEntry msvEntry( SmsMtmL()->Entry().Entry() );
TMsvId parent = msvEntry.Parent();
if( parent == KMsvDraftEntryIdValue )
{
aMessage->setLocation(ConvergedMessage::Draft);
//TODO: need to give FORWARD etc info in convergedMessage
aMessage->setDirection(ConvergedMessage::Outgoing);
//Populate recipients
populateRecipientsL(aMessage);
//Populate message body
populateMessageBodyL(aMessage,msvEntry);
}
else if(aOperation == UniEditorPluginInterface::Forward)
{
//Populate message body
populateMessageBodyL(aMessage,msvEntry);
}
//This is required as the switch entry doesnot reset sms headers
//so if we fwd an inbox msg and then try to save that content to drafts
//we see some issue
delete iSmsMtm;
iSmsMtm = NULL;
return;
}
// -----------------------------------------------------------------------------
// ConvertToL
// @see header
// -----------------------------------------------------------------------------
TMsvId UniEditorSmsPluginPrivate::ConvertToL( ConvergedMessage* message )
{
// create message in draft folder
TMsvId id = CreateNativeSmsL();
int err = KErrNone;
TRAP(err,
// set sms data
SetSmsDataL( message );
// set sms settings
SetSmsSettingsL();
// save all changes for the entry
SmsMtmL()->SaveMessageL();
);
// delete the created drafts entry because error
// happened during save
if (err != KErrNone)
{
DeleteDraftsEntryL(id);
id = -1;
}
return id;
}
// -----------------------------------------------------------------------------
// CreateNativeSmsL
// @see header
// -----------------------------------------------------------------------------
TMsvId UniEditorSmsPluginPrivate::CreateNativeSmsL()
{
CMsvEntry* cEntry = SmsMtmL()->Session().GetEntryL(KMsvDraftEntryId);
CleanupStack::PushL( cEntry );
SmsMtmL()->SwitchCurrentEntryL( cEntry->EntryId() );
TMsvEntry tEntry;
tEntry.SetAttachment( EFalse );
tEntry.iMtm = KSenduiMtmSmsUid;
tEntry.iType = KUidMsvMessageEntry;
tEntry.iRelatedId = iSmsServiceId;
tEntry.iServiceId = KMsvLocalServiceIndexEntryId;
tEntry.iDate.UniversalTime();
tEntry.SetInPreparation( ETrue );
tEntry.SetVisible( EFalse );
cEntry->CreateL(tEntry);
SmsMtmL()->SwitchCurrentEntryL(tEntry.Id());
CleanupStack::PopAndDestroy( cEntry );
return SmsMtmL()->Entry().Entry().Id();
}
// -----------------------------------------------------------------------------
// SetSmsDataL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetSmsDataL(ConvergedMessage* message)
{
// populate recipients, subject and emailfields
SetSmsHeaderL(message);
// populate the attachments in msg entry
SetSmsAttachmentsL(message);
}
// -----------------------------------------------------------------------------
// SetSmsHeaderL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetSmsHeaderL(ConvergedMessage* message)
{
TBuf<KMaxDetailsLength> idetailsBuf;
idetailsBuf.Zero();
//Save for email over sms
if ( iRecipients )
{
delete iRecipients;
iRecipients = NULL;
}
iRecipients = new ( ELeave ) CDesCArrayFlat( KRecipientsArrayGranularity );
CSmsEmailFields *emailFields = CSmsEmailFields::NewL();
CleanupStack::PushL( emailFields );
ConvergedMessageAddressList addrList = message->toAddressList();
int addrCount = addrList.count();
for(int i=0; i<addrCount; i++)
{
HBufC* addr = XQConversions::qStringToS60Desc( addrList.at(i)->address() );
HBufC* alt_alias = XQConversions::qStringToS60Desc( addrList.at(i)->alias() );
if(addr->Length() > 0)
{
CleanupStack::PushL(addr);
if(alt_alias->Length() > 0)
CleanupStack::PushL(alt_alias);
HBufC* pureAddr = TMmsGenUtils::PureAddress( *addr ).AllocLC();
HBufC* aliasAddr = TMmsGenUtils::Alias( *addr ).AllocLC();
TInt appendLen = KMaxDetailsLength-idetailsBuf.Length();
TPtrC appendbuf;
if ( IsEmailAddress( *pureAddr ) )
{
emailFields->AddAddressL( *pureAddr );
appendbuf.Set(pureAddr->Des().Left(appendLen));
}
else
{
if(aliasAddr->Length() > 0)
{
SmsMtmL()->AddAddresseeL( *pureAddr, *aliasAddr );
appendbuf.Set(aliasAddr->Des().Left(appendLen));
}
else
{
if(alt_alias->Length() > 0)
{
SmsMtmL()->AddAddresseeL( *pureAddr, *alt_alias );
appendbuf.Set(alt_alias->Des().Left(appendLen));
}
else
{
SmsMtmL()->AddAddresseeL( *pureAddr );
appendbuf.Set(pureAddr->Des().Left(appendLen));
}
}
}
// copy the append-buffer to form idetails
if(appendLen > 0)
{
idetailsBuf.Append( appendbuf );
}
iRecipients->AppendL( *addr );
// cleanup
CleanupStack::PopAndDestroy(2, pureAddr );
if(alt_alias->Length() > 0)
{
CleanupStack::PopAndDestroy( alt_alias );
}
CleanupStack::PopAndDestroy( addr );
// append separator
if(i != addrCount-1)
{
if(KMaxDetailsLength-idetailsBuf.Length() > 0)
{
idetailsBuf.Append( KAddressSeparator() );
}
}
}
}
if(idetailsBuf.Length() > 0)
{
// set iDetails
CMsvEntry& entry = SmsMtmL()->Entry();
TMsvEntry msvEntry( entry.Entry() );
msvEntry.iDetails.Set( idetailsBuf );
entry.ChangeL( msvEntry );
SmsMtmL()->SaveMessageL();
}
// set subject
if ( !message->subject().isEmpty() )
{
HBufC* subj = XQConversions::qStringToS60Desc( message->subject() );
if( subj )
{
CleanupStack::PushL( subj );
emailFields->SetSubjectL( *subj );
CleanupStack::PopAndDestroy( subj );
}
}
SmsMtmL()->SmsHeader().SetEmailFieldsL( *emailFields );
CleanupStack::PopAndDestroy( emailFields );
}
// -----------------------------------------------------------------------------
// SetSmsBodyL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetSmsBodyL(ConvergedMessage* message)
{
HBufC8* bodytext = XQConversions::qStringToS60Desc8( message->bodyText() );
if( bodytext->Length() > 0)
{
CleanupStack::PushL( bodytext );
RDesReadStream stream(*bodytext);
CleanupClosePushL( stream );
CPlainText::TImportExportParam param;
param.iForeignEncoding = KCharacterSetIdentifierUtf8;
param.iOrganisation = CPlainText::EOrganiseByParagraph;
CPlainText::TImportExportResult result;
SmsMtmL()->Body().Reset();
SmsMtmL()->Body().ImportTextL( 0, stream, param, result );
CleanupStack::PopAndDestroy(&stream);
CleanupStack::PopAndDestroy( bodytext );
}
}
// -----------------------------------------------------------------------------
// SetSmsAttachmentsL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetSmsAttachmentsL(ConvergedMessage* message)
{
// set body text
SetSmsBodyL( message );
// look for attachments
ConvergedMessageAttachmentList attachmentList = message->attachments();
int attachmentCount = attachmentList.count();
ConvergedMessageAttachment* attachment = NULL;
if( attachmentCount > 1)
{
//Programming error in caller code
// sms can have at-max 1 attachment e.g. vcard, vcal etc
User::Leave( KErrArgument );
}
else if( attachmentCount == 1)
{
attachment = attachmentList.at(0);
}
// set entry info for drafts viewing
TMsvEntry tEntry = SmsMtmL()->Entry().Entry();
CMsvStore* store = SmsMtmL()->Entry().EditStoreL();
CleanupStack::PushL( store );
// fill localized strings for smart-msgs e.g. 'Business Card' for vcards
QString descr;
if ( attachment )
{
// create msv attachment in store
CreateAttachmentL(store,
*XQConversions::qStringToS60Desc(attachment->filePath()));
// check for mimetype of the attachment
TPtrC8 mimetype;
int attSize;
QString attMimeType;
TMsgMediaType attMediaType = EMsgMediaUnknown;
iGenUtils->getFileInfoL(attachment->filePath(),
attSize, attMimeType, attMediaType);
mimetype.Set( *XQConversions::qStringToS60Desc8(attMimeType) );
if ( mimetype.CompareF( KMsgMimeTextPlain ) == 0 )
{
iBioMsg=EFalse;
}
else if ( mimetype.CompareF(KMsgMimeVCard) == 0 )
{
iBioMsg=ETrue;
tEntry.iBioType = KMsgBioUidVCard.iUid;
SmsMtmL()->BioTypeChangedL( KMsgBioUidVCard );
descr = BUSINESS_CARD;
}
else if ( mimetype.CompareF(KMsgMimeVCal ) == 0 ||
mimetype.CompareF(KMsgMimeICal ) == 0 )
{
iBioMsg=ETrue;
tEntry.iBioType = KMsgBioUidVCalendar.iUid;
SmsMtmL()->BioTypeChangedL( KMsgBioUidVCalendar );
}
else
{
// do not expect any other mimetype
User::Leave( KErrArgument );
}
}
// populate description for this msg (from subject/body content)
CSmsHeader& header = SmsMtmL()->SmsHeader();
TBuf<KSmsMessageEntryDescriptionAmountOfChars> buf;
buf.Zero();
if(!iBioMsg)
{
ExtractDescriptionFromMessageL(
header.Message(),
buf,
KSmsMessageEntryDescriptionAmountOfChars );
}
else if(!descr.isNull())
{
buf.Copy( *XQConversions::qStringToS60Desc(descr) );
}
tEntry.iDescription.Set( buf );
// save/commit all changes
SmsMtmL()->SaveMessageL( *store, tEntry );
SmsMtmL()->Entry().ChangeL( tEntry );
store->Commit();
CleanupStack::PopAndDestroy( store );
}
// -----------------------------------------------------------------------------
// CreateAttachmentL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::CreateAttachmentL(CMsvStore* aStore, const TDesC& aFilePath)
{
MMsvAttachmentManager* attachmentManager = &( aStore->AttachmentManagerL() );
CMsvAttachment* attachment = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
CleanupStack::PushL( attachment );
int attSize;
QString mimeType;
TMsgMediaType mediaType = EMsgMediaUnknown;
QString filepath = XQConversions::s60DescToQString( aFilePath );
iGenUtils->getFileInfoL(filepath, attSize, mimeType, mediaType);
attachment->SetSize( attSize );
attachment->SetMimeTypeL( *XQConversions::qStringToS60Desc8(mimeType) );
CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
attachmentManager->AddAttachmentL( aFilePath, attachment, wait->iStatus );
wait->Start();
CleanupStack::PopAndDestroy( wait );
CleanupStack::Pop( attachment );
aStore->CommitL();
}
// -----------------------------------------------------------------------------
// SetSmsSettingsL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetSmsSettingsL()
{
CSmsSettings* sendOptions = CSmsSettings::NewL();
CleanupStack::PushL( sendOptions );
// "ConvertToL" might be called right after constructor.
// In this case iSmsHeader is still NULL. Need to initialise.
if ( !iSmsHeader )
{
CMsvStore* store = SmsMtmL()->Entry().EditStoreL();
CleanupStack::PushL( store );
LoadHeadersL( store );
CleanupStack::PopAndDestroy( store );
}
iSmsHeader->GetSmsSettingsL( *sendOptions );
sendOptions->CopyL( *sendOptions );
if ( iBioMsg )
{
// make sure bio messages have no conversion
sendOptions->SetMessageConversion( ESmsConvPIDNone );
}
// Update some global SMS settings affecting all messages.
// These might have changed from the ones retrieved when
// the message was created and so needs to be updated.
CSmsSettings* defaultSettings = CSmsSettings::NewLC();
CSmsAccount* account = CSmsAccount::NewLC();
account->LoadSettingsL( *defaultSettings );
CleanupStack::PopAndDestroy( account );
sendOptions->SetDeliveryReport( defaultSettings->DeliveryReport() );
sendOptions->SetSmsBearer( defaultSettings->SmsBearer() );
sendOptions->SetValidityPeriod( defaultSettings->ValidityPeriod() );
sendOptions->SetReplyPath( defaultSettings->ReplyPath() );
if (defaultSettings->CharacterSet()
== TSmsDataCodingScheme::ESmsAlphabetUCS2)
{
iCharSupportType = TUniSendingSettings::EUniCharSupportFull;
}
else
{
iCharSupportType = TUniSendingSettings::EUniCharSupportReduced;
}
iSmsHeader->SetSmsSettingsL( *sendOptions );
// Move all the stuff from iSmsHeader::SmsSettings to SmsMtm::SmsHeader::SmsSettings
SmsMtmL()->SmsHeader( ).SetSmsSettingsL( *sendOptions );
//If sc is existant then only set the default service center
if(ValidateSCNumberL())
{
SmsMtmL()->SmsHeader( ).Message( ).
SetServiceCenterAddressL( defaultSettings->GetServiceCenter(defaultSettings->DefaultServiceCenter()).Address() );
}
CleanupStack::PopAndDestroy(defaultSettings);
CleanupStack::PopAndDestroy( sendOptions );
//Initialize the settings
SetEncodingSettingsL( iUnicodeMode, ESmsEncodingNone,
iCharSupportType);
//get bodytext
TInt smslength = SmsMtmL()->Body().LdDocumentLength();
HBufC* body = HBufC::NewLC(smslength);
TPtrC ptr;
ptr.Set(SmsMtmL()->Body().Read(0,smslength));
TInt numOfRemainingChars;
TInt numOfPDUs;
TBool unicodeMode;
TSmsEncoding alternativeEncodingType;
//This is to reset the charset type
GetNumPDUsL(ptr,numOfRemainingChars,numOfPDUs,
unicodeMode,alternativeEncodingType);
if (iNLTFeatureSupport)
{
//Turkish SMS-PREQ2265 Specific
TSmsEncoding currAlternateEncoding =
iSmsHeader->Message().Alternative7bitEncoding();
SmsMtmL()->SmsHeader().Message().SetAlternative7bitEncoding(
currAlternateEncoding);
}
//Write the settings into message header
TSmsUserDataSettings smsSettings;
CSmsMessage& smsMsg = SmsMtmL()->SmsHeader().Message();
if (iUnicodeMode)
{
smsSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabetUCS2);
}
else
{
smsSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet7Bit);
}
smsSettings.SetTextCompressed(EFalse);
smsMsg.SetUserDataSettingsL( smsSettings );
CleanupStack::PopAndDestroy(body);
}
// -----------------------------------------------------------------------------
// SendL
// @see header
// -----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SendL( TMsvId aId )
{
SmsMtmL()->SwitchCurrentEntryL( aId );
SmsMtmL()->LoadMessageL();
MoveMessagesToOutboxL();
}
// -----------------------------------------------------------------------------
// ValidateServiceL
// @see header
// -----------------------------------------------------------------------------
TBool UniEditorSmsPluginPrivate::ValidateServiceL( TBool aEmailOverSms )
{
TBool valid = ValidateSCNumberL();
if ( aEmailOverSms )
{
valid = ValidateSCNumberForEmailOverSmsL();
}
return valid;
}
// -----------------------------------------------------------------------------
// IsServiceValidL
// @see header
// -----------------------------------------------------------------------------
TBool UniEditorSmsPluginPrivate::IsServiceValidL()
{
// Not implemented.
return ETrue;
}
// -----------------------------------------------------------------------------
// SmsMtmL
// @see header
// -----------------------------------------------------------------------------
CSmsClientMtm* UniEditorSmsPluginPrivate::SmsMtmL()
{
if ( !iSmsMtm )
{
if ( !iMtmRegistry )
{
iMtmRegistry = CClientMtmRegistry::NewL( *iSession );
}
iSmsMtm = static_cast<CSmsClientMtm*>( iMtmRegistry->NewMtmL( KSenduiMtmSmsUid ) );
}
return iSmsMtm;
}
// ----------------------------------------------------------------------------
// MoveMessagesToOutboxL
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::MoveMessagesToOutboxL()
{
if ( !iRecipients || !iRecipients->Count() )
{
User::Leave( KErrGeneral );
}
// manage attachment and body content for sms
// e.g. in case of smartmsgs, we will need to populate attachment's
// content into msg body and discard the attachment
CMsvStore* store = SmsMtmL()->Entry().EditStoreL();
CleanupStack::PushL(store);
MMsvAttachmentManager* attachmentManager = &(store->AttachmentManagerL());
MMsvAttachmentManagerSync& managerSync =
store->AttachmentManagerExtensionsL();
TInt attCount = attachmentManager->AttachmentCount();
if (attCount > 1)
{
//Programming error in caller code
User::Leave(KErrArgument);
}
else if (attCount == 1)
{
// get mimetype
CMsgMediaResolver* mediaResolver = CMsgMediaResolver::NewL();
CleanupStack::PushL(mediaResolver);
mediaResolver->SetCharacterSetRecognition(EFalse);
RFile filehandle = mediaResolver->FileHandleL(
attachmentManager->GetAttachmentInfoL(0)->FilePath());
CleanupClosePushL(filehandle);
TPtrC8 mimetype;
TDataType datatype;
mediaResolver->RecognizeL(filehandle, datatype);
mimetype.Set(datatype.Des8());
if (mimetype.CompareF(KMsgMimeTextPlain) == 0)
{
CreatePlainTextSMSL(filehandle);
CleanupStack::Pop(&filehandle);
filehandle.Close();
managerSync.RemoveAttachmentL(0);
}
else if (mimetype.CompareF(KMsgMimeVCard) == 0)
{
CreateVCardSMSL(filehandle);
CleanupStack::Pop(&filehandle);
filehandle.Close();
}
else if (mimetype.CompareF(KMsgMimeVCal) == 0 ||
mimetype.CompareF(KMsgMimeICal) == 0)
{
CreateVCalSMSL(filehandle);
CleanupStack::Pop(&filehandle);
filehandle.Close();
managerSync.RemoveAttachmentL(0);
}
else
{
User::Leave(KErrArgument);
}
CleanupStack::PopAndDestroy(mediaResolver);
}
// commit changes
store->CommitL();
CleanupStack::PopAndDestroy(store);
//we must create an entry selection for message copies
CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
CleanupStack::PushL( selection );
CMsvEntry& entry = SmsMtmL()->Entry();
TMsvEntry msvEntry( entry.Entry() );
if ( iOfflineSupported && iGenUtils->IsPhoneOfflineL() )
{
msvEntry.SetSendingState( KMsvSendStateSuspended );
msvEntry.iError = KErrGsmOfflineOpNotAllowed;
}
else
{
msvEntry.SetSendingState( KMsvSendStateWaiting );
}
CSmsHeader& header = SmsMtmL()->SmsHeader();
TBuf<KSmsMessageEntryDescriptionAmountOfChars> buf;
if (!iBioMsg )
{
ExtractDescriptionFromMessageL(
header.Message(),
buf,
KSmsMessageEntryDescriptionAmountOfChars );
msvEntry.iDescription.Set( buf );
}
CSmsNumber* rcpt = CSmsNumber::NewL();
CleanupStack::PushL( rcpt );
TPtrC name;
TPtrC address;
TBool cantExit = ETrue;
while ( cantExit )
{
HBufC* addressBuf = NULL;
TPtr addressPtr( 0, 0);
NameAndAddress( iRecipients->MdcaPoint(0) , name, address );
// set To-field stuff into the Details of the entry
if ( name.Length() )
{
msvEntry.iDetails.Set( name );
}
else
{
// Internal data structures always holds the address data in western format.
// UI is responsible of doing language specific conversions.
addressBuf = HBufC::NewLC( address.Length() );
addressPtr.Set( addressBuf->Des() );
addressPtr.Copy( address );
iGenUtils->ConvertDigitsTo( addressPtr, EDigitTypeWestern );
msvEntry.iDetails.Set( addressPtr );
}
TMsvId copyId;
if ( iRecipients->Count() == 1 )
{
//Note that we came here also in case of many recipients. ...eventually.
if ( IsEmailAddress( address ) )
{
FillEmailInformationDataL( header, address );
//Let's remove the recipient and replace it with Email over SMS gateway address
//But let's first cehck if it exists
if( SmsMtmL( )->AddresseeList().Count() )
{
SmsMtmL( )->RemoveAddressee( 0 );
}
SmsMtmL()->AddAddresseeL(
iEmailOverSmsC->Address( ) ,
KNullDesC( ) );
}
else
{
InsertSubjectL( header, SmsMtmL()->Body() );
}
entry.ChangeL( msvEntry );
SmsMtmL()->SaveMessageL();
// Move it
copyId = MoveMessageEntryL( KMsvGlobalOutBoxIndexEntryId );
cantExit = EFalse;
}
else
{// Many recipients in array
// Own copy function for Emails
// This is because EmailOverSms messages can
// contain adresses longer than 21 digits
if ( IsEmailAddress( address ) )
{
copyId = CreateMessageInOutboxL(
msvEntry, address );
}
else // For MSISDN's
{
rcpt->SetAddressL( address );
if ( name.Length() )
{ // add name only if we have alias
rcpt->SetNameL( name );
}
copyId = CreateMessageInOutboxL(
msvEntry, *rcpt, SmsMtmL()->Body());
SmsMtmL()->RemoveAddressee( 0 );
}
//If hundreds of recipient, make sure viewserver
//timers are reseted
if ( iRecipients->Count() > 100 && ( iRecipients->Count() ) % 30 == 0 )
{
User::ResetInactivityTime();
}
iRecipients->Delete(0);
}
if ( addressBuf )
{
CleanupStack::PopAndDestroy( addressBuf );
}
// let's add the entry id into the cmsventryselection
selection->AppendL( copyId );
}
CleanupStack::PopAndDestroy( rcpt );
//Let's free some memory
if ( iRecipients )
{
delete iRecipients;
iRecipients = NULL;
}
SetScheduledSendingStateL( selection );
CleanupStack::PopAndDestroy( selection );
}
// ----------------------------------------------------------------------------
// MoveMessageEntryL
// @see header
// ----------------------------------------------------------------------------
TMsvId UniEditorSmsPluginPrivate::MoveMessageEntryL( TMsvId aTarget )
{
TMsvEntry msvEntry( SmsMtmL()->Entry().Entry() );
TMsvId id = msvEntry.Id();
if ( msvEntry.Parent() != aTarget )
{
TMsvSelectionOrdering sort;
sort.SetShowInvisibleEntries( ETrue );
CMsvEntry* parentEntry= CMsvEntry::NewL( *iSession, msvEntry.Parent(), sort );
CleanupStack::PushL( parentEntry );
// Copy original from the parent to the new location
CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
CMsvOperation* op = parentEntry->MoveL(
msvEntry.Id(),
aTarget,
wait->iStatus );
CleanupStack::PushL( op );
wait->Start();
TMsvLocalOperationProgress prog = McliUtils::GetLocalProgressL( *op );
User::LeaveIfError( prog.iError );
id = prog.iId;
CleanupStack::PopAndDestroy( op );
CleanupStack::PopAndDestroy( wait );
CleanupStack::PopAndDestroy( parentEntry );
}
return id;
}
// ----------------------------------------------------------------------------
// CreateMessageInOutboxL
// Use this function for non-email messages
// @see header
// ----------------------------------------------------------------------------
TMsvId UniEditorSmsPluginPrivate::CreateMessageInOutboxL(
const TMsvEntry& aEntry,
const CSmsNumber& aRecipient,
const CRichText& aBody )
{
// Initialize the richtext object
CRichText* richText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
CleanupStack::PushL( richText );
// Initialise header and store
CSmsHeader* header = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *richText );
CleanupStack::PushL( header );
CMsvStore* sourceStore = SmsMtmL()->Entry().ReadStoreL();
CleanupStack::PushL( sourceStore );
// Read store
header->RestoreL( *sourceStore );
// Initialise number with parameters
CSmsNumber* rcpt = CSmsNumber::NewL( aRecipient );
CleanupStack::PushL( rcpt );
header->Recipients().ResetAndDestroy();
header->Recipients().AppendL( rcpt );
CleanupStack::Pop( rcpt );
// Create entry to Outbox
TMsvEntry entry( aEntry );
entry.iMtmData3 = KSmsPluginBioMsgUnparsed;
CMsvEntry* outbox = iSession->GetEntryL( KMsvGlobalOutBoxIndexEntryId );
CleanupStack::PushL( outbox );
outbox->CreateL( entry );
iSession->CleanupEntryPushL( entry.Id() );
outbox->SetEntryL( entry.Id());
//Initialize target store
CMsvStore* targetStore;
targetStore = outbox->EditStoreL();
CleanupStack::PushL( targetStore );
//Add attachment
MMsvAttachmentManager& attaManager = sourceStore->AttachmentManagerL();
RFile tmpFile;
//Check if attachment exists and add it
if( sourceStore->AttachmentManagerL().AttachmentCount() )
{
tmpFile = attaManager.GetAttachmentFileL( 0 );
CleanupClosePushL( tmpFile );
MMsvAttachmentManager& targetAttaMan = targetStore->AttachmentManagerL();
CMsvAttachment* targetAtta = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
CleanupStack::PushL( targetAtta );
CMuiuOperationWait* waiter = CMuiuOperationWait::NewLC();
targetAttaMan.AddAttachmentL( tmpFile, targetAtta, waiter->iStatus );
waiter->Start();
CleanupStack::PopAndDestroy( waiter ); //waiter
CleanupStack::Pop(targetAtta );// targetAtta
CleanupStack::Pop( &tmpFile );//tmpFile
}
TInt totalLength( aBody.DocumentLength() );
HBufC* bodyText = HBufC::NewLC ( totalLength );
TPtr bodyTextPtr ( bodyText->Des() );
aBody.Extract( bodyTextPtr, 0, totalLength );
richText->InsertL( 0, bodyTextPtr );
CleanupStack::PopAndDestroy( bodyText );
InsertSubjectL( *header, *richText );
targetStore->StoreBodyTextL( *richText );
header->StoreL( *targetStore );
targetStore->CommitL();
// Usually SMCM takes care of updating iSize, but now when msg is
// created to Outbox for several recipients this has to be done manually.
entry.iSize = targetStore->SizeL();
entry.iRelatedId = iSmsServiceId;
entry.iServiceId = KMsvLocalServiceIndexEntryId;
outbox->ChangeL( entry );
CleanupStack::PopAndDestroy( targetStore );
iSession->CleanupEntryPop();
CleanupStack::PopAndDestroy( outbox );
CleanupStack::PopAndDestroy( sourceStore );
CleanupStack::PopAndDestroy( header );
CleanupStack::PopAndDestroy( richText );
return entry.Id();
}
// ---------------------------------------------------------
// CMsgSmsEditorAppUi::CreateMessageInOutboxL
// Creates message in outbox in case of multiple recipients
// with some e-mail over SMS addresses
// ---------------------------------------------------------
TMsvId UniEditorSmsPluginPrivate::CreateMessageInOutboxL(
const TMsvEntry& aEntry,
const TDesC& aAddress )
{
CRichText* richText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
CleanupStack::PushL( richText );
// Initialise header and store
CSmsHeader* header = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *richText );
CleanupStack::PushL( header );
CMsvStore* store = SmsMtmL()->Entry().ReadStoreL();
CleanupStack::PushL( store );
// Read store
header->RestoreL( *store );
CleanupStack::PopAndDestroy( store );
// Initialise number
CSmsNumber* rcpt = CSmsNumber::NewL();
CleanupStack::PushL( rcpt );
header->Recipients().ResetAndDestroy();
// Save Email specific information in header
FillEmailInformationDataL( *header, aAddress );
// Fill the recipient data for Email
// Address = Email gateway
// Alias = The real address
rcpt->SetAddressL( iEmailOverSmsC->Address() );
rcpt->SetNameL( aAddress ); // This takes only 21 chars
header->Recipients().AppendL( rcpt );
CleanupStack::Pop( rcpt );
// Create entry to Outbox
TMsvEntry entry( aEntry );
entry.iMtmData3 = KSmsPluginBioMsgUnparsed;
CMsvEntry* outbox = iSession->GetEntryL( KMsvGlobalOutBoxIndexEntryId );
CleanupStack::PushL( outbox );
outbox->CreateL( entry );
iSession->CleanupEntryPushL( entry.Id());
outbox->SetEntryL( entry.Id());
// Save
store = outbox->EditStoreL();
CleanupStack::PushL( store );
header->StoreL( *store );
richText->Reset();
richText->InsertL( 0 , SmsMtmL()->Body().Read( 0 ) );
store->StoreBodyTextL( *richText );
store->CommitL();
// Usually SMCM takes care of updating iSize, but now when msg is
// created to Outbox for several recipients this has to be done manually.
entry.iSize = store->SizeL();
entry.iRelatedId = iSmsServiceId;
entry.iServiceId = KMsvLocalServiceIndexEntryId;
outbox->ChangeL( entry );
CleanupStack::PopAndDestroy( store );
iSession->CleanupEntryPop();
CleanupStack::PopAndDestroy( outbox );
CleanupStack::PopAndDestroy( header );
CleanupStack::PopAndDestroy( richText );
return entry.Id();
}
// ----------------------------------------------------------------------------
// SetScheduledSendingStateL
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetScheduledSendingStateL( CMsvEntrySelection* aSelection )
{
const TMsvEntry msvEntry = SmsMtmL()->Entry().Entry();
if ( msvEntry.SendingState() == KMsvSendStateWaiting )
{
// Add entry to task scheduler
TBuf8<1> dummyParams;
CMuiuOperationWait* waiter = CMuiuOperationWait::NewLC();
waiter->iStatus = KRequestPending;
CMsvOperation* op= SmsMtmL()->InvokeAsyncFunctionL(
ESmsMtmCommandScheduleCopy,
*aSelection,
dummyParams,
waiter->iStatus );
CleanupStack::PushL( op );
waiter->Start();
CleanupStack::PopAndDestroy( op );
CleanupStack::PopAndDestroy( waiter );
}
}
// ----------------------------------------------------------------------------
// NameAndAddress
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::NameAndAddress( const TDesC& aMsvAddress, TPtrC& aName, TPtrC& aAddress )
{
TInt addressStart = aMsvAddress.LocateReverse( KMsgSmsAddressStartChar );
TInt addressEnd = aMsvAddress.LocateReverse( KMsgSmsAddressEndChar );
if ( addressStart != KErrNotFound && addressEnd != KErrNotFound
&& addressEnd > addressStart )
{
// verified address, will be used as selected from contacts manager
aName.Set( aMsvAddress.Ptr(), addressStart );
aAddress.Set(
aMsvAddress.Mid( addressStart + 1 ).Ptr(),
( addressEnd - addressStart ) -1 );
if ( !aAddress.Length())
{
aAddress.Set( aName );
aName.Set( KNullDesC ); // empty string
}
}
else
{
// unverified string, will be used as entered in the header field
aName.Set( KNullDesC ); // empty string
aAddress.Set( aMsvAddress.Ptr(), aMsvAddress.Length() ); // a whole string to address
}
if ( aName.CompareF( aAddress ) == 0 )
{
aName.Set( KNullDesC ); // empty string
}
}
// ----------------------------------------------------------------------------
// UniEditorSmsPluginPrivate::ExtractDescriptionFromMessageL
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::ExtractDescriptionFromMessageL(
const CSmsMessage& aMessage,
TDes& aDescription,
TInt aMaxLength)
{
// subject was already put in emailfields
HBufC* subject = SmsMtmL()->SmsHeader().EmailFields().Subject().AllocL();
if ( subject->Length() > 0 )
{
aDescription = subject->Des().Left(aMaxLength);
}
else
{// Extract from message body
aMessage.Buffer().Extract(
aDescription,
0,
Min(
aMaxLength,
aMessage.Buffer().Length()));
}
//replace paragraphs with spaces.
TBuf<KSmsEdExtrDescReplaceCharacterCount> replaceChars;
replaceChars.Zero();
replaceChars.Append( CEditableText::EParagraphDelimiter );
replaceChars.Append( KSmsEdUnicodeLFSupportedByBasicPhones );
replaceChars.Append( CEditableText::ELineBreak );
iGenUtils->ReplaceCharacters( aDescription, replaceChars, CEditableText::ESpace );
aDescription.Trim();
}
// ----------------------------------------------------------------------------
// CreatePlainTextSMSL
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::CreatePlainTextSMSL( RFile& aFile)
{
RFileReadStream stream( aFile );
CleanupClosePushL( stream );
CPlainText::TImportExportParam param;
param.iForeignEncoding = KCharacterSetIdentifierUtf8;
param.iOrganisation = CPlainText::EOrganiseByParagraph;
CPlainText::TImportExportResult result;
SmsMtmL()->Body().ImportTextL( 0, stream, param, result );
CleanupStack::PopAndDestroy( &stream );
}
// ----------------------------------------------------------------------------
// InsertSubjectL
// Insert subject for non email addresses into the body
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::InsertSubjectL( CSmsHeader& aHeader, CRichText& aText )
{
// subject was already put in emailfields
HBufC* subject = SmsMtmL()->SmsHeader().EmailFields().Subject().AllocL();
if ( ( subject->Length() > 0 ) && !iBioMsg )
{
CleanupStack::PushL(subject);
TInt writePosition = subject->Length()+2;//+2 for the parentesis
if ( subject->Locate( KUniSmsStartParenthesis )!= KErrNotFound ||
subject->Locate( KUniSmsEndParenthesis ) != KErrNotFound)
{
HBufC* modifiableSubject = subject->Alloc();
CleanupStack::PushL(modifiableSubject);
TPtr ptr = modifiableSubject->Des();
TBuf<1> replaceChars;
replaceChars.Zero();
replaceChars.Append( KUniSmsStartParenthesis );
// Replace '(' chars with '<'
iGenUtils->ReplaceCharacters( ptr, replaceChars, TChar('<') );
replaceChars.Zero();
replaceChars.Append( KUniSmsEndParenthesis );
// Replace ')' chars with '>'
iGenUtils->ReplaceCharacters( ptr, replaceChars, TChar('>') );
aText.InsertL( 0, KUniSmsStartParenthesis );
aText.InsertL( 1, ptr );
aText.InsertL( writePosition-1, KUniSmsEndParenthesis );
CleanupStack::PopAndDestroy( modifiableSubject );
}
else
{
aText.InsertL( 0, KUniSmsStartParenthesis );
aText.InsertL( 1, *subject );
aText.InsertL( writePosition-1, KUniSmsEndParenthesis );
}
}
// Clears the CSmsHeaders EmailFields for non Email addresses
CSmsEmailFields* emailFields = CSmsEmailFields::NewL();
CleanupStack::PushL( emailFields );
aHeader.SetEmailFieldsL( *emailFields );
CleanupStack::PopAndDestroy( emailFields );
}
// ----------------------------------------------------------------------------
// CreateVCardSMS
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::CreateVCardSMSL( RFile& aFile )
{
TInt fileSize;
TInt err ( aFile.Size( fileSize ) );
User::LeaveIfError(err);
// Create two buffers: 8-bit for reading from file and 16-bit for
// converting to 16-bit format
HBufC8* buf8 = HBufC8::NewLC( fileSize );
TPtr8 ptr8 = buf8->Des();
HBufC16* buf16 = HBufC16::NewLC( fileSize );
TPtr16 ptr16 = buf16->Des();
for (TInt err = aFile.Read(ptr8);
ptr8.Length() > 0;
err = aFile.Read(ptr8))
{
User::LeaveIfError(err);
ptr16.Copy(ptr8);
SmsMtmL()->Body().InsertL(SmsMtmL()->Body().DocumentLength(), ptr16);
}
// Cleanup and return
CleanupStack::PopAndDestroy( buf16 );
CleanupStack::PopAndDestroy( buf8 );
}
// ----------------------------------------------------------------------------
// CreateVCalSMS
// @see header
// ----------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::CreateVCalSMSL( RFile& aFile )
{
TInt err (KErrNone);
TInt fileSize;
err = aFile.Size( fileSize );
User::LeaveIfError(err);
HBufC8* buf8 = HBufC8::NewLC( fileSize );
TPtr8 ptr8 = buf8->Des();
err = aFile.Read( ptr8 );
User::LeaveIfError(err);
HBufC16* buf16 = HBufC16::NewLC( fileSize );
TPtr16 ptr16 = buf16->Des();
ptr16.Copy(ptr8);
SmsMtmL()->Body().InsertL(0, ptr16);
CleanupStack::PopAndDestroy( buf16 );
CleanupStack::PopAndDestroy( buf8 );
}
// ----------------------------------------------------------------------------
// UniEditorSmsPluginPrivate::ValidateSCNumberL
// @see header
// ----------------------------------------------------------------------------
TBool UniEditorSmsPluginPrivate::ValidateSCNumberL()
{
TBool valid( EFalse );
CSmsAccount* smsAccount = CSmsAccount::NewLC();
CSmsSettings* settings = CSmsSettings::NewLC();
smsAccount->LoadSettingsL(*settings);
int serviceCenterCount = settings->ServiceCenterCount();
if( serviceCenterCount > 0 )
{
TInt defaultIndex = settings->DefaultServiceCenter();
if( settings->GetServiceCenter(defaultIndex).Address().Length() > 0 )
{
valid = ETrue;
}
}
else if(settings->ReplyPath())
{
valid = ETrue;
}
CleanupStack::PopAndDestroy(2);
return valid;
}
// ---------------------------------------------------------
// UniEditorSmsPluginPrivate::ValidateSCNumberForEmailOverSmsL
// @see header
// ---------------------------------------------------------
TBool UniEditorSmsPluginPrivate::ValidateSCNumberForEmailOverSmsL()
{
TBool confNeeded( EFalse );
// Read the email settings
TBuf<KUniSmsSCStringLength> emailSmscNumber;
TBuf<KUniSmsSCStringLength> emailGateWayNumber;
TBool notUsed( EFalse );
// The file may not exist
TInt readResult = iGenUtils->ReadEmailOverSmsSettingsL(
emailSmscNumber,
emailGateWayNumber,
notUsed );
if ( KErrNone == readResult )
{
// Check that both have valid values
// In any otther case we need to show the conf pop-up window
if ( emailSmscNumber != KNullDesC && emailGateWayNumber != KNullDesC)
{
confNeeded = ETrue;
}
}
return confNeeded;
}
// ---------------------------------------------------------
// UniEditorSmsPluginPrivate::FillEmailInformationDataL
// @see header
// ---------------------------------------------------------
void UniEditorSmsPluginPrivate::FillEmailInformationDataL(
CSmsHeader& aHeader,
const TPtrC& aAddress )
{
CSmsEmailFields* emailFields = CSmsEmailFields::NewL();
CleanupStack::PushL( emailFields );
// The Email SMSC may differ from sms SMSC
aHeader.Message().SetServiceCenterAddressL( iEmailOverSmsC->Name() );
// Check if there is need to save as EmailFieds with header
if ( aAddress.Length() )
{
// Set the address
emailFields->AddAddressL( aAddress );
}
// subject was already put in emailfields
HBufC* subject = SmsMtmL()->SmsHeader().EmailFields().Subject().AllocL();
if ( subject->Length() > 0 )
{ // Handle the subject
CleanupStack::PushL( subject );
TPtr text = subject->Des();
TBuf<1> replaceChars;
replaceChars.Zero();
replaceChars.Append( KUniSmsStartParenthesis );
// Replace '(' chars with '<'
iGenUtils->ReplaceCharacters( text, replaceChars, TChar('<') );
replaceChars.Zero();
replaceChars.Append( KUniSmsEndParenthesis );
// Replace ')' chars with '>'
iGenUtils->ReplaceCharacters( text, replaceChars, TChar('>') );
// For Emails save it to CSmsEmailFields
emailFields->SetSubjectL( text );
CleanupStack::PopAndDestroy( subject );
}
aHeader.SetEmailFieldsL( *emailFields );
CleanupStack::PopAndDestroy( emailFields );
}
// ----------------------------------------------------
// UniEditorSmsPluginPrivate::IsEmailAddress()
// @see header
// ----------------------------------------------------
TBool UniEditorSmsPluginPrivate::IsEmailAddress( const TPtrC& aAddress ) const
{
TBool isEmailAddress( EFalse );
if ( aAddress.Locate('@') != KErrNotFound)
{
isEmailAddress = ETrue;
}
return isEmailAddress;
}
//------------------------------------------------------------------------------
// UniEditorSmsPluginPrivate::SetEncodingSetings
// Turkish SMS-PREQ2265 Specific
// To Set encoding settings like encoding type, character support
// and alternative encoding if any
//
// IMPORTANT NOTE:
// This function is usually called from CV and UE to reset/set alternative
// encoding or char support
// when corresponding feilds change. Hence aUnicodeMode is always set to false
//------------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::SetEncodingSettingsL( TBool aUnicodeMode,
TSmsEncoding aAlternativeEncodingType,
TInt aCharSupportType)
{
if ( !iSmsHeader )
{
iSmsHeader = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *iRichText );
CSmsSettings* settings = CSmsSettings::NewLC();
CSmsAccount* account = CSmsAccount::NewLC();
account->LoadSettingsL( *settings );
CleanupStack::PopAndDestroy( account );
iSmsHeader->SetSmsSettingsL( *settings );
CleanupStack::PopAndDestroy( settings );
}
TSmsUserDataSettings smsSettings;
CSmsMessage& smsMsg = iSmsHeader->Message();
iUnicodeMode = aUnicodeMode;
iCharSupportType = aCharSupportType;
iAlternativeEncodingType = aAlternativeEncodingType;
if (iUnicodeMode)
{
smsSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabetUCS2);
}
else
{
smsSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet7Bit);
}
smsSettings.SetTextCompressed(EFalse);
smsMsg.SetUserDataSettingsL( smsSettings );
//First try without any alternate encoding
smsMsg.SetAlternative7bitEncoding( aAlternativeEncodingType );
}
//------------------------------------------------------------------------------
// UniEditorSmsPluginPrivate::GetNumPDUs
// Turkish SMS-PREQ2265 Specific
// To get PDU Info: extracts details of number of PDUs, number of remaining
// chars in last PDU
// and encoding types used.
//------------------------------------------------------------------------------
void UniEditorSmsPluginPrivate::GetNumPDUsL(
TDesC& aBuf,
TInt& aNumOfRemainingChars,
TInt& aNumOfPDUs,
TBool& aUnicodeMode,
TSmsEncoding & aAlternativeEncodingType )
{
TInt numOfUnconvChars, numOfDowngradedChars, isAltEncSupported;
TSmsEncoding currentAlternativeEncodingType;
CSmsMessage& smsMsg = iSmsHeader->Message();
// need to set the input buffer to SMS buffer through iRichText(which is reference to SMS Buffer object)
iRichText->Reset();
iRichText->InsertL(0, aBuf);
//call SMS stack API to get PDU info
smsMsg.GetEncodingInfoL( aNumOfPDUs, numOfUnconvChars, numOfDowngradedChars, aNumOfRemainingChars );
//Algo to switch to Unicode if required
while( (numOfUnconvChars || numOfDowngradedChars) && !iUnicodeMode )
{
currentAlternativeEncodingType = smsMsg.Alternative7bitEncoding();
if( currentAlternativeEncodingType != iAlternativeEncodingType )
{
//try with this new alternative encoding type
isAltEncSupported = smsMsg.SetAlternative7bitEncoding( iAlternativeEncodingType );
if( isAltEncSupported == KErrNotSupported )
{
// if required alternative encoding plugin is not supported, retain the existing encoding mechanism.
iAlternativeEncodingType = currentAlternativeEncodingType;
continue;
}
}
else if( numOfUnconvChars || iCharSupportType == TUniSendingSettings::EUniCharSupportFull)
{
//switch to Unicode
//iUnicodeMode = ETrue;
SetEncodingSettingsL( ETrue, iAlternativeEncodingType, TUniSendingSettings::EUniCharSupportFull);
}
else
{
//Get out of while loop and return the results
break;
}
//get the PDU info with new settings
iRichText->Reset();
iRichText->InsertL(0, aBuf);
smsMsg.GetEncodingInfoL( aNumOfPDUs, numOfUnconvChars, numOfDowngradedChars, aNumOfRemainingChars );
}
/*
* Enable the below code to debug if something wrong with characters sent even in unicode mode
*/
aUnicodeMode = iUnicodeMode;
aAlternativeEncodingType = iAlternativeEncodingType;
if(iUnicodeMode)
{
//In case of Unicode mode, SMS Stack returns number of available free User Data units.
//Need to convert them w.r.t characters(each char takse 2 UD units).
aNumOfRemainingChars = aNumOfRemainingChars/2;
}
}
// ----------------------------------------------------
// UniEditorSmsPluginPrivate::DeleteDraftsEntryL()
// @see header
// ----------------------------------------------------
void UniEditorSmsPluginPrivate::DeleteDraftsEntryL( TMsvId aId )
{
CMsvEntry* pEntry = iSession->GetEntryL(KMsvDraftEntryIdValue);
CleanupStack::PushL(pEntry);
pEntry->DeleteL( aId );
CleanupStack::PopAndDestroy(pEntry);
}
// ----------------------------------------------------
// UniEditorSmsPluginPrivate::populateRecipientsL()
// @see header
// ----------------------------------------------------
void UniEditorSmsPluginPrivate::populateRecipientsL(
ConvergedMessage *aMessage)
{
TPtrC name;
TPtrC address;
const CSmsEmailFields& emailFields = SmsMtmL( )->SmsHeader( ).EmailFields();
if( emailFields.HasAddress( ))
{ // If email address set -> copy them here
const MDesCArray& emailRecipients = emailFields.Addresses();
for( TInt id = 0; id < emailRecipients.MdcaCount( ); id++ )
{
HBufC* pureAddr = TMmsGenUtils::PureAddress( emailRecipients.MdcaPoint( id ) ).AllocLC();
HBufC* aliasAddr = TMmsGenUtils::Alias( emailRecipients.MdcaPoint( id ) ).AllocLC();
ConvergedMessageAddress messageAddress(
XQConversions::s60DescToQString(*pureAddr),
XQConversions::s60DescToQString(*aliasAddr));
CleanupStack::PopAndDestroy(2, pureAddr );
aMessage->addToRecipient(messageAddress);
}
}
// Copy non-email over sms addresses if needed
const CMsvRecipientList& smsRecipients = SmsMtmL()->AddresseeList();
int smsRecCount = smsRecipients.Count();
for (int i = 0; i < smsRecCount; i++)
{ // Go thru all the recipients
if( !emailFields.HasAddress( ) )
{ // and copy them only if email addresses did not exist
HBufC* pureAddr =
TMmsGenUtils::PureAddress(smsRecipients[i]).AllocLC();
HBufC* aliasAddr =
TMmsGenUtils::Alias(smsRecipients[i]).AllocLC();
ConvergedMessageAddress messageAddress(
XQConversions::s60DescToQString(*pureAddr),
XQConversions::s60DescToQString(*aliasAddr));
CleanupStack::PopAndDestroy(2, pureAddr );
aMessage->addToRecipient(messageAddress);
}
}
if( emailFields.Subject( ).Length( ) )
{ // If email subject exists -> copy it
aMessage->setSubject(XQConversions::s60DescToQString(
emailFields.Subject()));
}
}
// ----------------------------------------------------
// UniEditorSmsPluginPrivate::populateMessageBodyL()
// @see header
// ----------------------------------------------------
void UniEditorSmsPluginPrivate::populateMessageBodyL(
ConvergedMessage* aMessage,
TMsvEntry &aEntry)
{
if ( aEntry.iBioType == KMsgBioUidVCard.iUid
|| aEntry.iBioType == KMsgBioUidVCalendar.iUid )
{
//In case of drafts the vcal is present inside msg store and
//can be read directly
if(aEntry.Parent() == KMsvDraftEntryIdValue)
{
//In case of drafts the vcf/vcs file is stored inside store
//so we can directly extract it
CMsvStore* store = SmsMtmL()->Entry().EditStoreL();
CleanupStack::PushL( store );
MMsvAttachmentManager& manager = store->AttachmentManagerL();
CMsvAttachment *attachment = manager.GetAttachmentInfoL(0);
QString filepath = XQConversions::s60DescToQString(attachment->FilePath());
ConvergedMessageAttachment* conv_attachment =
new ConvergedMessageAttachment(filepath, ConvergedMessageAttachment::EAttachment);
ConvergedMessageAttachmentList conv_attList;
conv_attList << conv_attachment;
aMessage->addAttachments(conv_attList);
CleanupStack::PopAndDestroy( store );
}
else
{
//For non drafts cases extract the vcf/vcs using datamodel interface
UniDataModelLoader* pluginLoader = new UniDataModelLoader();
UniDataModelPluginInterface* pluginInterface =
pluginLoader->getDataModelPlugin(ConvergedMessage::BioMsg);
pluginInterface->setMessageId(aEntry.Id());
UniMessageInfoList attachments = pluginInterface->attachmentList();
QString attachmentPath = attachments[0]->path();
ConvergedMessageAttachment* conv_attachment =
new ConvergedMessageAttachment(attachmentPath, ConvergedMessageAttachment::EAttachment);
ConvergedMessageAttachmentList conv_attList;
conv_attList << conv_attachment;
aMessage->addAttachments(conv_attList);
foreach(UniMessageInfo* attachment,attachments)
{
delete attachment;
}
delete pluginLoader;
}
}
else //plain text
{
TInt totalLength( SmsMtmL()->Body().DocumentLength() );
if ( totalLength > 0 )
{
HBufC* bodyText = HBufC::NewLC ( totalLength );
TPtr bodyTextPtr ( bodyText->Des() );
SmsMtmL()->Body().Extract( bodyTextPtr, 0, totalLength );
aMessage->setBodyText(XQConversions::s60DescToQString(
bodyTextPtr));
CleanupStack::PopAndDestroy( bodyText );
}
}
}
// ----------------------------------------------------
// UniEditorSmsPluginPrivate::HandleSessionEventL()
// @see header
// ----------------------------------------------------
void UniEditorSmsPluginPrivate::HandleSessionEventL(TMsvSessionEvent /*aEvent*/,
TAny* /*aArg1*/,
TAny* /*aArg2*/, TAny* /*aArg3*/)
{
// do nothing
}
// End of File