diff -r 4697dfb2d7ad -r 238255e8b033 messagingappbase/smsmtm/clientmtm/src/SMUTHDR.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingappbase/smsmtm/clientmtm/src/SMUTHDR.CPP Fri Apr 16 14:56:15 2010 +0300 @@ -0,0 +1,1075 @@ +// Copyright (c) 1999-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 +#include +#include + +#include +#include +#include +#include +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif + +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) +#include +#endif + +const TUid KUidMsvSMSHeaderStream = {0x10001834}; +const TInt16 KMsvSmsHeaderVersion = 1; +const TInt KSmcmRecipientsGranularity = 8; +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) +_LIT16(KComma, ","); +_LIT16(KDelimiter, ";"); +#endif + +/** +Allocates and constructs a new CSmsHeader object. + +Use this function to create a new SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or +SMS-STATUS-REPORT type message. + +@param aType +The Protocol Data Unit (PDU) type for the SMS message. + +@param aText +The message text. + +@return +A new CSmsHeader object. +*/ +EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsPDU::TSmsPDUType aType, CEditableText& aText) + { + CSmsHeader* self = new(ELeave) CSmsHeader(); + CleanupStack::PushL(self); + self->ConstructL(aType, aText); + CleanupStack::Pop(self); + return self; + } + +/** +Allocates and constructs a new CSmsHeader object. + +Use this function to create a new SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or +SMS-STATUS-REPORT type message. This version uses a previously connected +file server session handle. + +@param aType +The Protocol Data Unit (PDU) type for the SMS message. + +@param aText +The message text. + +@param aFs +Handle to an open file server session. CSmsHeader will not close the file session. + +@return +A new CSmsHeader object. +*/ +EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsPDU::TSmsPDUType aType, CEditableText& aText, RFs& aFs) + { + CSmsHeader* self = new(ELeave) CSmsHeader(); + CleanupStack::PushL(self); + self->ConstructL(aType, aText, aFs); + CleanupStack::Pop(self); + return self; + } + +/** +Allocates and constructs a new CSmsHeader object. + +Use this function to create a new SMS-DELIVER type message. + +@param aMessage +The SMS message encapsulation from the SMS stack. + +@return +A new CSmsHeader object. +*/ +EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsMessage* aMessage) + { + CSmsHeader* self = new(ELeave) CSmsHeader(aMessage); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Destructor. +*/ +EXPORT_C CSmsHeader::~CSmsHeader() + { + iRecipients.ResetAndDestroy(); + delete iMessage; + delete iEmailFields; + if(iCloseFs) + { + iFs.Close(); + } + } + +/** +Sets the SMS message settings for the message. + +This can only be used on SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or SMS-STATUS-REPORT +type messages. + +NOTE - if this is an Email over SMS message then the PID of is not changed. The +PID would have been set correctly when the email fields were set. + +@param aSmsSettings +The SMS message settings for the message + +@leave KErrNotSupported +The message PDU type was not supported, or the message conversion value was not +supported. + +@panic SMCM 0 +The message PDU is not supported (debug only). +*/ +EXPORT_C void CSmsHeader::SetSmsSettingsL(const CSmsMessageSettings& aSmsSettings) + { + __ASSERT_DEBUG( (Type()==CSmsPDU::ESmsSubmit) || (Type()==CSmsPDU::ESmsDeliver) || (Type()==CSmsPDU::ESmsStatusReport) || (Type()==CSmsPDU::ESmsCommand), Panic(ESmutPanicUnsupportedMsgType)); + + switch(Type()) + { + case(CSmsPDU::ESmsSubmit): + { + Submit().SetRejectDuplicates(aSmsSettings.RejectDuplicate()); + Submit().SetReplyPath(aSmsSettings.ReplyPath()); + + //Check if delivery report for the last segment only is required . + if(aSmsSettings.LastSegmentDeliveryReport()) + { + CSmsTPSRROperations& tpSRROperations = static_cast(iMessage->GetOperationsForNonIEL(ESmsTPSRRParameter)); + tpSRROperations.SetSchemeL(); + tpSRROperations.SetLastSegmentStatusReportL(ETrue); + } + else + { + Submit().SetStatusReportRequest(aSmsSettings.DeliveryReport()); + } + Submit().SetValidityPeriod(aSmsSettings.ValidityPeriod()); + Submit().SetValidityPeriodFormat(aSmsSettings.ValidityPeriodFormat()); + break; + } + case(CSmsPDU::ESmsCommand): + { + Command().SetStatusReportRequest(aSmsSettings.DeliveryReport()); + break; + } + case(CSmsPDU::ESmsDeliver): + case(CSmsPDU::ESmsStatusReport): + break; + default: + { + User::Leave(KErrNotSupported); + break; + } + }; + + if (Message().TextPresent()) + SetCanConcatenate(aSmsSettings.CanConcatenate()); + + CSmsPDU& pdu=Message().SmsPDU(); + if (pdu.DataCodingSchemePresent()) + pdu.SetAlphabet(aSmsSettings.CharacterSet()); + if (pdu.ProtocolIdentifierPresent() && iEmailFields->Length() == 0 ) + { + // The email fields object for this message is empty - therefore the + // PID can be set. With a non-empty email fields object the PID would + // have been set for interworking with email and MUST not be changed. + pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking); + + // MessageConversion + switch(aSmsSettings.MessageConversion()) + { + case(ESmsConvPIDNone): + { + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsNoTelematicDevice); + break; + } + case ESmsConvFax: + case ESmsConvX400: + case ESmsConvPaging: + case ESmsConvMail: + case ESmsConvErmes: + case ESmsConvSpeech: + { + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice); + pdu.SetTelematicDeviceType((TSmsProtocolIdentifier::TSmsTelematicDeviceType) aSmsSettings.MessageConversion()); + break; + } + default: + { + User::Leave(KErrNotSupported); + break; + } + }; + } + } + +/** +Gets the SMS message settings for the message. + +This can only be used on SMS-SUBMIT type messages. + +@param aSmsSettings +The output argument with the SMS message settings. + +@leave KErrNotSupoprted +The Telematic Device type is not supported. + +@panic SMCM 0 +The message PDU is not supported (debug only). +*/ +EXPORT_C void CSmsHeader::GetSmsSettingsL(CSmsMessageSettings& aSmsSettings) const + { + __ASSERT_DEBUG( Type()==CSmsPDU::ESmsSubmit, Panic(ESmutPanicUnsupportedMsgType)); + switch(Type()) + { + case(CSmsPDU::ESmsSubmit): + { + aSmsSettings.SetRejectDuplicate(Submit().RejectDuplicates()); + aSmsSettings.SetReplyPath(Submit().ReplyPath()); + TSmsStatusReportScheme scheme = iMessage->Scheme(); + if (scheme == ETPSRRScheme) + { + aSmsSettings.SetLastSegmentDeliveryReport(ETrue); + } + else + { + aSmsSettings.SetDeliveryReport(Submit().StatusReportRequest()); + } + aSmsSettings.SetValidityPeriod(Submit().ValidityPeriod()); + aSmsSettings.SetValidityPeriodFormat(Submit().ValidityPeriodFormat()); + aSmsSettings.SetCharacterSet(Submit().Alphabet()); + + if (iMessage->SmsPDU().PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking) + { + if (iMessage->SmsPDU().TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsNoTelematicDevice) + { + aSmsSettings.SetMessageConversion(ESmsConvPIDNone); + } + else //if (iMessage->SmsPDU().TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice) + { + switch (iMessage->SmsPDU().TelematicDeviceType()) + { + case TSmsProtocolIdentifier::ESmsGroup3TeleFax: + case TSmsProtocolIdentifier::ESmsX400MessageHandlingSystem: + case TSmsProtocolIdentifier::ESmsNationalPagingSystem: + case TSmsProtocolIdentifier::ESmsInternetElectronicMail: + case TSmsProtocolIdentifier::ESmsERMES: + case TSmsProtocolIdentifier::ESmsVoiceTelephone: + aSmsSettings.SetMessageConversion((TSmsPIDConversion) iMessage->SmsPDU().TelematicDeviceType()); + break; + default: + User::Leave(KErrNotSupported); + break; + } + } + } + + aSmsSettings.SetCanConcatenate(CanConcatenate()); + break; + } + default: + { + break; + } + } + } + +/** +Sets the email fields for the message. + +If the supplied email fields is not empty then the PID of the PDU of the message +is set for interworking with email. + +If the supplied email fields is empty and the PID of the PDU of the message is +set for interworking with email then the PID is set to the default value that +indicates no telematic device. If the PID was not set for interworking with +email then it is left unchanged. + +@param aEmailFields +The email fields object. A copy is made of this object. +*/ +EXPORT_C void CSmsHeader::SetEmailFieldsL(const CSmsEmailFields& aEmailFields) + { + __ASSERT_DEBUG( Type()==CSmsPDU::ESmsSubmit, Panic(ESmutPanicUnsupportedMsgType)); + + CSmsEmailFields* temp = CSmsEmailFields::NewL(aEmailFields); + delete iEmailFields; + iEmailFields = temp; + + CSmsPDU& pdu = Message().SmsPDU(); + if( pdu.ProtocolIdentifierPresent() ) + { + if( iEmailFields->Length() > 0 ) + { + // Set the PID for interworking with email. + pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking); + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice); + pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail); + } + else + { + // The email fields are empty - if the PID is set for interworking + // with email, set to indicate no telematic device. + if( pdu.PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking && + pdu.TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice && + pdu.TelematicDeviceType() == TSmsProtocolIdentifier::ESmsInternetElectronicMail ) + { + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsNoTelematicDevice); + } + } + } + } + +/** +Sets the email fields for a reply message. + +The address field is copied from the specified email fields. The subject field +is formatted according to the specified subject format using the subject from +the specified email fields. + +The PID of the PDU of the message is set for interworking with email. + +@param aEmailFields +The email fields object. + +@param aReplySubjectFormat +The format of the subject field. + +@internalComponent +*/ +void CSmsHeader::SetReplyEmailFieldsL(const CSmsEmailFields& aEmailFields, const TDesC& aReplySubjectFormat) + { + // Create the reply email fields - copy address and then format the subject, + // if one exists according to the reply prefix. + CSmsEmailFields* temp = CSmsEmailFields::NewL(); + CleanupStack::PushL(temp); + temp->AddAddressL(aEmailFields.Addresses().MdcaPoint(0)); + + SetEmailReplyForwardSubjectL(temp, aEmailFields.Subject(), aReplySubjectFormat); + + CleanupStack::Pop(temp); + delete iEmailFields; + iEmailFields = temp; + + // Set the PID for interworking with email. + CSmsPDU& pdu = Message().SmsPDU(); + if( pdu.ProtocolIdentifierPresent() ) + { + pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking); + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice); + pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail); + } + } + +/** +Sets the email fields for a forward message. + +The address field is left empty. The subject field is formatted according to the +specified subject format using the subject from the specified email fields. + +The PID of the PDU of the message is set for interworking with email. + +@param aEmailFields +The email fields object. + +@param aForwardSubjectFormat +The format of the subject field. + +@internalComponent +*/ +void CSmsHeader::SetForwardEmailFieldsL(const CSmsEmailFields& aEmailFields, const TDesC& aForwardSubjectFormat) + { + // Create the reply email fields - copy address and then format the subject, + // if one exists according to the reply prefix. + CSmsEmailFields* temp = CSmsEmailFields::NewL(); + CleanupStack::PushL(temp); + + SetEmailReplyForwardSubjectL(temp, aEmailFields.Subject(), aForwardSubjectFormat); + + CleanupStack::Pop(temp); + delete iEmailFields; + iEmailFields = temp; + + // Set the PID for interworking with email. + CSmsPDU& pdu = Message().SmsPDU(); + if( pdu.ProtocolIdentifierPresent() ) + { + pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking); + pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice); + pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail); + } + } + +void CSmsHeader::SetEmailReplyForwardSubjectL(CSmsEmailFields* aEmailFields, const TDesC& aSubject, const TDesC& aSubjectFormat) + { + TInt length = aSubject.Length(); + if( length > 0 ) + { + // Prevent a chain of the format string appearing in the subject - check + // to see if the format string is already the prefix of the subject. + TInt formatPosInSubject = KErrNotFound; + + _LIT(KFormatStringSpecifier, "%S"); + TInt formatPos = aSubjectFormat.Find(KFormatStringSpecifier); + if( formatPos > 0 ) + { + // Look in current subject for the format string - avoid the '%'. + formatPosInSubject = aSubject.FindF(aSubjectFormat.Left(formatPos - 1)); + } + + // Need to format the string if the format string is not at the start of + // the current subject. + if( formatPosInSubject != 0 ) + { + // Create a buffer large enough to hold re-formated subject - need + // to subtract two from the prefix length (the %S). + length += aSubjectFormat.Length() - 2; + HBufC* buf = HBufC::NewLC(length); + TPtr ptr(buf->Des()); + + // Format the reply subject and set in the email fields. + ptr.Format(aSubjectFormat, &aSubject); + aEmailFields->SetSubjectL(*buf); + + CleanupStack::PopAndDestroy(buf); + } + else + { + // Subject already contains the format string - use it. + aEmailFields->SetSubjectL(aSubject); + } + } + } + +/** +The email fields object for this message. + +@return +The email fields object for this message. +*/ +EXPORT_C const CSmsEmailFields& CSmsHeader::EmailFields() const + { + return *iEmailFields; + } + +/** +Internalises the object from the specified stream. + +@param aStream +The stream to be read from. +*/ +EXPORT_C void CSmsHeader::InternalizeL(RMsvReadStream& aStream) + { +#if (!defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + + aStream.ReadInt16L(); //version. Not used yet + + iRecipients.ResetAndDestroy(); + TInt count=aStream.ReadInt32L(); + while(count--) + { + CSmsNumber* recipient=CSmsNumber::NewL(); + CleanupStack::PushL(recipient); + recipient->InternalizeL(aStream); + iRecipients.AppendL(recipient); + CleanupStack::Pop(recipient); + } + + iFlags = aStream.ReadUint32L(); + iBioMsgIdType = (TBioMsgIdType) aStream.ReadInt8L(); + iMessage->InternalizeWithoutBufferL(aStream); +#else + iMessage->InternalizeWithoutBufferL(aStream); +#endif + } + +/** +Externalises the object to the specified stream. + +@param aStream +The stream to be writen to. +*/ +EXPORT_C void CSmsHeader::ExternalizeL(RMsvWriteStream& aStream) const + { +#if (!defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + + aStream.WriteInt16L(KMsvSmsHeaderVersion); + + TInt count=iRecipients.Count(); + aStream.WriteInt32L(count); + + for (TInt i=0; iExternalizeL(aStream); + + aStream.WriteUint32L(iFlags); + aStream.WriteInt8L(iBioMsgIdType); + iMessage->ExternalizeWithoutBufferL(aStream); +#else + iMessage->ExternalizeWithoutBufferL(aStream); +#endif + } + +/** +Restores the object from the message entry store. + +The SMS object is restored from the KUidMsvSMSHeaderStream in the supplied store. + +@param aStore +The store from which the object is restored. + +@leave KErrNotFound +The stream KUidMsvSMSHeaderStream does not exist in aStore. +*/ +EXPORT_C void CSmsHeader::RestoreL(CMsvStore& aStore) + { +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + ReStoreDBL(aStore); + RMsvReadStream in; + in.OpenLC(aStore,KUidMsvSMSHeaderStream); + InternalizeL(in); + CleanupStack::PopAndDestroy(&in); +#else + + RMsvReadStream in; + in.OpenLC(aStore,KUidMsvSMSHeaderStream); + InternalizeL(in); + CleanupStack::PopAndDestroy(&in); + + iEmailFields->RestoreL(aStore); + +#endif + } + + +/** +Stores the object in the message entry store. + +The object is written to the KUidMsvSMSHeaderStream stream. Any previous content +is overwritten. + +@param aStore +The store to hold the stream into which the object is written. +*/ +EXPORT_C void CSmsHeader::StoreL(CMsvStore& aStore) const + { +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + StoreDbL(aStore); + RMsvWriteStream out; + out.AssignLC(aStore,KUidMsvSMSHeaderStream); + ExternalizeL(out); + out.CommitL(); + CleanupStack::PopAndDestroy(&out); + +#else + RMsvWriteStream out; + out.AssignLC(aStore,KUidMsvSMSHeaderStream); + ExternalizeL(out); + out.CommitL(); + CleanupStack::PopAndDestroy(&out); + + iEmailFields->StoreL(aStore); +#endif + } + + +/** +Check whether a CMsvStore contains an SMS header stream. + +@param aStore The store. +@return ETrue if there is a SMS header +*/ +EXPORT_C TBool CSmsHeader::ContainsSmsHeaderL(const CMsvStore& aStore) + { + return aStore.IsPresentL(KUidMsvSMSHeaderStream); + } + +CSmsHeader::CSmsHeader(CSmsMessage* aSmsMessage) +: iRecipients(KSmcmRecipientsGranularity), + iMessage(aSmsMessage), + iFlags(ESmsHeaderNoFlags), + iBioMsgIdType(EBioMsgIdNbs), + iCloseFs(ETrue) + { + } + +void CSmsHeader::ConstructL(CSmsPDU::TSmsPDUType aType, CEditableText& aText) + { + User::LeaveIfError(iFs.Connect()); + iMessage=CSmsMessage::NewL(iFs, aType, CSmsEditorBuffer::NewL(aText), EFalse); + iEmailFields = CSmsEmailFields::NewL(); + } + +void CSmsHeader::ConstructL(CSmsPDU::TSmsPDUType aType, CEditableText& aText, RFs& aFs) + { + iFs=aFs; + iCloseFs = EFalse; + iMessage=CSmsMessage::NewL(iFs, aType, CSmsEditorBuffer::NewL(aText), EFalse); + iEmailFields = CSmsEmailFields::NewL(); + } + +void CSmsHeader::ConstructL() + { + iEmailFields = CSmsEmailFields::NewL(); + + // Check the PID of the SMS PDU to see if set for interworking with email. + CSmsPDU& pdu = Message().SmsPDU(); + if( pdu.ProtocolIdentifierPresent() && + pdu.PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking && + pdu.TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice && + pdu.TelematicDeviceType() == TSmsProtocolIdentifier::ESmsInternetElectronicMail ) + { + __ASSERT_DEBUG( pdu.Type() == CSmsPDU::ESmsDeliver, User::Invariant() ); + + // Ok, this is an email SMS - parse out the address and the optional + // subject fields. + CSmsBufferBase& message = Message().Buffer(); + TInt length = message.Length(); + HBufC* buf = HBufC::NewLC(length); + TPtr bufPtr(buf->Des()); + message.Extract(bufPtr, 0, length); + + TInt end = iEmailFields->ParseL(*buf); + + if( end > 0 ) + { + TPtrC body((*buf).Mid(end)); + message.Reset(); + message.InsertL(0, body); + } + CleanupStack::PopAndDestroy(buf); + } + } + +void CSmsHeader::SetCanConcatenate(TBool aCanConcatenate) + { + iFlags = (iFlags & ~ESmsHeaderCanConcatenate) | (aCanConcatenate ? ESmsHeaderCanConcatenate : ESmsHeaderNoFlags); + } + +TBool CSmsHeader::CanConcatenate() const + { + return iFlags & ESmsHeaderCanConcatenate; + } + +/** +Gets the summary information for the specified acknowledgement. + +If the specified acknowledgement is not recognised, then this function returns +the default value of TMsvSmsEntryAckSummary::ENoAckSummary. +nothing. + +@param +aAckType The requested acknowledgement summary. + +@return +The acknowledgement summary information. + +@see +TMsvSmsEntry::TMsvSmsEntryAckSummary +*/ +EXPORT_C TMsvSmsEntry::TMsvSmsEntryAckSummary TMsvSmsEntry::AckSummary(TSmsAckType aAckType) const + { + TMsvSmsEntryAckSummary summary = ENoAckSummary; + switch( aAckType ) + { + case ESmsAckTypeDelivery: + summary = static_cast((iMtmData2 & EMsvSmsEntryDeliveryAckSummary) >> EMsvSmsEntryDeliveryAckSummaryShift); + break; + default: + // Use default summary - fail gracefully. + break; + } + return summary; + } + +/** +Sets the summary information for the specified acknowlwdgement. + +If the specified acknowledgement is not recognised, then this function does +nothing. + +@param +aAckType The acknowledgement summary to be set. + +@param +aAckSummary The summary information. + +@see +TMsvSmsEntry::TMsvSmsEntryAckSummary +*/ +EXPORT_C void TMsvSmsEntry::SetAckSummary(TSmsAckType aAckType, TMsvSmsEntryAckSummary aAckSummary) + { + switch( aAckType ) + { + case ESmsAckTypeDelivery: + iMtmData2 = (iMtmData2 & ~EMsvSmsEntryDeliveryAckSummary) | ((aAckSummary << EMsvSmsEntryDeliveryAckSummaryShift) & EMsvSmsEntryDeliveryAckSummary); + break; + default: + // Do nothing - fail gracefully. + break; + } + } + +/** +Gets the message log ID and a flag indicating if it is valid. + +The returned flag indicates whether the message log ID is valid. If it is valid +then the message has only a single recipient that is pending a status report. In +this case the returned message log ID refers to the recipient that is pending. + +If it is not valid then the message has more than one recipient that is pending +a status report. The message log ID should is not valid and should not be used. + +@param +aMessageId An output argument for the message log ID. + +@return +A flag indicating whether the message log ID aMessageId is valid or not. +*/ +EXPORT_C TBool TMsvSmsEntry::MessageId(TInt32& aMessageId) const + { + aMessageId = iMtmData3; + return iMtmData2 & EMsvSmsMessageValid; + } + +/** +Sets the message log ID and a flag indicating if it is valid. + +If the message has only a single recipient that is pending a status report then +the message log ID for that recipient can be set in the index. The flag must be +set to true. + +If the message has more than one recipient that is pending a status report then +the message log ID must not be used. The flag must be set to false. + +This functionality cannot be used with bio-messages. This function will panic if +used with a bio-message. + +@param +aMessageId The message log ID. Should only be used if aIsValid is true. It has + a default value of zero. + +@param +aIsValid A flag indicating if the message log ID is valid. This should have + a value or true if the message has only a single recipient pending + a status report. + +@panic USER 0 +This message is a bio-message and therefore the message ID field cannot be used. +*/ +EXPORT_C void TMsvSmsEntry::SetMessageId(TInt32 aMessageId, TBool aIsValid) + { + __ASSERT_ALWAYS( iBioType == 0, User::Invariant() ); + + aIsValid ? (iMtmData2 |= EMsvSmsMessageValid) : (iMtmData2 &= ~EMsvSmsMessageValid); + iMtmData3 = aMessageId; + } + +/** +Gets the reply to address if it exists, otherwise calls FromAddress(). + +Only valid for SMS-DELIVER type messages. +@return +The reply to address if it exists, otherwise the originator address as returned by FromAddress(). +*/ +TPtrC CSmsHeader::ReplyAddressL() const + { + + if(Type()==CSmsPDU::ESmsDeliver) + { + //Check for a reply address field + CSmsReplyAddressOperations& operations = STATIC_CAST(CSmsReplyAddressOperations&,Message().GetOperationsForIEL(CSmsInformationElement::ESmsReplyAddressFormat)); + if(!operations.ContainsReplyAddressIEL()) + { + //if there is no reply to field call FromAddress() + return FromAddress(); + } + //return the reply to address + HBufC* replyAddressHBuf=operations.GetReplyAddressL(); + return replyAddressHBuf->Des(); + } + else + { + return FromAddress(); + } + } + +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + +/** +Stores the object in the message entry store in SQL DB. + +The object is written to the KUidMsvSMSHeaderStream stream. Any previous content +is overwritten. + +@param aStore +The store to hold the stream into which the object is written. +*/ + +void CSmsHeader::StoreDbL(CMsvStore& aStore) const + { + _LIT(KDetails,""); + + CHeaderFields* smsHeaderFields = new(ELeave) CHeaderFields(); + CleanupStack::PushL(smsHeaderFields); + smsHeaderFields->iUid = KUidMsvSMSHeaderStream; + + // 1. Header version field. + CFieldPair* smsHeaderVersionfield = new(ELeave) CFieldPair(); + CleanupStack::PushL(smsHeaderVersionfield); + smsHeaderVersionfield->iFieldNumValue = KMsvSmsHeaderVersion; + smsHeaderFields->iFieldPairList.AppendL(smsHeaderVersionfield); + CleanupStack::Pop(smsHeaderVersionfield); + + // 2. Recipient count field. + CFieldPair* smsRecipientCountField = new(ELeave) CFieldPair(); + CleanupStack::PushL(smsRecipientCountField); + smsRecipientCountField->iFieldNumValue = iRecipients.Count(); + smsHeaderFields->iFieldPairList.AppendL(smsRecipientCountField); + CleanupStack::Pop(smsRecipientCountField); + + // 3. Recipients field. + TInt size = 0; + for (TInt i=0; i < iRecipients.Count(); i++) + { + size += sizeof(CMsvRecipient::TRecipientStatus); + size += 16; // CMsvRecipient::iError (4), iRetries(4) and iTime (8) + size += Align4(iRecipients[i]->Address().Size()); // CSmsNumber::iNumber + size += Align4(iRecipients[i]->Name().Size()); // CSmsNumber::iName + size += sizeof(TLogId); // CSmsNumber::iLogId + size += sizeof(CSmsNumber::TSmsAckStatus); // CSmsNumber::iDeliveryStatus + size += 10; // For delimiters + } + + RBuf recipients; + CleanupClosePushL(recipients); + recipients.CreateL(size); + + for (TInt i=0; iStatus()); //0 + recipients.Append(KComma); + recipients.AppendNum(iRecipients[i]->Error()); //1 + recipients.Append(KComma); + recipients.AppendNum(iRecipients[i]->Retries()); //2 + recipients.Append(KComma); + recipients.AppendNum(iRecipients[i]->Time().Int64()); //3 + recipients.Append(KComma); + + recipients.Append(iRecipients[i]->Address()); //4 + recipients.Append(KComma); + recipients.Append(iRecipients[i]->Name()); //5 + recipients.Append(KComma); + recipients.AppendNum(iRecipients[i]->LogId()); //6 + recipients.Append(KComma); + recipients.AppendNum(iRecipients[i]->AckStatus(ESmsAckTypeDelivery)); //7 + recipients.Append(KDelimiter); + } + + CFieldPair* smsRecipientsField = new(ELeave) CFieldPair(); + CleanupStack::PushL(smsRecipientsField); + smsRecipientsField->iFieldTextValue = recipients.AllocL(); + smsHeaderFields->iFieldPairList.AppendL(smsRecipientsField); + + CleanupStack::Pop(smsRecipientsField); // smsRecipientsField + CleanupStack::PopAndDestroy(); // recipients + + // 4. SMS Flag + CFieldPair* smsSmsFlags = new(ELeave) CFieldPair(); + CleanupStack::PushL(smsSmsFlags); + smsSmsFlags->iFieldNumValue = iFlags; + smsHeaderFields->iFieldPairList.AppendL(smsSmsFlags); + CleanupStack::Pop(smsSmsFlags); + + // 5. BIO Msg Id + CFieldPair* smsBioMsgIdType = new(ELeave) CFieldPair(); + CleanupStack::PushL(smsBioMsgIdType); + smsBioMsgIdType->iFieldNumValue = iBioMsgIdType; + smsHeaderFields->iFieldPairList.AppendL(smsBioMsgIdType); + CleanupStack::Pop(smsBioMsgIdType); + + + CFieldPair* smsdetailField = new (ELeave)CFieldPair(); + CleanupStack::PushL(smsdetailField); + smsdetailField->iFieldName = KDetails().AllocL(); + smsdetailField->iFieldType = ETextField; + smsdetailField->iFieldTextValue = KNullDesC().AllocL(); + smsHeaderFields->iFieldPairList.AppendL(smsdetailField); + CleanupStack::Pop(smsdetailField); + + TMsvWriteStore storeWriter(aStore); + storeWriter.AssignL(smsHeaderFields); + storeWriter.CommitL(); + + CleanupStack::Pop(smsHeaderFields); + + // 6. SMS-Email UID + // 7. SMS-EMail HeaderVersion + // 8. Subject + // 9. AddressCount + // 10. Addresses + + iEmailFields->StoreDBL(aStore); + + } + +/** +Restores the object from the message entry store in SQL DB. + +The SMS object is restored from the KUidMsvSMSHeaderStream in the supplied store. + +@param aStore +The store from which the object is restored. + +@leave KErrNotFound +The stream KUidMsvSMSHeaderStream does not exist in aStore. +*/ + +void CSmsHeader::ReStoreDBL(CMsvStore& aStore) + { + + CHeaderFields* rcvHeaderRow = NULL; + TMsvReadStore storeReader(aStore, KUidMsvSMSHeaderStream); + storeReader.LoadL(rcvHeaderRow); + + + iRecipients.ResetAndDestroy(); + + TInt i = 0; + CFieldPair* rcvHeader = rcvHeaderRow->iFieldPairList[i]; + + TInt16 headerversion = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue; // header version. + TInt count = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue; + + HBufC* receipientList = rcvHeaderRow->iFieldPairList[i++]->iFieldTextValue->Des().AllocL(); + CleanupStack::PushL(receipientList); + + TPtrC receipientListPtr = receipientList->Des(); + GetRecipientL(receipientListPtr); + + iFlags = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue; + iBioMsgIdType = (TBioMsgIdType)rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue ; + + CleanupStack::PopAndDestroy(receipientList); + + iEmailFields->ReStoreDBL(aStore); + + } + +/** +Get the recipient strring and Create the recipient. + +@param : aRecipientStr A TPtrC16. +@return None. +*/ +void CSmsHeader::GetRecipientL(TDesC16& aRecipientStrList) + { + TPtrC16 aRecipientStr = aRecipientStrList.Left(aRecipientStrList.Length()); + + if(aRecipientStr.Length()>0) + { + RArray smsNumberData; + TInt startPos = 0; + TInt firstSemiColonPos = aRecipientStr.Locate(';'); + TInt lastSemiColonPos = aRecipientStr.LocateReverse(';'); + + do + { + CSmsNumber* recipientNumber=CSmsNumber::NewL(); + TPtrC16 str1 = aRecipientStr.Left(firstSemiColonPos+1); // First recipient + startPos = str1.Locate(',') ; + + while(startPos != KErrNotFound ) + { + TPtrC16 str2 = str1.Left(startPos); + smsNumberData.Append(str2); + + startPos++; + str1.Set(str1.Mid(startPos, str1.Length()- startPos)); + + startPos = str1.Locate(','); + if(startPos == KErrNotFound) + { + TPtrC16 str3; + str3.Set(str1.Mid(0,str1.Length()-1)); + smsNumberData.Append(str3); + break; + } + + } + + recipientNumber->SetStatus((CMsvRecipient::TRecipientStatus)ConvertToTInt(smsNumberData[0])); + recipientNumber->SetError(ConvertToTInt(smsNumberData[1])); + recipientNumber->SetRetries(ConvertToTInt(smsNumberData[2])); + TInt64 time = ConvertToTInt(smsNumberData[3]); + recipientNumber->SetTimeValue(time); + + //CSmsNumber + recipientNumber->SetAddressL(smsNumberData[4]); + recipientNumber->SetNameL(smsNumberData[5]); + + TLex logId(smsNumberData[6]); + TInt32 logIdNum; + logId.Val(logIdNum); + recipientNumber->SetLogId(logIdNum); + + TLex ackStatus(smsNumberData[7]); + TInt32 ackStatusNum; + recipientNumber->SetAckStatus( (TSmsAckType) ackStatus.Val(ackStatusNum), CSmsNumber::ENoAckRequested); + + iRecipients.AppendL(recipientNumber); + smsNumberData.Reset(); + + if(firstSemiColonPos != lastSemiColonPos) + { + aRecipientStr.Set(aRecipientStr.Mid(firstSemiColonPos+1,aRecipientStr.Length()-firstSemiColonPos-1)); + firstSemiColonPos = aRecipientStr.Locate(';'); + lastSemiColonPos = aRecipientStr.LocateReverse(';'); + } + else + { + break; + } + + }while(1); + + smsNumberData.Close(); + } + } + + +/** + * Convert a String to an Integer. + * @param aStr A string to make Integer. + * @return TInt A integer value + */ + TInt CSmsHeader::ConvertToTInt(TDesC16& aStr) + { + TLex str(aStr); + TInt32 string; + str.Val(string); + return string; + } + +#endif