messagingfw/biomsgfw/BioWatchers/Src/SmsSocketWatcher.cpp
changeset 62 db3f5fa34ec7
parent 0 8e480a14352b
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "SmsSocketWatcher.h"
       
    17 #include <e32std.h>
       
    18 #include <bsp.h>
       
    19 #include <biouids.h>
       
    20 #include <biodb.h>
       
    21 #include <msvstd.h>
       
    22 #include <msventry.h>
       
    23 #include <smut.h>
       
    24 #include <smuthdr.h>
       
    25 #include <msvuids.h>
       
    26 #include <watcher.h>
       
    27 #include <smutset.h>
       
    28 #include <csmsemailfields.h>
       
    29 #include <csmsaccount.h>
       
    30 #include <e32property.h>
       
    31 #include <smsuaddr.h>
       
    32 
       
    33 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
       
    34 #include <bifchangeobserver.h>
       
    35 #include <biomessageuids.h>
       
    36 #include <tmsvsmsentry.h>
       
    37 #include "cwatcher.h"
       
    38 #include "tmsvbioinfo.h"
       
    39 #endif
       
    40 
       
    41 const TInt KSmsThresholdDiskSpaceValue = 125000; // 125 KB
       
    42 
       
    43 /*
       
    44  *	CBaseSmsActiveSocketWatcher
       
    45 */
       
    46 
       
    47 EXPORT_C CBaseSmsActiveSocketWatcher::CBaseSmsActiveSocketWatcher(CWatcherLog& aWatcherLog, TInt aPriority, TUid aBioID, RFs& aFs)
       
    48 :	CActive(aPriority), 
       
    49 	iState(ESmsIsClass0Msg),
       
    50 	iBioMsgUID(aBioID),
       
    51 	iBioServiceId(KMsvLocalServiceIndexEntryId),
       
    52 	iSmsServiceId(KMsvLocalServiceIndexEntryId),
       
    53 	iWatcherLog(aWatcherLog),
       
    54 	iFs(aFs)
       
    55 	{
       
    56 	// Add it to the scheduler
       
    57 	CActiveScheduler::Add(this);
       
    58 	}
       
    59 
       
    60 EXPORT_C CBaseSmsActiveSocketWatcher::~CBaseSmsActiveSocketWatcher() 
       
    61 	{
       
    62 	iTimer.Close();
       
    63 	delete iSettings;
       
    64 	delete iGetDetDesc;
       
    65 	REComSession::FinalClose();
       
    66 	}
       
    67 
       
    68 EXPORT_C void CBaseSmsActiveSocketWatcher::Complete(TInt aStatus)
       
    69 	{
       
    70  	DoComplete(aStatus);
       
    71 	WatcherComplete(aStatus);
       
    72 	}
       
    73 
       
    74 EXPORT_C TInt CBaseSmsActiveSocketWatcher::RunError(TInt aError)
       
    75 	{
       
    76 	BIOWATCHERLOG(iWatcherLog.Printf(_L8("Bio: RunL Failed with %d"), aError));
       
    77 	Complete(aError);
       
    78 	return KErrNone;
       
    79 	}
       
    80 
       
    81 EXPORT_C void CBaseSmsActiveSocketWatcher::RunL()
       
    82 //
       
    83 // When the AO is state driven, this form of Run() is very effective
       
    84 // DoRunL() takes the AO through the states, queuing another asynch step as required
       
    85 // if DoRunL() detects the end of the cycle it returns without queuing another cycle.
       
    86 //
       
    87 // If Run() would exit without queuing another cycle it reports completion to the client.
       
    88 // This is true if the asynch step or DoRunL fails, or the state cycle is complete
       
    89 //
       
    90 	{
       
    91 	BIOWATCHERLOG(iWatcherLog.Printf(_L("Bio: DoRunL: %S, iStatus %d"), &iBioMsgText, iStatus.Int()));
       
    92 		
       
    93 	DoRunL();
       
    94 	}
       
    95 
       
    96 EXPORT_C void CBaseSmsActiveSocketWatcher::SetupL()
       
    97 	{
       
    98 	DoSetupL();
       
    99 	// Start the RunL in the WaitForMessage
       
   100 	if (iState != ESmsIsClass0Msg)
       
   101 		{
       
   102 		iState = ESmsWWaitForMsg;
       
   103 		}
       
   104 	}
       
   105 
       
   106 EXPORT_C void CBaseSmsActiveSocketWatcher::StartL()
       
   107 	{
       
   108 	BIOWATCHERLOG(iWatcherLog.Printf(_L("Bio: StartL: %S"), &iBioMsgText));
       
   109 
       
   110 	TRequestStatus* pS=&iStatus;
       
   111 	
       
   112 	// Nothing Asynchronous, so just throw into the wait state RunL()
       
   113 	User::RequestComplete(pS, KErrNone);
       
   114 	SetActive();
       
   115 	}
       
   116 
       
   117 EXPORT_C void CBaseSmsActiveSocketWatcher::RestoreSettingsL(CMsvSession& aSession)
       
   118 	{
       
   119 	SetBioServiceId(aSession);
       
   120 
       
   121 	// access sms service settings
       
   122 	CSmsAccount* smsAccount = CSmsAccount::NewLC();
       
   123 	// load settings
       
   124 	smsAccount->LoadSettingsL(*iSettings);
       
   125 
       
   126 	CleanupStack::PopAndDestroy(smsAccount);
       
   127 	}
       
   128 	
       
   129 EXPORT_C void CBaseSmsActiveSocketWatcher::RestoreSettingsL(TMsvId aBioServiceId, TMsvId aSmsServiceId)
       
   130 	{
       
   131 	SetBioServiceId(aBioServiceId, aSmsServiceId);
       
   132 	
       
   133 	// access sms service settings
       
   134 	CSmsAccount* smsAccount = CSmsAccount::NewLC();
       
   135 	// load settings
       
   136 	smsAccount->LoadSettingsL(*iSettings);
       
   137 
       
   138 	CleanupStack::PopAndDestroy(smsAccount);
       
   139 	}
       
   140 
       
   141 EXPORT_C void CBaseSmsActiveSocketWatcher::StoreMsgL(CSmsMessage* aSmsMessage)
       
   142 	{
       
   143 	StoreMsgL(aSmsMessage, EFalse);
       
   144 	}
       
   145 
       
   146 EXPORT_C void CBaseSmsActiveSocketWatcher::StoreMsgL(CSmsMessage* aSmsMessage, TBool aCheckForSID)
       
   147 	{
       
   148 	BIOWATCHERLOG(iWatcherLog.Printf(_L("Bio: StoreMsgL: %S"), &iBioMsgText));
       
   149 
       
   150 	CleanupStack::PushL(aSmsMessage);
       
   151 
       
   152 	CMsvSession* session = CMsvSession::OpenSyncL(*this);
       
   153 	CleanupStack::PushL(session);
       
   154 
       
   155 	BIOWATCHERLOG(LogMessageL(*aSmsMessage));
       
   156 	// The trap error code is ignored here. We already have loaded the settings
       
   157 	// in the SetupL method. Any catastrophic failure would be reported later
       
   158 	// when the message store is attempted.
       
   159 	TRAP_IGNORE(RestoreSettingsL(*session));
       
   160 
       
   161 	PreStoreActionL(*session, *aSmsMessage);
       
   162 
       
   163 	CMsvEntry* msvEntry = session->GetEntryL(KMsvGlobalInBoxIndexEntryId);
       
   164 	CleanupStack::PushL(msvEntry);
       
   165 	TInt systemDrive = RFs::GetSystemDrive();
       
   166   	TInt driveUnit = session->CurrentDriveL();
       
   167   	 
       
   168   	TVolumeInfo volumeInfo;
       
   169   	User::LeaveIfError(iFs.Volume(volumeInfo, driveUnit));
       
   170   	 
       
   171   	 
       
   172   	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: driveUnit: %d "),driveUnit));
       
   173   	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: volumeInfo  : %d"), volumeInfo.iFree));
       
   174   	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: threshold level= : %d"), KSmsThresholdDiskSpaceValue));
       
   175  
       
   176  
       
   177   	//Check if  non-system drive has enough space to store the message
       
   178   	if (driveUnit != systemDrive ) 
       
   179   	  	{
       
   180   	  	BIOWATCHERLOG(iWatcherLog.Printf(_L8("Low Memory")));
       
   181   	  	
       
   182   	  	TInt value;
       
   183   	  	TInt err = RProperty::Get(KUidSystemCategory,KUidPSDiskSpaceMonitorKeyType, value);
       
   184   	  	
       
   185   	  	BIOWATCHERLOG(iWatcherLog.Printf(_L("RProperty Get Value: %d "),err));
       
   186 		
       
   187 		if (volumeInfo.iFree < KSmsThresholdDiskSpaceValue)
       
   188   	  	 	{
       
   189   	  	 	if(value == ESmsDiskSpaceAvailable)
       
   190   	  	 	    {
       
   191   	  	 	    User::LeaveIfError(RProperty::Set(KUidSystemCategory,KUidPSDiskSpaceMonitorKeyType, ESmsDiskSpaceFull));
       
   192   	  	 	    }
       
   193   	  	 	User::Leave(KErrDiskFull);
       
   194   	  	 	}
       
   195   	  	 else
       
   196   	  	 	{
       
   197   	  	 	if(value == ESmsDiskSpaceFull)
       
   198   	  	 	    {
       
   199   	  	 	    User::LeaveIfError(RProperty::Set(KUidSystemCategory,KUidPSDiskSpaceMonitorKeyType, ESmsDiskSpaceAvailable));
       
   200   	  	 	    }
       
   201   	  	 	}
       
   202   	  	}
       
   203 
       
   204 
       
   205 	if( CanStoreMessage() )
       
   206 		{
       
   207 		TBool retainReplaceMessage = ETrue;
       
   208 		ReplaceTypeMessageL(*msvEntry, *aSmsMessage, retainReplaceMessage);
       
   209 		CleanupStack::Pop(3, aSmsMessage); 
       
   210 		CleanupStack::PushL(session); //guaranteed not leave because of the 3 previous POPs
       
   211 		CleanupStack::PushL(msvEntry);
       
   212 
       
   213 		if( retainReplaceMessage )
       
   214 			CreateMessageL(*msvEntry, aSmsMessage, aCheckForSID); //destroys the CSmsMessage
       
   215 		else
       
   216 			delete aSmsMessage; //destroy the CSmsMessage as CreateMessageL() would have done
       
   217 
       
   218 		CleanupStack::PopAndDestroy(2, session);
       
   219 		}
       
   220 	else
       
   221 		{
       
   222 		CleanupStack::PopAndDestroy(3, aSmsMessage);
       
   223 		BIOWATCHERLOG(iWatcherLog.Printf(_L8("Not Creating Message")));
       
   224 		}
       
   225 	}
       
   226 
       
   227 void CBaseSmsActiveSocketWatcher::ReplaceTypeMessageL(CMsvEntry& aEntry, CSmsMessage& aMessage, TBool& aRetainOriginalMessage)
       
   228 	{
       
   229     if (aMessage.Type() == CSmsPDU::ESmsDeliver)
       
   230         {
       
   231         TUint8 pid(0);
       
   232         const CSmsPDU& sms = aMessage.SmsPDU();
       
   233         const CSmsDeliver& smsTemp = STATIC_CAST(const CSmsDeliver&,sms);
       
   234         pid = (TUint8)*smsTemp.ProtocolIdentifier();
       
   235 
       
   236         if ((pid & TSmsProtocolIdentifier::ESmsPIDTypeMask) == TSmsProtocolIdentifier::ESmsPIDShortMessageType)
       
   237             {
       
   238             if ( ((pid & TSmsProtocolIdentifier::ESmsShortMessageTypeMask) <= TSmsProtocolIdentifier::ESmsReplaceShortMessageType7)
       
   239                 || ((pid & TSmsProtocolIdentifier::ESmsShortMessageTypeMask) == TSmsProtocolIdentifier::ESmsReturnCallMesage) )
       
   240                 {
       
   241                 DeleteReplaceTypeMessagesL(aEntry, pid, aMessage, aRetainOriginalMessage);
       
   242                 }
       
   243             }
       
   244         }   // Type()
       
   245 	}
       
   246 
       
   247 
       
   248 void CBaseSmsActiveSocketWatcher::DeleteReplaceTypeMessagesL(CMsvEntry& aEntry, TUint8 aPid, CSmsMessage& aMessage, TBool& aRetainOriginalMessage)
       
   249 	{
       
   250 	CSmsDeliver& smsTemp = STATIC_CAST(CSmsDeliver&, aMessage.SmsPDU());
       
   251 	TTime sourceMessageTime;
       
   252 	TInt quart;
       
   253 	smsTemp.ServiceCenterTimeStamp(sourceMessageTime, quart);
       
   254 	
       
   255 	// get the children
       
   256  	TMsvId parentFolder = KMsvGlobalInBoxIndexEntryId;
       
   257  
       
   258  	// If this is a class2 message, do the replacement in the class2 folder
       
   259  	TSmsDataCodingScheme::TSmsClass classTemp(TSmsDataCodingScheme::ESmsClass0);
       
   260  	smsTemp.Class(classTemp);
       
   261 
       
   262  	if (aMessage.Storage() == CSmsMessage::ESmsSIMStorage)
       
   263  		{	
       
   264  		if (CheckMessageExistsL(aEntry.Session(), iSettings->Class2Folder()))
       
   265  			{			
       
   266  			parentFolder = iSettings->Class2Folder();
       
   267  			}
       
   268  		}
       
   269  
       
   270  	aEntry.SetEntryL(parentFolder);
       
   271 	
       
   272 	TInt count = aEntry.Count();
       
   273 	while (count--)
       
   274 		{
       
   275 		const TMsvSmsEntry& entry = aEntry[count];
       
   276 		if ((entry.iMtm == KUidMsgTypeSMS || entry.iMtm == KUidBIOMessageTypeMtm) && entry.iType == KUidMsvMessageEntry)
       
   277 			{
       
   278 			const TUint8 entryPID = entry.ProtocolIdentifier();
       
   279 
       
   280 			if ((entryPID & TSmsProtocolIdentifier::ESmsPIDTypeMask) == TSmsProtocolIdentifier::ESmsPIDShortMessageType)
       
   281 				{
       
   282 				if ((entryPID & TSmsProtocolIdentifier::ESmsShortMessageTypeMask) == (aPid & TSmsProtocolIdentifier::ESmsShortMessageTypeMask))
       
   283 					{
       
   284 					CParaFormatLayer* paraLayer = CParaFormatLayer::NewL();
       
   285 					CleanupStack::PushL(paraLayer);
       
   286 					CCharFormatLayer* charLayer = CCharFormatLayer::NewL();
       
   287 					CleanupStack::PushL(charLayer);
       
   288 					CRichText* richtext = CRichText::NewL(paraLayer,charLayer);
       
   289 					CleanupStack::PushL(richtext);
       
   290 					
       
   291 					CSmsHeader* header = CSmsHeader::NewL(CSmsPDU::ESmsDeliver, *richtext);
       
   292 					CleanupStack::PushL(header);
       
   293 					
       
   294 					CMsvEntry* currentEntry = aEntry.ChildEntryL(entry.Id());
       
   295 					CleanupStack::PushL(currentEntry);
       
   296 					
       
   297 					CMsvStore* store = NULL;
       
   298 					TRAPD(error, store = currentEntry->ReadStoreL());
       
   299 
       
   300 					//If message arrived with "replace short message functionality", and some how message deleted from Mail2 store 
       
   301 					//but entry exist in Index file. In such case, need to delete entry from Index file and treat this as a new message.
       
   302 					if(error == KErrNotFound)
       
   303 						{
       
   304 						aRetainOriginalMessage = ETrue;
       
   305 						aEntry.DeleteL(entry.Id());
       
   306 						CleanupStack::PopAndDestroy(5); //paraLayer, charLayer, richtext, header, currentEntry
       
   307 						return;
       
   308 						}
       
   309 
       
   310 					CleanupStack::PushL(store);
       
   311 					header->RestoreL(*store);
       
   312 					CleanupStack::PopAndDestroy(2); //store, currentEntry
       
   313 					
       
   314 					if ((header->FromAddress().Compare(smsTemp.ToFromAddress()) == 0))
       
   315 						{
       
   316 						CSmsDeliver& smsDeliver = static_cast<CSmsDeliver&>(header->Message().SmsPDU());
       
   317 						TTime foundMessageTime;
       
   318 						smsDeliver.ServiceCenterTimeStamp(foundMessageTime, quart);
       
   319 
       
   320 						if (sourceMessageTime > foundMessageTime)
       
   321 							{
       
   322 							aRetainOriginalMessage = ETrue;
       
   323 							aEntry.DeleteL(entry.Id());
       
   324 							}
       
   325 						else
       
   326 							aRetainOriginalMessage = EFalse;
       
   327 						}
       
   328 					
       
   329 					CleanupStack::PopAndDestroy(4); //paraLayer, charLayer, richtext, header
       
   330 					}
       
   331 				}
       
   332 			}
       
   333 		}
       
   334 	}
       
   335 
       
   336 TBool CBaseSmsActiveSocketWatcher::CheckForSID(TPtr& aMessage, TSecureId& aSecureId)
       
   337 	{
       
   338 	_LIT(KSecureIDStr, "//SYM");
       
   339 	const TInt KIdLen = 8;
       
   340 
       
   341 	// Sanity check
       
   342 	if (aMessage.Length() < (KIdLen + KSecureIDStr().Length()))
       
   343 		return EFalse;
       
   344 
       
   345 	TBool locatedSecureId = (aMessage.Find(KSecureIDStr) == 0);
       
   346 	if (locatedSecureId)
       
   347 		{
       
   348 		TPtr idPtr = aMessage.MidTPtr(KSecureIDStr().Length(), KIdLen); // Extract the string for the id.
       
   349 		TLex numConverter;
       
   350 		numConverter.Assign(idPtr.Ptr());
       
   351 
       
   352 		TUint32 hexId;
       
   353 		if (numConverter.Val(hexId, EHex) == KErrNone)
       
   354 			aSecureId = TSecureId(hexId); // Convert the string to a number
       
   355 		else
       
   356 			locatedSecureId = EFalse;
       
   357 		}
       
   358 	return locatedSecureId;
       
   359 	}
       
   360 
       
   361 
       
   362 void CBaseSmsActiveSocketWatcher::CreateMessageL(CMsvEntry& aEntry, CSmsMessage* aMessage, TBool aCheckForSecureId)
       
   363 	{
       
   364 	// This function destroys CSmsMessage.
       
   365 	CleanupStack::PushL(aMessage);
       
   366 
       
   367 	// Create a CSmsHeader based on this message. smsHdr takes ownership of aMessage
       
   368 	CSmsHeader* header = CSmsHeader::NewL(aMessage);
       
   369 	CleanupStack::Pop(aMessage);
       
   370 	CleanupStack::PushL(header);
       
   371 
       
   372 	TMsvSmsEntry entry;
       
   373 	entry.iType = KUidMsvMessageEntry;
       
   374 	entry.SetVisible(EFalse);
       
   375 	entry.SetInPreparation(ETrue);
       
   376 	entry.SetReadOnly(EFalse);
       
   377 	entry.SetUnread(ETrue);
       
   378 	entry.SetSendingState(KMsvSendStateNotApplicable);
       
   379 
       
   380 	TInt length = iSettings->DescriptionLength();
       
   381 	HBufC* buf = HBufC::NewLC(length);
       
   382 	TPtr description = buf->Des();	
       
   383 	
       
   384 	const CSmsEmailFields& fields = header->EmailFields();
       
   385 	TBool isEmail = fields.HasAddress();
       
   386 					
       
   387 	TMsvId parentFolder = KMsvGlobalInBoxIndexEntryId;
       
   388 	// Fix for INC17771: This defect meant that a message in the outbox, e.g. would be put into the inbox;
       
   389 	// therefore, we check the status of the message to see what folder it should go into
       
   390 	if( aMessage->Status() == NMobileSmsStore::EStoredMessageUnsent )
       
   391 		parentFolder = KMsvGlobalOutBoxIndexEntryId;
       
   392 	
       
   393 	if( iBioMsgUID != KNullUid )
       
   394 		{
       
   395 		// BioficateEntry!!!
       
   396 		// Set up all the needed ids
       
   397 		TSmsUtilities::PopulateMsgEntry(entry, *aMessage, iBioServiceId, *iSettings, KUidBIOMessageTypeMtm);
       
   398 		entry.iBioType = iBioMsgUID.iUid;
       
   399 
       
   400 		// Look up and set the description
       
   401 		TInt index;
       
   402 		CBIODatabase* bioDB = CBIODatabase::NewLC(aEntry.Session().FileSession());
       
   403 		bioDB->GetBioIndexWithMsgIDL(iBioMsgUID, index);
       
   404 		description.Copy(bioDB->BifReader(index).Description().Left(length));
       
   405 		entry.iDescription.Set(description);
       
   406 		CleanupStack::PopAndDestroy(bioDB);
       
   407 		}
       
   408 	else
       
   409 		{
       
   410 		TSmsUtilities::PopulateMsgEntry(entry, *aMessage, iSmsServiceId, *iSettings);
       
   411 
       
   412 		if( isEmail && fields.Subject().Length() > 0 )
       
   413 			{
       
   414 			// For an email SMS should only set the description to be the subject
       
   415 			// if there is a subject.
       
   416 			entry.iDescription.Set(fields.Subject());
       
   417 			}
       
   418 		else
       
   419 			{
       
   420 			// For normal SMS and for email SMS messages that do not have a 
       
   421 			// subject field, the description is the begining part of the body.
       
   422 			User::LeaveIfError(iGetDetDesc->GetDescription(*aMessage, description, length));
       
   423 			entry.iDescription.Set(description);
       
   424 			}
       
   425 
       
   426 		TBool classDefined(EFalse);
       
   427 		TSmsDataCodingScheme::TSmsClass classTemp(TSmsDataCodingScheme::ESmsClass0);
       
   428 
       
   429 		if( aMessage->Type() == CSmsPDU::ESmsDeliver )
       
   430 			{
       
   431             const CSmsDeliver& deliver = static_cast<const CSmsDeliver&>(aMessage->SmsPDU());
       
   432             entry.SetProtocolIdentifier(*deliver.ProtocolIdentifier());
       
   433 			classDefined = deliver.Class(classTemp);
       
   434 
       
   435 			if( aMessage->Storage() == CSmsMessage::ESmsSIMStorage)
       
   436 				{
       
   437 				// This is a class 2 message - store the new SMS message in the 
       
   438 				// folder specified in the SMS service settings (if that folder
       
   439 				// exists, other wise default to Inbox).
       
   440 				if( CheckMessageExistsL(aEntry.Session(), iSettings->Class2Folder()) )
       
   441 					parentFolder = iSettings->Class2Folder();
       
   442 				}
       
   443             }
       
   444 		entry.SetClass(classDefined, classTemp);
       
   445 		// Check the Existing sms message for User Prompt indicator
       
   446 		const RPointerArray<const CEmsInformationElement>&  emsElements= aMessage->GetEMSInformationElementsL();
       
   447 		// Loop through the array checking for a user prompt indicator element
       
   448 		TInt count = emsElements.Count();
       
   449 		for( TInt i=0; i < count; ++i )
       
   450 			{
       
   451 			if( emsElements[i]->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator )
       
   452 				{
       
   453 				entry.SetUserPromptIndicator(ETrue);
       
   454 				break;
       
   455 				}
       
   456 			}
       
   457 		}
       
   458 	// Set the details
       
   459  	TInt detailsLen = KSmsDetailsLength;
       
   460   	if(isEmail)
       
   461 		{
       
   462 		detailsLen = fields.Addresses().MdcaPoint(0).Length();
       
   463 		}   
       
   464   	RBuf details;
       
   465   	details.CleanupClosePushL() ;
       
   466   	details.CreateL(detailsLen);
       
   467 	TInt err = KErrNone;
       
   468 	if( isEmail )
       
   469 		{
       
   470 		// For an email SMS, details is taken from the address field.
       
   471 		details.Copy(fields.Addresses().MdcaPoint(0));
       
   472 		}
       
   473 	else
       
   474 		{
       
   475 		// For normal SMS message details is taken from the info from destination
       
   476 		// address in the PDU.
       
   477 		err = iGetDetDesc->GetDetails(aEntry.Session().FileSession(), *aMessage, details);
       
   478 		}
       
   479 	if( err == KErrNone )
       
   480 		entry.iDetails.Set(details);
       
   481 
       
   482 	// Create the entry
       
   483 	aEntry.SetEntryL(parentFolder);
       
   484 	aEntry.CreateL(entry);
       
   485 	aEntry.Session().CleanupEntryPushL(entry.Id());
       
   486 	aEntry.SetEntryL(entry.Id());
       
   487 
       
   488 	// Save the message
       
   489 	CMsvStore* store = aEntry.EditStoreL();
       
   490 	CleanupStack::PushL(store);
       
   491 
       
   492 	// Save off the CSmsHdr
       
   493 	header->StoreL(*store);
       
   494 
       
   495 	// Save the body - create and fill a CRichText object.
       
   496 	CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
       
   497 	CleanupStack::PushL(paraFormatLayer);
       
   498 	CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
       
   499 	CleanupStack::PushL(charFormatLayer);
       
   500 	CRichText* richText = CRichText::NewL(paraFormatLayer,charFormatLayer);
       
   501 	CleanupStack::PushL(richText);
       
   502 
       
   503 	TInt len= aMessage->Buffer().Length();
       
   504 	HBufC* bufBody = HBufC::NewLC(len);
       
   505 
       
   506 	TPtr bufBodyPtr = bufBody->Des();
       
   507 	aMessage->Buffer().Extract(bufBodyPtr, 0, len);
       
   508 	richText->InsertL(0, bufBodyPtr); 
       
   509 	store->StoreBodyTextL(*richText);
       
   510 
       
   511 	TBool foundSecureId(EFalse);
       
   512 	TSecureId secureId;
       
   513 	if (aCheckForSecureId)
       
   514 		foundSecureId = CheckForSID(bufBodyPtr, secureId); // Check for SID
       
   515 
       
   516 	CleanupStack::PopAndDestroy(4, paraFormatLayer); //bufBody, richText, charFormatLayer, paraFormatLayer
       
   517 	store->CommitL();
       
   518 
       
   519 	// Update the index...
       
   520 	entry.SetReadOnly(ETrue);
       
   521 	entry.SetVisible(Visible());
       
   522 	entry.SetInPreparation(EFalse);
       
   523 	entry.iSize = store->SizeL();
       
   524 
       
   525 	if (foundSecureId)
       
   526 		aEntry.ChangeL(entry, secureId);
       
   527 	else
       
   528 		aEntry.ChangeL(entry);
       
   529 
       
   530 	CleanupStack::PopAndDestroy(store);
       
   531 	aEntry.Session().CleanupEntryPop(); // entry
       
   532 	CleanupStack::PopAndDestroy(&details);  
       
   533 	CleanupStack::PopAndDestroy(2, header);	// this also deletes aMessage, as owned by header
       
   534 	}
       
   535 
       
   536 TBool CBaseSmsActiveSocketWatcher::CheckMessageExistsL(CMsvSession& aSession, TMsvId aId) const
       
   537 	{
       
   538 	TMsvEntry tempEntry;
       
   539 	TMsvId tempService;
       
   540 	const TInt err = aSession.GetEntry(aId, tempService, tempEntry);
       
   541 
       
   542 	if (err != KErrNotFound)
       
   543 		User::LeaveIfError(err);
       
   544 
       
   545 	return (err == KErrNone);
       
   546 	}
       
   547 
       
   548 void CBaseSmsActiveSocketWatcher::SetBioServiceId(CMsvSession& aSession)
       
   549     {
       
   550 	TInt err = KErrNone;
       
   551 
       
   552 	if (iBioServiceId == KMsvLocalServiceIndexEntryId)
       
   553 		{
       
   554 		TRAP(err, TSmsUtilities::ServiceIdL(aSession, iBioServiceId,  KUidBIOMessageTypeMtm));
       
   555 		if (err == KErrNotFound)
       
   556 			{
       
   557 			iBioServiceId = KMsvLocalServiceIndexEntryId;
       
   558 			err = KErrNone;
       
   559 			}
       
   560 		}
       
   561 
       
   562 	if (err == KErrNone && iSmsServiceId == KMsvLocalServiceIndexEntryId)
       
   563 		{
       
   564 		TRAP(err, TSmsUtilities::ServiceIdL(aSession, iSmsServiceId));
       
   565 		if (err == KErrNotFound)
       
   566 			{
       
   567 			iSmsServiceId = KMsvLocalServiceIndexEntryId;
       
   568 			err = KErrNone;
       
   569 			}
       
   570 		}
       
   571     }
       
   572 
       
   573 void CBaseSmsActiveSocketWatcher::SetBioServiceId(TMsvId aBioServiceId, TMsvId aSmsServiceId)
       
   574 	{
       
   575 	if (iBioServiceId == KMsvLocalServiceIndexEntryId)
       
   576 		{
       
   577 		iBioServiceId = aBioServiceId;
       
   578 		}
       
   579 	if (iSmsServiceId == KMsvLocalServiceIndexEntryId)
       
   580 		{
       
   581 		iSmsServiceId = aSmsServiceId;
       
   582 		}
       
   583 	}
       
   584 
       
   585 EXPORT_C void CBaseSmsActiveSocketWatcher::ConstructL(CBIODatabase& aBioDb, TMsvId aBioServiceId, TMsvId aSmsServiceId)
       
   586 	{
       
   587 	SetBioMsgText(aBioDb);
       
   588 	iSettings = CSmsSettings::NewL();	
       
   589 	
       
   590 	// load ECOM interface used to create SMS details and description values.
       
   591 	iGetDetDesc = CSmsGetDetDescInterface::NewL();
       
   592 	
       
   593 	RestoreSettingsL(aBioServiceId, aSmsServiceId);
       
   594 	}
       
   595 
       
   596 EXPORT_C void CBaseSmsActiveSocketWatcher::SetBioMsgText(CBIODatabase& aBioDb)
       
   597 	{
       
   598 	TInt index = 0;
       
   599 	TRAPD(err, aBioDb.GetBioIndexWithMsgIDL(iBioMsgUID, index));
       
   600 			
       
   601 	if (!err)
       
   602 		iBioMsgText = aBioDb.BifReader(index).Description();
       
   603 	}
       
   604 	
       
   605 EXPORT_C void CBaseSmsActiveSocketWatcher::PreStoreActionL(CMsvSession& /*aSession*/, CSmsMessage& /*aMessage*/)
       
   606 	{
       
   607 	}
       
   608 
       
   609 #ifndef _BIOMSG_NO_LOGGING
       
   610 
       
   611 void CBaseSmsActiveSocketWatcher::LogMessageL(const CSmsMessage& aSmsMessage)
       
   612 	{
       
   613 	if (!iWatcherLog.IsLogging())
       
   614 		return;
       
   615 
       
   616 	BIOWATCHERLOG(iWatcherLog.Printf(KNullDesC));
       
   617 	TBuf<64> temp;
       
   618 	
       
   619 	switch (aSmsMessage.Type())
       
   620 		{
       
   621 		case CSmsPDU::ESmsDeliver:
       
   622 			temp = _L("[Deliver%S]");
       
   623 			break;
       
   624 		case CSmsPDU::ESmsStatusReport:
       
   625 			temp = _L("[StatusReport%S]");
       
   626 			break;
       
   627 		default:
       
   628 			temp = _L("[Message%S]");
       
   629 			break;
       
   630 		}
       
   631 
       
   632 	TInt length = iBioMsgText.Length();
       
   633 	HBufC* hBuf = HBufC::NewLC(length);
       
   634 	TPtr buf1 = hBuf->Des();
       
   635 
       
   636 	for (TInt i = 0; i < length; i++)
       
   637 		{
       
   638 		if (iBioMsgText[i] != ' ' && iBioMsgText[i] != '\n' && iBioMsgText[i] != '\t' && iBioMsgText[i] != '\r')
       
   639 			buf1.Append(iBioMsgText[i]);
       
   640 		}
       
   641 
       
   642 	BIOWATCHERLOG(iWatcherLog.Printf(temp, &buf1));
       
   643 	CleanupStack::PopAndDestroy(); //hBuf
       
   644 	hBuf = NULL;
       
   645 
       
   646 	length = aSmsMessage.Buffer().Length();
       
   647 	hBuf = HBufC::NewLC(32 + length);
       
   648 	TPtr buf2 = hBuf->Des();
       
   649 	aSmsMessage.Buffer().Extract(buf2, 0, length);
       
   650 	buf2.Insert(0, _L("Message= "));
       
   651 	LogEachLine(buf2);
       
   652 	CleanupStack::PopAndDestroy(); //hBuf
       
   653 	hBuf = NULL;
       
   654 
       
   655 	temp = aSmsMessage.ToFromAddress();
       
   656 	BIOWATCHERLOG(iWatcherLog.Printf(_L("Recipients= %S"), &temp));
       
   657 
       
   658 	temp = aSmsMessage.ServiceCenterAddress();
       
   659 	BIOWATCHERLOG(iWatcherLog.Printf(_L("SC= %S"), &temp));
       
   660 
       
   661 	BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioUid= %d"), iBioMsgUID.iUid));
       
   662 
       
   663 	if (aSmsMessage.SmsPDU().DataCodingSchemePresent())
       
   664 		{
       
   665 		temp.Zero();
       
   666 		temp.Append(_L("Encoding= "));
       
   667 		switch (aSmsMessage.SmsPDU().Alphabet())
       
   668 			{
       
   669 			case TSmsDataCodingScheme::ESmsAlphabet7Bit:
       
   670 				temp.Append(_L("7"));
       
   671 				break;
       
   672 			case TSmsDataCodingScheme::ESmsAlphabet8Bit:
       
   673 				temp.Append(_L("8"));
       
   674 				break;
       
   675 			case TSmsDataCodingScheme::ESmsAlphabetUCS2:
       
   676 				temp.Append(_L("16"));
       
   677 				break;
       
   678 			default:
       
   679 				temp.Append(_L("Unsupported"));
       
   680 				break;
       
   681 			}
       
   682 
       
   683 		BIOWATCHERLOG(iWatcherLog.Printf(temp));
       
   684 		}
       
   685 
       
   686 	BIOWATCHERLOG(iWatcherLog.Printf(KNullDesC));
       
   687 	}
       
   688 
       
   689 void CBaseSmsActiveSocketWatcher::Log(const TDesC& aInput)
       
   690 	{
       
   691 	if (!iWatcherLog.IsLogging())
       
   692 		return;
       
   693 
       
   694 	//This function is required because iWatcherLog.Printf()
       
   695 	//will only accept descriptors of max length 255.
       
   696 
       
   697 	const TInt KSmsLogMaxLength = KLogBufferSize - 22; //max number of characters RFileLogger will display
       
   698 	const TInt length = aInput.Length();
       
   699 	TInt start = 0;
       
   700 
       
   701 	while (start < length)
       
   702 		{
       
   703 		TPtrC buf(aInput.Mid(start, Min(KSmsLogMaxLength, length - start)));
       
   704 		BIOWATCHERLOG(iWatcherLog.Printf(KWatcherStringFormat, &buf));
       
   705 		start += KSmsLogMaxLength;
       
   706 		}
       
   707 	}
       
   708 
       
   709 void CBaseSmsActiveSocketWatcher::Log(const TDesC8& aInput)
       
   710 	{
       
   711 	if (!iWatcherLog.IsLogging())
       
   712 		return;
       
   713 	
       
   714 	//This function is required because iWatcherLog.Printf()
       
   715 	//will only accept descriptors of max length 255.
       
   716 	
       
   717 	const TInt KSmsLogMaxLength = KLogBufferSize - 22; //max number of characters RFileLogger will display
       
   718 	const TInt length = aInput.Length();
       
   719 	TInt start = 0;
       
   720 	
       
   721 	while (start < length)
       
   722 		{
       
   723 		TPtrC8 buf(aInput.Mid(start, Min(KSmsLogMaxLength, length - start)));
       
   724 		BIOWATCHERLOG(iWatcherLog.Printf(KWatcherStringFormat, &buf));
       
   725 		start += KSmsLogMaxLength;
       
   726 		}
       
   727 	}
       
   728 
       
   729 
       
   730 void CBaseSmsActiveSocketWatcher::LogEachLine(const TDesC& aInput)
       
   731 	{
       
   732 	if (!iWatcherLog.IsLogging())
       
   733 		return;
       
   734 
       
   735 	//LogEachLine() logs each line in aInput separately.
       
   736 	//This is required because RFileLogger (used by iWatcherLog.Printf())
       
   737 	//will replace all line feeds and carriage returns with a '.'
       
   738 
       
   739 	TPtrC part(aInput);
       
   740 	TInt length = part.Length();
       
   741 
       
   742 	while (length > 0)
       
   743 		{
       
   744 		TInt find = part.Locate('\n');
       
   745 
       
   746 		if (find == KErrNotFound)
       
   747 			{
       
   748 			Log(part);
       
   749 			break;
       
   750 			}
       
   751 		else
       
   752 			{
       
   753 			if (find == 0)
       
   754 				BIOWATCHERLOG(iWatcherLog.Printf(KNullDesC));
       
   755 			else
       
   756 				Log(part.Left(find));
       
   757 
       
   758 			if (find < length - 1)
       
   759 				part.Set(part.Mid(find + 1));
       
   760 			else
       
   761 				break;
       
   762 			}
       
   763 
       
   764 		length = part.Length();
       
   765 		}
       
   766 	}
       
   767 
       
   768 #endif