diff -r 4697dfb2d7ad -r 238255e8b033 messagingappbase/smsmtm/clientmtm/src/csmsemailfields.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingappbase/smsmtm/clientmtm/src/csmsemailfields.cpp Fri Apr 16 14:56:15 2010 +0300 @@ -0,0 +1,816 @@ +// Copyright (c) 2004-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 + +const TInt KSmsEmailAddressesArrayGranularity = 4; + +const TUid KUidMsvSmsEmailFieldsStream = {0x10204C9D}; +const TInt KMsvSmsEmailFieldsVersion = 1; +const TUint8 KSmsEmailComma = ','; +const TUint8 KSmsEmailAtSign = '@'; +const TUint8 KSmsEmailSpace = ' '; +const TUint8 KSmsEmailOpenBracket = '('; +const TUint8 KSmsEmailCloseBracket = ')'; +const TUint8 KSmsEmailHash = '#'; +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) +_LIT16(KDelimiter, ";"); +_LIT16(KComma, ","); +#endif +/** +Factory constructor. + +@return +An empty email fields object. +*/ +EXPORT_C CSmsEmailFields* CSmsEmailFields::NewL() + { + CSmsEmailFields* self = new (ELeave) CSmsEmailFields(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** +Factory copy constructor. + +@param aEmailFields +The orginal email fields object from which a copy is made. + +@return +A copy of aEmailFields. +*/ +EXPORT_C CSmsEmailFields* CSmsEmailFields::NewL(const CSmsEmailFields& aEmailFields) + { + CSmsEmailFields* self = new (ELeave) CSmsEmailFields(); + CleanupStack::PushL(self); + self->ConstructL(aEmailFields); + CleanupStack::Pop(self); + return self; + } + +/** +Destructor. +*/ +EXPORT_C CSmsEmailFields::~CSmsEmailFields() + { + Reset(); + delete iAddresses; + } + +/** +Resets the contents of the email fields object. +*/ +EXPORT_C void CSmsEmailFields::Reset() + { + delete iSubject; + iSubject = NULL; + if( iAddresses!=NULL ) + { + iAddresses->Reset(); + } + } + +/** +The number of characters in the email fields. + +Calculates the number of characters that will be pre-pended to an SMS message +when SMS is set for interworking with email. The address and subject fields are +only valid if the their length is greater than zero. + +The address field is a comma separated list of addresses. + +It assumes that a subject will be added with the following format. + +@code + +
() + +@endcode + +No validation of the contents of the fields is performed. + +@return +The number of characters in the email fields. +*/ +EXPORT_C TInt CSmsEmailFields::Length() const + { + // Get the address length and subject length + TInt subject = Subject().Length(); + TInt address = 0; + + if( HasAddress() ) + { + // Go through address list - there is at least one address... + address = (*iAddresses)[0].Length(); + + TInt count = iAddresses->Count(); + for( TInt i=1; i < count; ++i ) + { + // Any subsequent addresses are in a comma separated list - include + // length of comma separator. + address += (1 + (*iAddresses)[i].Length()); + } + } + + if( subject > 0 ) + { + // There is a subject - add the address and subject lengths plus the + // two delimiters; the '(' and ')' delimiters. + return (address + subject + 2); + } + if( address > 0 ) + { + // There is no subject field, but there is an address field - add the + // address length and the single space delimiter for the end of the + // address field. + return (address + 1); + } + + // There is neither an address nor a subject field - return zero length. + return 0; + } + +/** +Indicates whether the address field contains at least one address + +@return +A value of true if the address field contains at least one address, false if the +address field is empty. +*/ +EXPORT_C TBool CSmsEmailFields::HasAddress() const + { + return (iAddresses->Count() > 0); + } + +/** +Composes the email fields. + +The email fields are formatted into a buffer. The buffer is returned and left +on the cleanup stack. + +If there is no address fields, then the function leaves with the error code +KErrCorrupt. + +The address field is a comma separate list of addresses. + +If a subject field exists then the address fields is delimited by a open bracket +'(' and the subject is delimited by a close bracket ')'. + +@return +A buffer contain the formatted email fields. A pointer to this buffer is left +on the cleanup stack. + +@leave KErrCorrupt +The email fields has a zero-length address field. + +@internalTechnology +*/ +EXPORT_C HBufC* CSmsEmailFields::ComposeLC() const + { + if( !HasAddress() ) + { + User::Leave(KErrCorrupt); + } + + HBufC* buf = HBufC::NewLC(Length()); + TPtr ptr(buf->Des()); + + // Append the addresses - must have at least one address... + ptr.Append((*iAddresses)[0]); + + // Append remaining addresses as comma separated list + TInt count = iAddresses->Count(); + for( TInt i=1; i < count; ++i ) + { + ptr.Append(KSmsEmailComma); + ptr.Append((*iAddresses)[i]); + } + + // The delimiter for the address depends on whether there is a subject. + if( Subject().Length() > 0 ) + { + // Append open bracket '(', followed by subject and then close bracket ')'. + ptr.Append(KSmsEmailOpenBracket); + ptr.Append(*iSubject); + ptr.Append(KSmsEmailCloseBracket); + } + else + { + // No subject - address delimited by a space. + ptr.Append(KSmsEmailSpace); + } + return buf; + } + +/** +Parses the given buffer for email fields. + +Supports the two address formats. + +@code + + user@domain1.domain2 + +or + + User Name + +@endcode + +Also, supports the two subject formats. + +@code + +
() + +or + +
### + +@endcode + +The parsed address and optional subject are set in the email fields object. Any +existing data in the object is deleted. + +@param aBuffer +The buffer to be parsed. + +@return +If the email fields were successfully parsed the start position of the actual +body text from the start of aBuffer is returned. If the email fields could not +be parsed from aBuffer the error code KErrCorrupt is returned. + +@internalComponent +*/ +TInt CSmsEmailFields::ParseL(const TDesC& aBuffer) + { + Reset(); + + // The to-address or the from-address can have following two formats - + // 1. user@domain1.domain2 + // 2. User Name + // In the second format the <> brackets are part of the address. + // The address is delimited by one of the following - + // 1. + // 2. ( + // 3. # + // The later two cases imply that there is a subject field. These two + // delimiters are also mutually exclusive. + // + // First find the @ symbol - this will be the address. + TPtrC buf(aBuffer); + TInt pos = buf.Locate(KSmsEmailAtSign); + if( pos <= 0 ) + { + return KErrCorrupt; + } + + // Found the address - search for the delimiters. + TInt atPos = pos; + buf.Set(buf.Mid(pos)); + pos = buf.Locate(KSmsEmailSpace); + TInt spacePos = pos != KErrNotFound ? pos : KMaxTInt; + + pos = buf.Locate(KSmsEmailOpenBracket); + TInt bracketPos = pos != KErrNotFound ? pos : KMaxTInt; + + pos = buf.Locate(KSmsEmailHash); + TInt hashPos = pos != KErrNotFound ? pos : KMaxTInt; + + TInt bodyPos = KErrNotFound; + if( spacePos < bracketPos && spacePos < hashPos ) + { + // There is no subject as the is the first delimiter. + pos = spacePos + atPos; + + // Set the start of the body text - need to move past the delimiter. + bodyPos = pos + 1; + } + else + { + // The delimiter is either the # or ( - this implies a subject field. + TInt end = KErrNotFound; + if( bracketPos < hashPos ) + { + // Address delimited by the bracket position; + pos = bracketPos + atPos; + + // Set the start of the body text - need to move past the delimiter. + bodyPos = pos + 1; + + // Subject has the (subject) format - find the end of the subject + // indicated by the closing bracket ')'. First move past delimiter. + buf.Set(buf.Mid(bracketPos+1)); + end = buf.Locate(KSmsEmailCloseBracket); + } + else if( hashPos < KMaxTInt && buf[hashPos+1] == KSmsEmailHash ) + { + // Address delimited by the hash position; + pos = hashPos + atPos; + + // Set the start of the body text - need to move past the two # + // delimiters. + bodyPos = pos + 2; + + // Subject has the ##subject# format - find the end of the subject + // indicated by a final hash '#'. First move past the delimiters. + buf.Set(buf.Mid(hashPos+2)); + end = buf.Locate(KSmsEmailHash); + } + if( end == KErrNotFound ) + { + // In this case the email fields are corrupt - one of the following + // has occurred - + // 1. The address had no delimiter - missing , # or (. + // 2. The subject had no delimiter - missing # or ). + // 3. The address has only a single delimiting #. + return KErrCorrupt; + } + SetSubjectL(buf.Left(end)); + + // Update the start of the body text to get passed the subject - need + // to move past the delimiter. + bodyPos += end + 1; + } + // Add the address and return the position of the start of the body text. + AddAddressL(aBuffer.Left(pos)); + + return bodyPos; + } + +/** +Adds the address to the list of addresses. + +The address to be added must have a non-zero length. A zero-length address will +not be added to the address list. + +@param aAddress +The address to be added. +*/ +EXPORT_C void CSmsEmailFields::AddAddressL(const TDesC& aAddress) + { + if( aAddress.Length() > 0 ) + { + iAddresses->AppendL(aAddress); + } + } + +/** +Removes the specified address. + +@param aIndex +The index for the address to be remvoed. +*/ +EXPORT_C void CSmsEmailFields::RemoveAddress(TInt aIndex) + { + iAddresses->Delete(aIndex); + } + +/** +The array of email addresses. + +@see MDesCArray + +@return +An array of email addresses. +*/ +EXPORT_C const MDesCArray& CSmsEmailFields::Addresses() const + { + return *iAddresses; + } + +/** +Sets the email subject field. + +Copies the contents of subject as the email subject field. If the copy is +unsuccessful the current contents is left unchanged. + +@param aSubject +The subject to be copied into the email field. +*/ +EXPORT_C void CSmsEmailFields::SetSubjectL(const TDesC& aSubject) + { + HBufC* subject = aSubject.AllocL(); + delete iSubject; + iSubject = subject; + } + +/** +The subject field. + +@return +The subject field. +*/ +EXPORT_C const TDesC& CSmsEmailFields::Subject() const + { + return (iSubject) ? static_cast(*iSubject) : KNullDesC(); + } + +/** +Restores the email fields. + +If the store does not contain email fields data, the current email data is reset. + +@param aStore +The store to be read. + +@internalComponent +*/ +void CSmsEmailFields::RestoreL(CMsvStore& aStore) + { + if( aStore.IsPresentL(KUidMsvSmsEmailFieldsStream) ) + { + // The email fields stream exists - internalise from the stream. + RMsvReadStream in; + in.OpenLC(aStore, KUidMsvSmsEmailFieldsStream); + InternalizeL(in); + CleanupStack::PopAndDestroy(&in); + } + else + { + // There is no stream - reset the email fields. + Reset(); + } + } + + +/** +Stores the email fields. + +The email fields data will only be stored if there is at least some address or +subject data. If there is neither address nor subject data and the store already +contains email fields data, then this existing data is removed. + +@param aStore +The store to be written. + +@internalComponent +*/ +void CSmsEmailFields::StoreL(CMsvStore& aStore) const + { + if( HasAddress() || Subject().Length() > 0 ) + { + // The email fields have some data - store them. + RMsvWriteStream out; + out.AssignLC(aStore, KUidMsvSmsEmailFieldsStream); + ExternalizeL(out); + out.CommitL(); + CleanupStack::PopAndDestroy(&out); + } + else if( aStore.IsPresentL(KUidMsvSmsEmailFieldsStream) ) + { + // Ok, the current email fields have no data, but the email fileds + // stream exists - remove it. + aStore.Remove(KUidMsvSmsEmailFieldsStream); + } + } + +/** +Internalizes the email fields from the given stream. + +@param aStream +The stream to be read. +*/ +void CSmsEmailFields::InternalizeL(RReadStream& aStream) + { + Reset(); + aStream.ReadInt16L(); // read the version - to local as causes warning in EABI... + + TCardinality cardinality; + aStream >> cardinality; + TInt count = cardinality; + + for( TInt i = 0; i < count; ++i ) + { + HBufC* buf = HBufC::NewLC(aStream, KMaxTInt); + AddAddressL(*buf); + CleanupStack::PopAndDestroy(buf); + } + iSubject = HBufC::NewL(aStream, KMaxTInt); + } + +/** +Externalizes the email fields into the given stream. + +@param aStream +The stream to be written. +*/ +void CSmsEmailFields::ExternalizeL(RWriteStream& aStream) const + { + aStream.WriteInt16L(KMsvSmsEmailFieldsVersion); + + TInt count = iAddresses->Count(); + aStream << TCardinality(count); + for( TInt i = 0; i < count; ++i ) + { + aStream << (*iAddresses)[i]; + } + aStream << Subject(); + } + +CSmsEmailFields::CSmsEmailFields() +: CBase() + { + } + +void CSmsEmailFields::ConstructL() + { + iAddresses = new (ELeave) CDesCArrayFlat(KSmsEmailAddressesArrayGranularity); + } + +void CSmsEmailFields::ConstructL(const CSmsEmailFields& aEmailFields) + { + ConstructL(); + + const MDesCArray& addresses = aEmailFields.Addresses(); + TInt count = addresses.MdcaCount(); + + for( TInt i=0; i < count; ++i ) + { + AddAddressL(addresses.MdcaPoint(i)); + } + iSubject = aEmailFields.Subject().AllocL(); + } + +#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) + +/** +Stores the email fields in SQL DB. + +The email fields data will only be stored if there is at least some address or +subject data. If there is neither address nor subject data and the store already +contains email fields data, then this existing data is removed. + +@param aStore +The store to be written. + +@internalComponent +*/ + +void CSmsEmailFields::StoreDBL(CMsvStore& aStore) + { + // This is the continuation of the header entry created + // in CSmsHeader::StoreDbL(). + + if( HasAddress() || Subject().Length() > 0 ) + { + CHeaderFields* emailOverSmsHeaderFields = new (ELeave)CHeaderFields(); + CleanupStack::PushL(emailOverSmsHeaderFields); + emailOverSmsHeaderFields->iUid = KUidMsvSmsEmailFieldsStream; + + //----------------------EOS Info 6th Field ------------------------------ + CFieldPair* smsdetailField = new (ELeave)CFieldPair(); + CleanupStack::PushL(smsdetailField); + + RBuf eosbuf; + CleanupClosePushL(eosbuf); + eosbuf.CreateL(GetBufSize()); + + // Header version + eosbuf.AppendNum(KMsvSmsEmailFieldsVersion); + eosbuf.Append(KDelimiter); + + // AddressCount + eosbuf.AppendNum(iAddresses->Count()); + eosbuf.Append(KDelimiter); + + // Addresses + for (TInt i=0; iCount(); i++) + { + eosbuf.Append(iAddresses->MdcaPoint(i)); + if(i<(iAddresses->MdcaCount())-1) + eosbuf.Append(KComma); + } + + eosbuf.Append(KDelimiter); + + // Subject + eosbuf.Append(Subject()); + eosbuf.Append(KDelimiter); + + HBufC* newFrom1 = HBufC::NewL(eosbuf.Length()); + newFrom1->Des().Copy(eosbuf); + smsdetailField->iFieldTextValue = newFrom1; + emailOverSmsHeaderFields->iFieldPairList.AppendL(smsdetailField); + + eosbuf.Close(); + CleanupStack::Pop(); // Rbuf + CleanupStack::Pop(smsdetailField); + + + TMsvWriteStore storeWriter(aStore); + storeWriter.AssignL(emailOverSmsHeaderFields); + storeWriter.CommitL(); + + CleanupStack::Pop(emailOverSmsHeaderFields); + + } + else if( aStore.IsPresentL(KUidMsvSmsEmailFieldsStream) ) + { + + CHeaderFields* emailOverSmsHeaderFields = new (ELeave)CHeaderFields(); + CleanupStack::PushL(emailOverSmsHeaderFields); + emailOverSmsHeaderFields->iUid = KUidMsvSmsEmailFieldsStream; + + + CFieldPair* smsdetailField = new (ELeave)CFieldPair(); + CleanupStack::PushL(smsdetailField); + smsdetailField->iFieldTextValue = KNullDesC().AllocL(); + emailOverSmsHeaderFields->iFieldPairList.AppendL(smsdetailField); + CleanupStack::Pop(smsdetailField); + + TMsvWriteStore storeWriter(aStore); + storeWriter.AssignL(emailOverSmsHeaderFields); + storeWriter.CommitL(); + + + // Ok, the current email fields have no data, but the email fileds + // stream exists - remove it. + aStore.Remove(KUidMsvSmsEmailFieldsStream); + + CleanupStack::Pop(emailOverSmsHeaderFields); + } + } + +/** +To gett he Buffer size. +*/ + +TInt CSmsEmailFields::GetBufSize() + { + TInt size = 0; + + size += sizeof(KMsvSmsEmailFieldsVersion) + 1; // 1 is for Delimiter + size += Subject().Length() + 1 ; + size += sizeof(iAddresses->Count()) + 1 ; + + for(TInt i=0; iCount(); i++) + { + size += iAddresses->MdcaPoint(i).Length() + 1; // Extra byte for Comma + } + + return size ; + + } + + + +/** +Retrives the email fields from SQL DB. + +If the store does not contain email fields data, the current email data is reset. + +@param aStore +The store to be read. + +@internalComponent +*/ + + +void CSmsEmailFields::ReStoreDBL(CMsvStore& aStore) + { + Reset(); + CHeaderFields* rcvEmailHeaderRow = NULL; + TMsvReadStore storeReader(aStore, KUidMsvSmsEmailFieldsStream); + TRAPD(err, storeReader.ReadL(rcvEmailHeaderRow)); + + if(KErrNotFound == err) + { + return; + } + + TInt i = 0; //SMS Email over SMS + HBufC* eosheaderinfo = rcvEmailHeaderRow->iFieldPairList[i++]->iFieldTextValue ; + TPtr16 eosheaderPtr = (eosheaderinfo->Des()); + + //Parsing the eos string + TInt firstSemiColonPos = eosheaderPtr.Locate(';'); + TInt lastSemiColonPos = eosheaderPtr.LocateReverse(';'); + + RPointerArray eosinfoData; + CleanupClosePushL(eosinfoData); + TInt ii = 0 ; + + do + { + TPtrC16 str1 = eosheaderPtr.Left(firstSemiColonPos); // First data + HBufC16* tt = str1.AllocLC(); + firstSemiColonPos++; + eosinfoData.AppendL(tt); + CleanupStack::Pop(); + + if(firstSemiColonPos != lastSemiColonPos) + { + eosheaderPtr = (eosheaderPtr.Mid(firstSemiColonPos,eosheaderPtr.Length()-(firstSemiColonPos) )); + firstSemiColonPos = eosheaderPtr.Locate(';'); + lastSemiColonPos = eosheaderPtr.LocateReverse(';'); + if(firstSemiColonPos == lastSemiColonPos) + { + TPtrC16 str1 = eosheaderPtr.Left(eosheaderPtr.Length() -1); // Last data is Subject . End with Semicolon. -1 is to remove semicolon. + HBufC16* tt = str1.AllocLC(); + eosinfoData.AppendL(tt); + CleanupStack::Pop(); + } + } + else + { + //Empty field. + HBufC16* tt = KNullDesC().AllocLC(); + eosinfoData.AppendL(tt); + CleanupStack::Pop(); + } + + ii++; + }while(firstSemiColonPos != lastSemiColonPos); + + TInt16 headerversion = ConvertToTInt(*eosinfoData[0]); + + TInt count = ConvertToTInt(*eosinfoData[1]); + + if(count > 0) + { + _LIT16(KSemicolon, ";"); + HBufC16* addressesList = eosinfoData[2]->Des().AllocLC(); + addressesList = addressesList->ReAllocL(addressesList->Length()+2); + TPtr16 addressesListPtr = (addressesList->Des()); + addressesListPtr.Append(KSemicolon); + GetRecipientListL(addressesListPtr); + CleanupStack::PopAndDestroy(); + } + else + { + AddAddressL(KNullDesC16); + } + + iSubject = eosinfoData[3]->Des().AllocL(); + + + eosinfoData.ResetAndDestroy(); + CleanupStack::PopAndDestroy(); //RPointerArray + } + + /* Convert a String to an Integer. + * @param aStr A string to make Integer. + * @return TInt A integer value + */ +TInt CSmsEmailFields::ConvertToTInt(TDesC16& aStr) + { + TLex str(aStr); + TInt32 string; + str.Val(string); + return string; + } + +/** +To parse the recipient address list. +*/ + +void CSmsEmailFields::GetRecipientListL(TDesC16& aStr) + { + TPtrC16 recvstr = aStr; + + if(KErrNotFound != recvstr.Locate(',') ) + { // It has multipule recipient list is :- example@nokia.com, example@nokia.com,example@nokia.com; + TInt startPos = recvstr.Locate(',') ; + while(1) + { + TPtrC16 partstrx = recvstr.Left(startPos); + AddAddressL(partstrx); + startPos++; + recvstr.Set(recvstr.Mid(startPos, recvstr.Length()- startPos)); + + startPos = recvstr.Locate(','); + if(startPos == KErrNotFound) + { + TPtrC16 partstrxy; + partstrxy.Set(recvstr.Mid(0,recvstr.Length()-1)); + AddAddressL(partstrxy); + break; + } + } + + } + else // It has one recipient list is like this-> example@nokia.com; + { + TInt lastpos = recvstr.Locate(';'); + TPtrC16 partstrx = recvstr.Left(lastpos); + AddAddressL(partstrx); + } + } +#endif