messagingfw/biomsgfw/BioWatchers/Src/NBSSocketWatcher.cpp
changeset 0 8e480a14352b
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     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 // NBSocketWatcher.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "NBSSocketWatcher.h"
       
    19 #include "SmsSocketWatcher.h"
       
    20 
       
    21 #include <smuthdr.h>
       
    22 #include <msventry.h>
       
    23 #include <msvstd.h>
       
    24 #include <msvuids.h>
       
    25 #include <smut.h>
       
    26 #include <watcher.h>
       
    27 #include <smsuaddr.h>
       
    28 #include <gsmuelem.h>
       
    29 #include <gsmunonieoperations.h>
       
    30 #include <s32strm.h>
       
    31 #include <s32mem.h>
       
    32 #include <gsmubuf.h>
       
    33 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    34 #include <tmsvsmsentry.h>
       
    35 #include "cwatcher.h"			
       
    36 #endif
       
    37 
       
    38 const TInt KSmsWRetryTimer = 1000000 * 15; // 15 Secs
       
    39 
       
    40 /*
       
    41  * CNbsSocketWatcher
       
    42  */
       
    43 
       
    44 CNbsSmsSocketWatcher::CNbsSmsSocketWatcher(CWatcherLog& aWatcherLog, TInt aPriority, TUid aBioID, RFs& aFs, const TDesC& aNbsPattern, TSmsAddrFamily aAddrFamily)
       
    45 :	CBaseSmsActiveSocketWatcher(aWatcherLog, aPriority, aBioID, aFs),
       
    46 	iAddrFamily(aAddrFamily),
       
    47 	iNbsPattern(aNbsPattern)
       
    48 	{
       
    49 	}
       
    50 
       
    51 CNbsSmsSocketWatcher::~CNbsSmsSocketWatcher()
       
    52 	{
       
    53 	Cancel();
       
    54 
       
    55 	if (iSocket.SubSessionHandle())
       
    56 		iSocket.Close();
       
    57 
       
    58 	if (iSocketServer.Handle())
       
    59 		iSocketServer.Close();
       
    60 	
       
    61 	//destroying class 0 SMS E-Com pluin implementation 
       
    62 	if (iSmsClass0 != NULL)
       
    63 		{
       
    64 		REComSession::DestroyedImplementation(iDtor_ID_Key);
       
    65 		REComSession::FinalClose();
       
    66 		delete iSmsClass0;
       
    67 		}
       
    68 	RProperty::Delete(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType);
       
    69 	}
       
    70 
       
    71 CNbsSmsSocketWatcher* CNbsSmsSocketWatcher::NewLC(TMsvId aBioServiceId, 
       
    72 									   			  TMsvId aSmsServiceId, 
       
    73 									   			  CBIODatabase& aBioDb, 
       
    74 									   			  CWatcherLog& aWatcherLog, 
       
    75 									   			  TInt aPriority, 
       
    76 									   			  TUid aBioID, 
       
    77 									   			  RFs& aFs, 
       
    78 									   			  const TDesC& aNbsPattern, 
       
    79 									   			  TSmsAddrFamily aAddrFamily /*= ESmsAddrMatchText*/)
       
    80 	{
       
    81 	CNbsSmsSocketWatcher* self = new(ELeave) CNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
       
    82 	CleanupStack::PushL(self);
       
    83 	self->ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
       
    84 	return self;	
       
    85 	}
       
    86 
       
    87 
       
    88 void CNbsSmsSocketWatcher::ConstructL(TMsvId aBioServiceId, TMsvId aSmsServiceId, CBIODatabase& aBioDb)
       
    89 	{
       
    90 	CBaseSmsActiveSocketWatcher::ConstructL(aBioDb, aBioServiceId, aSmsServiceId);
       
    91 	User::LeaveIfError(iSocketServer.Connect());
       
    92 	TSecurityPolicy  readPolicy(ECapabilityReadDeviceData);
       
    93 	TSecurityPolicy  writePolicy(ECapabilityWriteDeviceData);
       
    94 
       
    95  
       
    96 	TInt ret = RProperty::Define(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType,
       
    97   	  	 				  RProperty::EInt, readPolicy, writePolicy);
       
    98  
       
    99 	BIOWATCHERLOG(iWatcherLog.Printf(_L(" Define return value %d"), ret));
       
   100  
       
   101 	if (ret != KErrNone  &&  ret != KErrAlreadyExists)
       
   102   		{
       
   103   		User::Leave(ret);
       
   104   		}   
       
   105   		 
       
   106 	TInt setRet = RProperty::Set(KUidSystemCategory, KUidPSDiskSpaceMonitorKeyType, ESmsDiskSpaceAvailable);
       
   107  
       
   108 	BIOWATCHERLOG(iWatcherLog.Printf(_L(" Set value %d"), setRet));
       
   109  
       
   110 	if (setRet != KErrNone)
       
   111   		{
       
   112   		User::Leave(setRet);
       
   113   		}
       
   114 	}
       
   115 
       
   116 void CNbsSmsSocketWatcher::DoCancel()
       
   117 	{
       
   118 	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoCancel")));
       
   119 	if (iIoCtlActive)
       
   120 		{
       
   121 		iSocket.CancelIoctl();
       
   122 		}
       
   123 
       
   124 	if(iTimer.Handle() != NULL)
       
   125 		iTimer.Cancel();
       
   126 
       
   127 	Complete(KErrCancel);
       
   128 	}
       
   129 
       
   130 void CNbsSmsSocketWatcher::DoRunL()
       
   131 	{
       
   132 	iIoCtlActive = EFalse;
       
   133 	switch(iState)
       
   134 		{
       
   135 		case ESmsWWaitForMsg:
       
   136 			iState = ESmsWReadMsg;
       
   137 			WaitForMessageL();
       
   138 			break;
       
   139 		
       
   140 		case ESmsWReadMsg:
       
   141 			iState = ESmsWWaitForMsg;
       
   142 			ReceiveL();
       
   143 			break;
       
   144 
       
   145 		case ESmsWRetryError:
       
   146 			if (!iTimer.Handle())
       
   147 				{
       
   148 				User::LeaveIfError(iTimer.CreateLocal());
       
   149 				}
       
   150 				
       
   151 			iState=ESmsWWaitForMsg;
       
   152 			iTimer.After(iStatus, KSmsWRetryTimer);
       
   153 			break;
       
   154 			
       
   155 		case ESmsIsClass0Msg:
       
   156 			iState = ESmsSupportClass0Msg;
       
   157 			CheckForClass0SmsSupport();
       
   158 			break;
       
   159 		
       
   160 		case ESmsSupportClass0Msg:
       
   161 			iState = ESmsWWaitForMsg;
       
   162 			SupportForClass0SmsL();
       
   163 			break;
       
   164 		}
       
   165 
       
   166 	SetActive();
       
   167 
       
   168 	}
       
   169 
       
   170 void CNbsSmsSocketWatcher::DoSetupL()
       
   171 	{
       
   172 	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoSetupL: %S"), &iBioMsgText));
       
   173 
       
   174 	// Set up the Socket to watch the port
       
   175 
       
   176 	// test if it's there... 
       
   177 	TProtocolDesc protoInfo;
       
   178 	TProtocolName protocolname;
       
   179 
       
   180 	BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Finding protocol")));
       
   181 
       
   182 	protocolname.Copy(KSmsDatagram);
       
   183 	User::LeaveIfError(iSocketServer.FindProtocol(protocolname,protoInfo));
       
   184 
       
   185 	BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Opening socket")));
       
   186 
       
   187 	// Create the RSocket
       
   188 	User::LeaveIfError(iSocket.Open(iSocketServer,
       
   189 										protoInfo.iAddrFamily,
       
   190 										protoInfo.iSockType, 
       
   191 										protoInfo.iProtocol));
       
   192 	
       
   193 	// Set up the Socket to watch the pattern
       
   194 	if (iBioMsgUID != KNullUid && iAddrFamily == ESmsAddrMatchText)
       
   195 	{
       
   196 		// need an 8 bit pattern
       
   197 		TBuf8<KMaxBioIdText> pattern; 
       
   198 		pattern.Copy(iNbsPattern);
       
   199 
       
   200 		iSmsAddr.SetSmsAddrFamily(ESmsAddrMatchText);
       
   201 		iSmsAddr.SetTextMatch(pattern);
       
   202 	}
       
   203 	else
       
   204 	{
       
   205 		// Binding to a non-patter address family
       
   206 		// like StatusReports, Special Messages, and RecieveAny
       
   207 		iSmsAddr.SetSmsAddrFamily(iAddrFamily);
       
   208 	}
       
   209 	
       
   210 	BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: DoSetupL: Binding socket")));
       
   211 
       
   212 	User::LeaveIfError(iSocket.Bind(iSmsAddr));
       
   213 	}
       
   214 
       
   215 void CNbsSmsSocketWatcher::DoComplete(TInt& rStatus)
       
   216 	{	
       
   217 	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: DoComplete: %S, status %d"), &iBioMsgText, rStatus));
       
   218 
       
   219 	if (iSocket.SubSessionHandle())
       
   220 		{
       
   221 		iSocket.Close();
       
   222 		}
       
   223 	}
       
   224 
       
   225 void CNbsSmsSocketWatcher::WaitForMessageL()
       
   226 	{
       
   227 	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: WaitForMessageL: %S"), &iBioMsgText));
       
   228 	iOctlRes()= KSockSelectRead;
       
   229 	iIoCtlActive = ETrue;
       
   230 	iSocket.Ioctl(KIOctlSelect, iStatus, &iOctlRes, KSOLSocket);
       
   231 	}
       
   232 	
       
   233 // CNbsSmsSocketWatcher::CheckForClass0SmsSupport to find out whether SMS stack is 
       
   234 // configured for this new behaviour of class 0 message or not.
       
   235 void CNbsSmsSocketWatcher::CheckForClass0SmsSupport()
       
   236 	{
       
   237 	// Need verify SMS stack configuration, if type of socket address is ESmsAddrRecvAny only
       
   238 	if (iAddrFamily == ESmsAddrRecvAny)
       
   239 		{
       
   240 		BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: CheckForClass0SmsSupport")));
       
   241 		iOctlRes()= KSockSelectRead;
       
   242 		iIoCtlActive = ETrue;
       
   243 		//iStatus will return KErrNone if stack supports new way of handling class 0 messages. 
       
   244 		//Otherwise it will return KErrNotSupported.
       
   245 		iSocket.Ioctl(KIoctlSupportOODClass0SmsMessages, iStatus, NULL, KSolSmsProv);
       
   246 		}
       
   247 	else
       
   248 		{
       
   249 		//Change state to Wait For Message
       
   250 		iState = ESmsWWaitForMsg;
       
   251 		//Complete self to enter state machine
       
   252 		TRequestStatus* status = &iStatus;
       
   253 		iStatus=KRequestPending;
       
   254 		User::RequestComplete(status, KErrNone);
       
   255 		}
       
   256 	}
       
   257 
       
   258 void CNbsSmsSocketWatcher::DoReceiveL()
       
   259  	{
       
   260  	// Get the Message
       
   261  	CSmsMessage* smsmessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, CSmsBuffer::NewL());
       
   262  	CleanupStack::PushL(smsmessage);
       
   263  			
       
   264  	RSmsSocketReadStream readstream(iSocket);
       
   265  	readstream >> *smsmessage; //can leave
       
   266  			
       
   267  	CleanupStack::Pop(smsmessage);
       
   268  	
       
   269  	//get the class type here
       
   270 	TSmsDataCodingScheme::TSmsClass classType(TSmsDataCodingScheme::ESmsClass2);
       
   271 	const CSmsDeliver& deliver = static_cast<const CSmsDeliver&>(smsmessage->SmsPDU());
       
   272     TBool classDefined = deliver.Class(classType);
       
   273     
       
   274     //handling class 0 sms message 
       
   275  	if(iSmsClass0 != NULL && classType == TSmsDataCodingScheme::ESmsClass0)
       
   276  		{
       
   277  		//destroy the CSmsMessage, once passed succesfully to Class0SMS plugin
       
   278  		CleanupStack::PushL(smsmessage);
       
   279  		
       
   280 		//Externalize CSmsMessage into a TDesC8
       
   281 		CSmsBufferBase& convSmsMsg = smsmessage->Buffer();
       
   282 		TInt len = convSmsMsg.Length() ;
       
   283 	
       
   284 		//for sending Incomplete MessageInfo to UI.
       
   285 		TInt startPos = 0;
       
   286 		TInt endPos = 0;
       
   287 		TBool isLastMessage = EFalse;
       
   288 		
       
   289 		HBufC *buffer = HBufC::NewLC(len);
       
   290 		TPtr temp = buffer->Des();
       
   291 		convSmsMsg.Extract(temp, 0, len);
       
   292 		
       
   293 		//allocate memory for CBufFlat, length sholud be: length of Class0SMS data + 2*(size of TInt)+(size of TBool)
       
   294 		CBufFlat* flat = CBufFlat::NewL(len + (3 * sizeof(TInt)));
       
   295 		CleanupStack::PushL(flat);
       
   296 		flat->ExpandL(0, len);
       
   297 		
       
   298 		RBufWriteStream writeStream(*flat);
       
   299 		CleanupClosePushL (writeStream);
       
   300 			
       
   301 		if (smsmessage->IsComplete())
       
   302 			{
       
   303 			//if it's complete class 0 SMS message
       
   304 			//passing startPos, endPos and isLastMessage value to 0
       
   305 			ExternalizeL(writeStream, startPos, endPos, isLastMessage, temp);
       
   306 			TPtr8 smsMsg(flat->Ptr(0));
       
   307 			iSmsClass0->DisplayMessageHandler(smsMsg, ETrue);
       
   308 			}
       
   309 		else
       
   310 			{
       
   311 			//handling incomplete SMS Message
       
   312 			CIncompleteClass0MessageInfo  &incompleteMessageInfo = (CIncompleteClass0MessageInfo&)smsmessage->GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter);
       
   313 			TInt msgRefNo = smsmessage->SmsPDU().ConcatenatedMessageReference();
       
   314 			
       
   315 			//get the information about the messsage & externalize it..	
       
   316 			incompleteMessageInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage);
       
   317 			ExternalizeL(writeStream, startPos, endPos, isLastMessage, temp);
       
   318 			TPtr8 smsMsg(flat->Ptr(0));
       
   319 					
       
   320 			if (iMsgRefNumber == -1 || iMsgRefNumber == msgRefNo)
       
   321 				{
       
   322 				//if it's 1st part of the Message, assign msgRefNo to iMsgRefNumber  
       
   323 				if (iMsgRefNumber == -1)
       
   324 					{
       
   325 					iMsgRefNumber = msgRefNo;
       
   326 					}
       
   327 						
       
   328 				iSmsClass0->DisplayMessageHandler(smsMsg, EFalse);
       
   329 							
       
   330 				//if it's last part of the Message, assign iMsgRefNumber to -1  							
       
   331 				if (isLastMessage)
       
   332 					{
       
   333 					iMsgRefNumber = -1;	
       
   334 					}
       
   335 				}
       
   336 			}
       
   337 			//delete smsmessage, as owned by header
       
   338 			CleanupStack::PopAndDestroy(4, smsmessage);
       
   339  		} //handling class 0 sms message
       
   340  	
       
   341  	// If the message is delivered to an unknown port (as opposed to no port at all)
       
   342  	// then we should only store the message if it is a "TextMessage".
       
   343  	// Otherwise the message should be silently consumed without being delivered.
       
   344  	// This is a requirement of the Java "Mobile Service Architecture", JSR 248, section 6.11.3.2 	
       
   345 	
       
   346  	else if (	iAddrFamily == ESmsAddrRecvAny 			// << This watcher is listening on an unknown port
       
   347  			&& MessageHasPort(*smsmessage)			// << The message is addressed to a specific port
       
   348  			&& ! IsJavaTextMessage(*smsmessage) )	// << The message is defined by JSR 205 as NOT a TextMessage object
       
   349  		{
       
   350  		BIOWATCHERLOG(iWatcherLog.Printf(_L8("BioNbs: Non-text message delivered to unknown port - deleting message")));
       
   351  		}
       
   352  	else
       
   353  		{
       
   354  		StoreMsgL(smsmessage, ETrue); // Store the messaage and check for SID entry for ownership
       
   355  		}
       
   356  	}
       
   357 
       
   358 void CNbsSmsSocketWatcher::ReceiveL()
       
   359 	{
       
   360 	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: ReceiveL: %S"), &iBioMsgText));
       
   361 	
       
   362 	TInt error;
       
   363 	
       
   364 	switch (iStatus.Int())
       
   365 		{
       
   366 		case KErrNone:
       
   367 			{
       
   368 			TRAP(error, DoReceiveL());
       
   369 			
       
   370 			// Tell the socket if we handled the message or not
       
   371 			if (error == KErrNone)
       
   372 				{
       
   373 				iIoCtlActive = ETrue;
       
   374 				iSocket.Ioctl(KIoctlReadMessageSucceeded, iStatus, NULL, KSolSmsProv);
       
   375 				}
       
   376 			else
       
   377 				{
       
   378 				BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: Recv fail %d: %S"), error, &iBioMsgText));
       
   379  				iState = ESmsWRetryError;
       
   380 				iIoCtlActive = ETrue;
       
   381 				iSocket.Ioctl(KIoctlReadMessageFailed, iStatus, NULL, KSolSmsProv);
       
   382 				}
       
   383 			}
       
   384 			break;
       
   385 			
       
   386 		case KIoctlSelectModemPresent:
       
   387 			// Enumerate to see it there are any messages when the phone's hooked up
       
   388 			// Only enumerate with default recievAny watcher
       
   389 			// this pattern watcher should do nothing
       
   390 			// SMS Prot should get the phone memory's SMS messages here
       
   391 		case KIoctlSelectModemNotPresent:
       
   392 			{
       
   393 			// Phone's disconnected ... wait in Ioctl again
       
   394 			// base class does this ... we're okay
       
   395 			TRequestStatus* pS=&iStatus;
       
   396 			User::RequestComplete(pS,0);
       
   397 			}			
       
   398 			break;
       
   399 
       
   400 		default:
       
   401 			User::Leave(iStatus.Int());
       
   402 		}
       
   403 	}
       
   404 
       
   405 /**
       
   406 Returns whether the message contains optional port addressing information.
       
   407 @return ETrue if message contains port addressing information, otherwise EFalse.
       
   408 */
       
   409 TBool CNbsSmsSocketWatcher::MessageHasPort(const CSmsMessage& aSmsMessage)
       
   410 	{
       
   411 	// Declare variables that will receive their values in ApplicationPortAddressing()
       
   412  	TInt destinationPort=0;
       
   413  	TInt originatorPort=0;
       
   414  	TBool is16bit=EFalse;
       
   415  	TBool hasPortAddressing = aSmsMessage.SmsPDU().ApplicationPortAddressing(destinationPort, originatorPort, &is16bit);
       
   416  	
       
   417  	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: MessageHasPort()"))); 	
       
   418  	BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs:  > has:%d, dest:%d, orig:%d, 16bit:%d)"), hasPortAddressing, destinationPort, originatorPort, is16bit));
       
   419  	
       
   420  	return hasPortAddressing;
       
   421 	}
       
   422 
       
   423 /**
       
   424 Check whether Discard Unknown Port message flag is set, if not check for Java wireless messaging.
       
   425 
       
   426 Returns whether the message is considered a TextMessage, according to Java wireless messaging
       
   427 specifications - JSR 205 "Wireless Messaging API" Appendix A.5.0 - which associates the TextMessage
       
   428 object with the 7-bit and 16-bit UCS-2 alphabets, and BinaryMessage with the 8-bit alphabet.
       
   429 @param aSmsMessage the message whose alphabet we are testing.
       
   430 @return ETrue if the alphabet is 7-bit or 16-bit UCS-2, otherwise EFalse.
       
   431 */
       
   432 TBool CNbsSmsSocketWatcher::IsJavaTextMessage(const CSmsMessage& aSmsMessage)
       
   433 	{
       
   434 	TBool isTextMessage = EFalse;
       
   435 	if(!iSettings->DiscardUnknownPortMessage())
       
   436 		{
       
   437 		TSmsDataCodingScheme::TSmsAlphabet alphabet = aSmsMessage.SmsPDU().Alphabet();
       
   438  	
       
   439 		if (alphabet == TSmsDataCodingScheme::ESmsAlphabet7Bit || alphabet == TSmsDataCodingScheme::ESmsAlphabetUCS2)
       
   440 			{
       
   441 			isTextMessage = ETrue;
       
   442 			}
       
   443 
       
   444 			BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs: IsJavaTextMessage()")));
       
   445 	 		BIOWATCHERLOG(iWatcherLog.Printf(_L("BioNbs:  > isTextMessage:%d, alphabet:%d)"), isTextMessage, alphabet));
       
   446 		}
       
   447 	
       
   448 	return isTextMessage;
       
   449 	}	
       
   450 	
       
   451 /*
       
   452  *	CSpecialNbsSmsSocketWatcher Implementation
       
   453  */
       
   454  
       
   455 CSpecialNbsSmsSocketWatcher* CSpecialNbsSmsSocketWatcher::NewLC(
       
   456 															TMsvId 			aBioServiceId, 
       
   457 															TMsvId 			aSmsServiceId, 
       
   458 															CBIODatabase&	aBioDb, 
       
   459 															CWatcherLog&	aWatcherLog,
       
   460 															TInt			aPriority,
       
   461 															TUid			aBioID,
       
   462 															RFs&			aFs,
       
   463 															const TDesC&	aNbsPattern, 
       
   464 															TSmsAddrFamily	aAddrFamily)
       
   465 	{
       
   466 	CSpecialNbsSmsSocketWatcher* self = new (ELeave) CSpecialNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
       
   467 	CleanupStack::PushL(self);
       
   468 	self->ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
       
   469 	return self;
       
   470 	}
       
   471 
       
   472 CSpecialNbsSmsSocketWatcher* CSpecialNbsSmsSocketWatcher::NewL(
       
   473 															TMsvId 			aBioServiceId, 
       
   474 															TMsvId 			aSmsServiceId, 
       
   475 															CBIODatabase&	aBioDb, 
       
   476 															CWatcherLog&	aWatcherLog, 
       
   477 															TInt			aPriority, 
       
   478 															TUid			aBioID, 
       
   479 															RFs&			aFs,
       
   480 															const TDesC&	aNbsPattern, 
       
   481 															TSmsAddrFamily	aAddrFamily)
       
   482 	{
       
   483 	CSpecialNbsSmsSocketWatcher* self = NewLC(aBioServiceId, aSmsServiceId, aBioDb, aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily);
       
   484 	CleanupStack::Pop(self);
       
   485 	return self;
       
   486 	}
       
   487 
       
   488 CSpecialNbsSmsSocketWatcher::CSpecialNbsSmsSocketWatcher(CWatcherLog& aWatcherLog, TInt aPriority, TUid aBioID, RFs& aFs, const TBioMsgIdText& aNbsPattern, TSmsAddrFamily aAddrFamily)
       
   489 : CNbsSmsSocketWatcher(aWatcherLog, aPriority, aBioID, aFs, aNbsPattern, aAddrFamily)
       
   490 	{
       
   491 	}
       
   492 
       
   493 void CSpecialNbsSmsSocketWatcher::RestoreSettingsL(CMsvSession& aSession)
       
   494 	{
       
   495 	CBaseSmsActiveSocketWatcher::RestoreSettingsL(aSession);
       
   496 
       
   497 	switch(iAddrFamily)
       
   498 		{
       
   499 	case ESmsAddrMessageIndication:
       
   500 		iReportHandling = iSettings->SpecialMessageHandling();
       
   501 		break;
       
   502 	case ESmsAddrStatusReport:
       
   503 		iReportHandling = iSettings->StatusReportHandling();
       
   504 		break;
       
   505 	default:
       
   506 		PanicWatcher(EAddrFamilyNotSupported1);
       
   507 		break;
       
   508 		}
       
   509 	}
       
   510 	
       
   511 void CSpecialNbsSmsSocketWatcher::RestoreSettingsL(TMsvId aBioServiceId, TMsvId aSmsServiceId)
       
   512 	{
       
   513 	CBaseSmsActiveSocketWatcher::RestoreSettingsL(aBioServiceId, aSmsServiceId);
       
   514 	
       
   515 	switch(iAddrFamily)
       
   516 		{
       
   517 	case ESmsAddrMessageIndication:
       
   518 		iReportHandling = iSettings->SpecialMessageHandling();
       
   519 		break;
       
   520 	case ESmsAddrStatusReport:
       
   521 		iReportHandling = iSettings->StatusReportHandling();
       
   522 		break;
       
   523 	default:
       
   524 		PanicWatcher(EAddrFamilyNotSupported2);
       
   525 		break;
       
   526 		}
       
   527 	}
       
   528 
       
   529 void CSpecialNbsSmsSocketWatcher::ConstructL(TMsvId aBioServiceId, TMsvId aSmsServiceId, CBIODatabase& aBioDb)
       
   530 	{
       
   531 	CNbsSmsSocketWatcher::ConstructL(aBioServiceId, aSmsServiceId, aBioDb);
       
   532 
       
   533 	if (iReportHandling == CSmsSettings::EDoNotWatchForReport)
       
   534 		{
       
   535 		User::Leave(KErrNotSupported);
       
   536 		}
       
   537 	}
       
   538 	
       
   539 
       
   540 CSpecialNbsSmsSocketWatcher::~CSpecialNbsSmsSocketWatcher()
       
   541 	{
       
   542 	Cancel();
       
   543 	}
       
   544 
       
   545 void CSpecialNbsSmsSocketWatcher::SetBioMsgText(CBIODatabase& /*aBioDb*/)
       
   546 	{
       
   547 	switch(iAddrFamily)
       
   548 		{
       
   549 	case ESmsAddrMessageIndication:
       
   550 		iBioMsgText = _L("Special Messages");
       
   551 		break;
       
   552 	case ESmsAddrStatusReport:
       
   553 		iBioMsgText = _L("Status Report");
       
   554 		break;
       
   555 	default:
       
   556 		PanicWatcher(EAddrFamilyNotSupported3);
       
   557 		break;
       
   558 		}
       
   559 	}
       
   560 
       
   561 void CSpecialNbsSmsSocketWatcher::PreStoreActionL(CMsvSession& aSession, CSmsMessage& aSmsMessage)
       
   562 	{
       
   563 	if( iAddrFamily == ESmsAddrStatusReport && 
       
   564 		(iReportHandling == CSmsSettings::EMoveReportToInboxInvisibleAndMatch ||
       
   565 		iReportHandling == CSmsSettings::EMoveReportToInboxVisibleAndMatch ||
       
   566 		iReportHandling == CSmsSettings::EDiscardReportAndMatch) )
       
   567 		{
       
   568 		// This is a Status Report and the matching has been requested - so
       
   569 		// do the matching!
       
   570 		TLogId logId = aSmsMessage.LogServerId();
       
   571 		CSmsStatusReport& report = static_cast<CSmsStatusReport&>(aSmsMessage.SmsPDU());
       
   572 		
       
   573 		MatchStatusReportL(aSession, logId, report.Status());
       
   574 		}	
       
   575 	}
       
   576 	
       
   577 void CSpecialNbsSmsSocketWatcher::MatchStatusReportL(CMsvSession& aSession, TLogId aLogId, TSmsStatus::TSmsStatusValue aDeliveryStatus)
       
   578 	{
       
   579 	// Need to check all SMS messages in the sent folder.
       
   580 	CMsvEntry* msvEntry = aSession.GetEntryL(KMsvSentEntryId);
       
   581 	CleanupStack::PushL(msvEntry);
       
   582 	
       
   583 	CMsvEntrySelection* selSent = msvEntry->ChildrenWithMtmL(KUidMsgTypeSMS);
       
   584 	CleanupStack::PushL(selSent);
       
   585 	
       
   586 	// Also need to check the Outbox - if the message failed to send at least
       
   587 	// one of its recipients then it will still be in the Outbox.
       
   588 	msvEntry->SetEntryL(KMsvGlobalOutBoxIndexEntryId);
       
   589 
       
   590 	CMsvEntrySelection* selOut = msvEntry->ChildrenWithMtmL(KUidMsgTypeSMS);
       
   591 	CleanupStack::PushL(selOut);
       
   592 	
       
   593 	// Create a header object here for efficiency
       
   594 	CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
       
   595 	CleanupStack::PushL(paraFormatLayer);
       
   596 	CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
       
   597 	CleanupStack::PushL(charFormatLayer);
       
   598 	CRichText* richText = CRichText::NewL(paraFormatLayer,charFormatLayer);
       
   599 	CleanupStack::PushL(richText);
       
   600 
       
   601 	CSmsHeader* header = CSmsHeader::NewL(CSmsPDU::ESmsSubmit, *richText);
       
   602 	CleanupStack::PushL(header);
       
   603 	
       
   604 	TMsvId messageId;
       
   605 	TBool found = SearchForMessageL(*msvEntry, *header, *selSent, aLogId, messageId);
       
   606 	
       
   607 	if( !found )
       
   608 		{
       
   609 		// Search the outbox just in case it is still there.
       
   610 		found = SearchForMessageL(*msvEntry, *header, *selOut, aLogId, messageId);
       
   611 		}
       
   612 	
       
   613 	if( found )
       
   614 		{
       
   615 		UpdateMessageEntryL(*msvEntry, *header, messageId, aLogId, aDeliveryStatus);
       
   616 		}
       
   617 
       
   618 	CleanupStack::PopAndDestroy(7, msvEntry);
       
   619 	}
       
   620 
       
   621 TBool CSpecialNbsSmsSocketWatcher::SearchForMessageL(CMsvEntry& aMsvEntry, CSmsHeader& aHeader, const CMsvEntrySelection& aSelection, TLogId aLogId, TMsvId& aMessageId)
       
   622 	{
       
   623 	TInt count = aSelection.Count();
       
   624 
       
   625 	if( count == 0 )
       
   626 		{
       
   627 		// Empty selection - cannot do search.
       
   628 		return EFalse;;
       
   629 		}
       
   630 		
       
   631 	TBool found = EFalse;
       
   632 	while( !found && count-- > 0 )
       
   633 		{
       
   634 		aMsvEntry.SetEntryL(aSelection.At(count));
       
   635 		TMsvSmsEntry entry = aMsvEntry.Entry();
       
   636 		
       
   637 		if( entry.AckSummary(ESmsAckTypeDelivery) == TMsvSmsEntry::EPendingAcks )
       
   638 			{
       
   639 			// This message is waiting for delivery report - is this it?
       
   640 			TLogId logId = 0;	
       
   641 			TBool validId = entry.MessageId(logId);
       
   642 			
       
   643 			if( validId )
       
   644 				{
       
   645 				// Check the logId is the one
       
   646 				if( aLogId == logId )
       
   647 					{
       
   648 					found = ETrue;
       
   649 					aMessageId = entry.Id();
       
   650 					}
       
   651 				}
       
   652 			else
       
   653 				{
       
   654 				// The long way round - restore the entry and search the list of 
       
   655 				// recipients.
       
   656 				CMsvStore* store = aMsvEntry.ReadStoreL();
       
   657 				CleanupStack::PushL(store);
       
   658 				aHeader.RestoreL(*store);	// no need to restore message body
       
   659 				CleanupStack::PopAndDestroy(store);
       
   660 				
       
   661 				TInt rcptCount = aHeader.Recipients().Count();
       
   662 				
       
   663 				while( !found && rcptCount-- > 0 )
       
   664 					{
       
   665 					CSmsNumber& rcpt = *aHeader.Recipients()[rcptCount];
       
   666 					
       
   667 					if( rcpt.AckStatus(ESmsAckTypeDelivery) == CSmsNumber::EPendingAck &&
       
   668 						rcpt.LogId() == aLogId )
       
   669 						{
       
   670 						found = ETrue;
       
   671 						aMessageId = entry.Id();
       
   672 						}					
       
   673 					}				
       
   674 				}
       
   675 			}
       
   676 		}
       
   677 	return found;
       
   678 	}
       
   679 	
       
   680 void CSpecialNbsSmsSocketWatcher::UpdateMessageEntryL(CMsvEntry& aMsvEntry, CSmsHeader& aHeader, TMsvId aMessageId, TLogId aLogId, TSmsStatus::TSmsStatusValue aDeliveryStatus)
       
   681 	{
       
   682 	// Set the entry - probably not necessary...
       
   683 	aMsvEntry.SetEntryL(aMessageId);
       
   684 	
       
   685 	// Update the message entry.
       
   686 	CMsvStore* store = aMsvEntry.EditStoreL();
       
   687 	CleanupStack::PushL(store);
       
   688 	aHeader.RestoreL(*store);	// no need to restore message body
       
   689 	
       
   690 	const TInt rcptCount = aHeader.Recipients().Count();
       
   691 	TInt pending = 0;
       
   692 	TInt fail = 0;
       
   693 	TInt last = 0;
       
   694 	TInt sent = 0;
       
   695 	
       
   696 	for( TInt count = 0; count < rcptCount; ++count )
       
   697 		{
       
   698 		CSmsNumber& rcpt = *aHeader.Recipients()[count];
       
   699 		
       
   700 		if( rcpt.Status() == CMsvRecipient::ESentSuccessfully )
       
   701 			{
       
   702 			++sent;
       
   703 		
       
   704 			CSmsNumber::TSmsAckStatus status = rcpt.AckStatus(ESmsAckTypeDelivery);
       
   705 			if( status == CSmsNumber::EPendingAck )
       
   706 				{
       
   707 				if(	rcpt.LogId() == aLogId )
       
   708 					{
       
   709 					// Update the recipient with the delivery status.
       
   710 					if( aDeliveryStatus == TSmsStatus::ESmsShortMessageReceivedBySME )
       
   711 						rcpt.SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EAckSuccessful);
       
   712 					else
       
   713 						{
       
   714 						// Recipient failed to get the message :(							
       
   715 						rcpt.SetAckStatus(ESmsAckTypeDelivery, CSmsNumber::EAckError);
       
   716 						rcpt.SetStatus(CMsvRecipient::EFailedToSend);
       
   717 						rcpt.SetError(aDeliveryStatus);
       
   718 						++fail;
       
   719 						}
       
   720 					}
       
   721 				else
       
   722 					{
       
   723 					// This message has recipients waiting for status reports...
       
   724 					++pending;
       
   725 					last = count;	// index to last pending recipient.
       
   726 					}
       
   727 				}
       
   728 			else if( status == CSmsNumber::EAckError )
       
   729 				{
       
   730 				// There is a recipient that failed to get the message
       
   731 				++fail;				
       
   732 				}
       
   733 			}
       
   734 		}
       
   735 		
       
   736 	// Store the updated recipient info
       
   737 	aHeader.StoreL(*store);
       
   738 	store->CommitL();
       
   739 	CleanupStack::PopAndDestroy(store);
       
   740 	
       
   741 	// Update the delivery summary info in the index...
       
   742 	// 1. EPendingAcks - there are still recipients waiting for status reports.
       
   743 	// 2. EAllSuccessful - all recipients were delivered to successfully.
       
   744 	// 3. EAllFailed - all recipients failed to be delivered to.
       
   745 	// 4. EMixed - a mixture of successful and failed deliveries to the recipients.
       
   746 	TMsvSmsEntry entry = aMsvEntry.Entry();
       
   747 	if( pending == 0 )
       
   748 		{
       
   749 		// Cases 2, 3 or 4 - check how many failed.
       
   750 		if( fail == 0 )
       
   751 			{
       
   752 			// Case 2 - EAllSuccessful.
       
   753 			entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EAllSuccessful);
       
   754 			}
       
   755 		else if( fail < sent )
       
   756 			{
       
   757 			// Case 4 - EMixed.
       
   758 			entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EMixed);
       
   759 			}
       
   760 		else
       
   761 			{
       
   762 			// Case 3 - EAllFailed.
       
   763 			entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EAllFailed);
       
   764 			}
       
   765 		}
       
   766 	else
       
   767 		{
       
   768 		// Case 1 - EPendingAcks.
       
   769 		entry.SetAckSummary(ESmsAckTypeDelivery, TMsvSmsEntry::EPendingAcks);
       
   770 		
       
   771 		if( (entry.iBioType == 0) && (pending == 1) )
       
   772 			{
       
   773 			// This message has only one pending recipient - update the entry to
       
   774 			// reflect this.
       
   775 			TLogId logId = aHeader.Recipients()[last]->LogId();
       
   776 			entry.SetMessageId(logId, ETrue);
       
   777 			}
       
   778 		}
       
   779 	aMsvEntry.ChangeL(entry);
       
   780 	}
       
   781 
       
   782 //SupportForClass0SmsL for launching the Class 0 SMS plugin, If Class 0 SMS support enabled from SMS Stack.
       
   783 void CNbsSmsSocketWatcher::SupportForClass0SmsL()
       
   784 	{
       
   785 	//if iStatus is KErrNotSupported, class 0 messages will be handled as normal Class2 messages
       
   786 	if( iStatus.Int() == KErrNone )
       
   787 		{
       
   788 		iMsgRefNumber = -1;
       
   789 		
       
   790 		//launch class 0 sms plugin 
       
   791 		iSmsClass0 = reinterpret_cast<CSmsClass0Base*>	
       
   792 								(REComSession::CreateImplementationL(
       
   793 														KUidClass0SmsHandler,
       
   794 														_FOFF(CNbsSmsSocketWatcher ,iDtor_ID_Key))); 
       
   795 		
       
   796 		}
       
   797 		
       
   798 		// Complete self to enter state machine
       
   799 		TRequestStatus* status = &iStatus;
       
   800 		iStatus=KRequestPending;
       
   801 		User::RequestComplete(status, KErrNone);
       
   802 	}	
       
   803 
       
   804 
       
   805 //externalize  start position, end position, isLastMessage flag and Class 0 SMS data,
       
   806 void CNbsSmsSocketWatcher::ExternalizeL(RBufWriteStream& aWriteStream, TInt aStartPos, TInt endPos, TBool aIsLastMessage, TPtr aData)
       
   807 	{
       
   808 	aWriteStream.WriteInt32L(aStartPos);
       
   809 	aWriteStream.WriteInt32L(endPos);
       
   810 	aWriteStream.WriteInt32L(aIsLastMessage);
       
   811 	aWriteStream << aData;
       
   812 	}