obex/obexprotocol/obex/src/obexclient.cpp
changeset 57 f6055a57ae18
parent 0 d0791faffa3f
equal deleted inserted replaced
54:4dc88a4ac6f4 57:f6055a57ae18
       
     1 // Copyright (c) 1997-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 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <charconv.h>
       
    22 #include <utf.h>
       
    23 #include <obex.h>
       
    24 #include <obextransportinfo.h>
       
    25 #include <obex/transport/obextransportcontrollerbase.h>
       
    26 #include <obex/internal/obextransportconstants.h>
       
    27 #include <obex/internal/obexinternalheader.h>
       
    28 #include <obex/internal/obexpacket.h>
       
    29 #include "logger.h"
       
    30 #include "obexsetpathdata.h"
       
    31 #include "OBEXUTIL.H"
       
    32 #include "obexheaderutil.h"
       
    33 #include "authentication.h"
       
    34 #include "obexpacketsignaller.h"
       
    35 #include "obexpackettimer.h"
       
    36 #include "obexnotifyhandlerclient.h"
       
    37 #include "obexerrorengine.h"
       
    38 
       
    39 #ifdef __FLOG_ACTIVE
       
    40 _LIT8(KLogComponent, "OBEX");
       
    41 #endif
       
    42 
       
    43 // Constant used to identify if the last received response code field
       
    44 // has been populated (i.e., if the first response has been received
       
    45 // from the OBEX server).  The response code field is only 7 bits (+ the
       
    46 // 'final bit') so the use of this 16 bit number will ensure the value
       
    47 // for KUnpopulatedResponseCode never overlaps with an actual code.
       
    48 const static TUint16 KUnpopulatedResponseCode = 0xffff;
       
    49 
       
    50 // For debug builds check that when an underlying error is set
       
    51 // it has not already been set since the start of the client operation
       
    52 // and check that a last error has been set when the operation completes.
       
    53 #define SET_LAST_ERROR(_error) __ASSERT_DEBUG(!iIsLastErrorSet, IrOBEXUtil::Fault(ELastErrorSetTwice)); iErrorEngine->SetLastError(CObexErrorEngine::_error); iIsLastErrorSet = ETrue
       
    54 #define CHECK_LAST_ERROR_IS_SET __ASSERT_DEBUG(iIsLastErrorSet, IrOBEXUtil::Fault(ELastErrorNotSet)); iIsLastErrorSet = EFalse
       
    55 
       
    56 
       
    57 // Constructor - set initial values
       
    58 CObexClient::CObexClient() : CObex()
       
    59 	{
       
    60 	iCurrentOperation = EOpIdle;
       
    61 	iConnectionID = KConnIDInvalid;
       
    62 	iLastReceivedResponseOpcode = static_cast<TObexResponse>(KUnpopulatedResponseCode);
       
    63 	}
       
    64 
       
    65 void CObexClient::ConstructL(TObexTransportInfo& aObexTransportInfo)
       
    66 	{
       
    67 	CObex::ConstructL(aObexTransportInfo);
       
    68 	iNotifyHandler = new(ELeave)CObexNotifyHandlerClient(*this);
       
    69 	iTransportController->SetOwner(*iNotifyHandler);
       
    70 
       
    71 	//	iHeaderSet is used to store headers received in Put Response
       
    72 	iHeaderSet = CObexHeaderSet::NewL();
       
    73 	iHeader = CObexHeader::NewL();
       
    74 	iPacketProcessSignaller = CObexPacketSignaller::NewL();
       
    75 	iErrorEngine = CObexErrorEngine::NewL();
       
    76 	iPacketTimer = CObexPacketTimer::NewL(*this);
       
    77 	}
       
    78 
       
    79 /** Destructor. 
       
    80 	
       
    81 @publishedAll
       
    82 @released
       
    83 */
       
    84 EXPORT_C CObexClient::~CObexClient()
       
    85 	{
       
    86 	LOG_LINE
       
    87 	LOG_FUNC
       
    88 
       
    89 	Error(KErrCompletion);
       
    90 	delete iHeader;
       
    91 	delete iHeaderSet;
       
    92 	delete iPacketProcessSignaller;
       
    93 	delete iNotifyHandler;
       
    94 	delete iErrorEngine;
       
    95 	delete iPacketTimer;
       
    96 	}
       
    97 
       
    98 /** A call back from the the service with the password required for use with generating 
       
    99 the challenge response. 
       
   100 
       
   101 @param aPassword Password
       
   102 
       
   103 @leave KErrNotReady if this function is not called from a MObexAuthChallengeHandler::GetUserPasswordL callback.
       
   104 
       
   105 @publishedAll
       
   106 @released
       
   107 */
       
   108 EXPORT_C void CObexClient::UserPasswordL(const TDesC& aPassword)
       
   109 	{
       
   110 	LOG_LINE
       
   111 	LOG_FUNC
       
   112 
       
   113 	//now have a password, get a nonce, and get it hashed then reply
       
   114 	FLOG(_L("CObexClient::UserPasswordL\n\r"));
       
   115 	if (GetConnectState() == EWaitForUserInput)
       
   116 		{
       
   117 		PrepareChallResponseL( aPassword); 
       
   118 
       
   119 		TObexInternalHeader hdr;
       
   120 		hdr.Set(TObexInternalHeader::EAuthResponse, CONST_CAST(TUint8*, iOutgoingChallResp.Ptr()), iOutgoingChallResp.Size());
       
   121 		FLOG(_L("CObexClient::UserPasswordL EAuth heaqder added\n\r")); 
       
   122 		if(iTransportController->SendPacket().InsertData(hdr))
       
   123 			{
       
   124 			SetConnectState(EWaitForFinalResponse);
       
   125 			iTransportController->SendPacket().SetFinal();
       
   126 			SendRequestPacket();
       
   127 			FLOG(_L("CObexClient::UserPasswordL packet sent\n\r")); 
       
   128 
       
   129 			}
       
   130 		else
       
   131 			{
       
   132 			LEAVEIFERRORL(KErrGeneral);
       
   133 			}
       
   134 		}
       
   135 	else
       
   136 		{
       
   137 		LEAVEIFERRORL(KErrNotReady);
       
   138 		}
       
   139 	}
       
   140 
       
   141 /** Allocates and constructs a new OBEX client object.
       
   142 
       
   143 The received protocol information object, aObexProtocolInfoPtr, specifies the transport protocol to use:
       
   144 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo 
       
   145 for Bluetooth, TObexUsbProtocolInfo for USB.
       
   146 
       
   147 @param aObexProtocolInfoPtr Protocol information object describing the transport to use
       
   148 @return New OBEX client object 
       
   149 	
       
   150 @publishedAll
       
   151 @released
       
   152 */
       
   153 EXPORT_C CObexClient* CObexClient::NewL(TObexProtocolInfo& aObexProtocolInfoPtr)
       
   154 	{
       
   155 	LOG_LINE
       
   156 	LOG_STATIC_FUNC_ENTRY
       
   157 
       
   158 	TObexProtocolPolicy defaultProtocolPolicy;	// no packet sizing policy specified, so use default	
       
   159 	TObexTransportInfo*  transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, defaultProtocolPolicy);
       
   160 	CleanupStack::PushL(transportInfo);
       
   161 	CObexClient* client = CObexClient::NewL(*transportInfo);
       
   162 	CleanupStack::PopAndDestroy(transportInfo);
       
   163 	return client;
       
   164 	}
       
   165 
       
   166 /** Allocates and constructs a new OBEX client object with packet sizing information.
       
   167 
       
   168 The received protocol information object, aObexProtocolInfoPtr, specifies the transport protocol to use:
       
   169 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo 
       
   170 for Bluetooth, TObexUsbProtocolInfo for USB.
       
   171 
       
   172 The aObexProtocolPolicy parameter specifies the packet sizing policy for this OBEX object.
       
   173 
       
   174 @param aObexProtocolInfoPtr Protocol information object describing the transport to use
       
   175 @param aObexProtocolPolicy Protocol policy object specifying the packet sizes to use
       
   176 @return New OBEX client object 
       
   177 	
       
   178 @publishedAll
       
   179 @released
       
   180 */
       
   181 EXPORT_C  CObexClient* CObexClient::NewL(TObexProtocolInfo& aObexProtocolInfoPtr, TObexProtocolPolicy& aObexProtocolPolicy)
       
   182 	{
       
   183 	LOG_LINE
       
   184 	LOG_STATIC_FUNC_ENTRY
       
   185 
       
   186 	TObexTransportInfo*  transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, aObexProtocolPolicy);
       
   187 	CleanupStack::PushL(transportInfo);
       
   188 	CObexClient* client = CObexClient::NewL(*transportInfo);
       
   189 	CleanupStack::PopAndDestroy(transportInfo);
       
   190 	return client;
       
   191 	}
       
   192 
       
   193 /** Allocates and constructs a new OBEX client object with packet sizing information.
       
   194 
       
   195 The received transport information object, aObexTransportInfo, specifies the transport protocol packet sizes to use:
       
   196 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo 
       
   197 for Bluetooth, TObexUsbProtocolInfo for USB.
       
   198 
       
   199 @param aObexTransportInfo  Transport information object describing the transport and packet sizes to use
       
   200 @return New OBEX client object 
       
   201 
       
   202 @capability WriteDeviceData If the TObexIrV3TransportInfo is passed as the argument
       
   203                             and the associated name is valid.
       
   204 	
       
   205 @publishedAll
       
   206 @released
       
   207 */
       
   208 EXPORT_C  CObexClient* CObexClient::NewL(TObexTransportInfo& aObexTransportInfo)
       
   209 	{
       
   210 	LOG_LINE
       
   211 	LOG_STATIC_FUNC_ENTRY
       
   212 
       
   213 	CObexClient* self = new(ELeave) CObexClient();
       
   214 	CleanupStack::PushL(self);
       
   215 	self->ConstructL(aObexTransportInfo);
       
   216 	CleanupStack::Pop(self);
       
   217 	return(self);
       
   218 	}
       
   219 
       
   220 /** OBEX CONNECT operation to any available remote machine, specifying an object 
       
   221 to pass.
       
   222 
       
   223 @param aObject OBEX object to pass to the remote machine
       
   224 @param aStatus Asynchronous status word. On completion, KErrNone if it was 
       
   225 successful, or a system-wide error code 	
       
   226 
       
   227 @publishedAll
       
   228 @released
       
   229 */
       
   230 EXPORT_C void CObexClient::Connect(CObexBaseObject& aObject, TRequestStatus& aStatus)
       
   231 	{
       
   232 	LOG_LINE
       
   233 	LOG_FUNC
       
   234 
       
   235 	if(!AlreadyActive(aStatus))
       
   236 		{
       
   237 		FLOG(_L("CObexClient::Connect no password but some header data\r\n"));
       
   238 		EmptyHeaderSet();
       
   239 		iChallenge = EFalse;
       
   240 		OBEX_TRAP(Error, ClientCommandL(EOpConnect, static_cast<TAny*>(&aObject), aStatus));
       
   241 		}
       
   242 	}
       
   243 
       
   244 /** OBEX CONNECT operation to any available remote machine, specifying an object 
       
   245 to pass and a password.
       
   246 
       
   247 @param aObject OBEX object to pass to the remote machine
       
   248 @param aPassword Password to access remote machine
       
   249 @param aStatus Asynchronous status word. On completion, KErrNone if it was 
       
   250 successful, or a system-wide error code 
       
   251 	
       
   252 @publishedAll
       
   253 @released
       
   254 */
       
   255 EXPORT_C void CObexClient::ConnectL(CObexBaseObject& aObject, const TDesC& aPassword, 
       
   256 								   TRequestStatus& aStatus)
       
   257 	{
       
   258 	LOG_LINE
       
   259 	LOG_FUNC
       
   260 
       
   261 	if(!AlreadyActive(aStatus))
       
   262 		{
       
   263 		FLOG(_L("CObexClient::Connect with password and some header info\r\n"));
       
   264 		EmptyHeaderSet();
       
   265 		delete iChallPassword;
       
   266 		iChallPassword = NULL;
       
   267 		iChallPassword = HBufC8::NewL(aPassword.Size());
       
   268 		TPtr8 ptr = iChallPassword->Des();
       
   269 		CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword);
       
   270 		iChallenge = ETrue;
       
   271 		OBEX_TRAP(Error, ClientCommandL(EOpConnect, static_cast<TAny*>(&aObject), aStatus));
       
   272 		}
       
   273 	}
       
   274 
       
   275 
       
   276 /** OBEX CONNECT operation to any available remote machine, specifying a password.
       
   277 
       
   278 @param aPassword Password to access remote machine
       
   279 @param aStatus On completion, KErrNone if it was successful, or a system-wide 
       
   280 error code 
       
   281 	
       
   282 @publishedAll
       
   283 @released
       
   284 */
       
   285 EXPORT_C void CObexClient::ConnectL(const TDesC& aPassword, TRequestStatus& aStatus)
       
   286 	{
       
   287 	LOG_LINE
       
   288 	LOG_FUNC
       
   289 
       
   290 	if(!AlreadyActive(aStatus))
       
   291 		{
       
   292 		FLOG(_L("CObexClient::Connect with password but no header info\r\n"));
       
   293 		EmptyHeaderSet();
       
   294 		delete iChallPassword;
       
   295 		iChallPassword = NULL;
       
   296 		iChallPassword = HBufC8::NewL(aPassword.Length());
       
   297 		TPtr8 ptr = iChallPassword->Des();
       
   298 		CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword);
       
   299 		iChallenge = ETrue;
       
   300 		OBEX_TRAP(Error, ClientCommandL(EOpConnect, NULL, aStatus));
       
   301 		}
       
   302 	}
       
   303 
       
   304 /** OBEX CONNECT operation to any available remote machine.
       
   305 
       
   306 @param aStatus Asynchronous status word. On completion, KErrNone if it was 
       
   307 successful, or a system-wide error code 
       
   308 	
       
   309 @publishedAll
       
   310 @released
       
   311 */
       
   312 EXPORT_C void CObexClient::Connect(TRequestStatus& aStatus)
       
   313 	{
       
   314 	LOG_LINE
       
   315 	LOG_FUNC
       
   316 
       
   317 	if(!AlreadyActive(aStatus))
       
   318 		{
       
   319 		FLOG(_L("\tno password no header"));
       
   320 		EmptyHeaderSet();
       
   321 		iChallenge = EFalse;
       
   322 		OBEX_TRAP(Error, ClientCommandL(EOpConnect, NULL, aStatus));
       
   323 		}
       
   324 	}
       
   325 
       
   326 /** OBEX DISCONNECT operation.
       
   327 
       
   328 This terminates the OBEX connection, and closes the transport on receiving 
       
   329 any response from the server. 
       
   330 
       
   331 @param aStatus Asynchronous status word. On completion, KErrNone on normal 
       
   332 disconnection, or KErrDisconnected if the server dropped the transport before 
       
   333 sending an OBEX response (which is valid behaviour). 
       
   334 	
       
   335 @publishedAll
       
   336 @released
       
   337 */
       
   338 EXPORT_C void CObexClient::Disconnect(TRequestStatus& aStatus)
       
   339 	{
       
   340 	LOG_LINE
       
   341 	LOG_FUNC
       
   342 
       
   343 	if(!AlreadyActive(aStatus))
       
   344 		{
       
   345 		FLOG(_L("CObexClient::Disconnect\r\n"));
       
   346 		EmptyHeaderSet();
       
   347 		OBEX_TRAP (Error, ClientCommandL(EOpDisconnect, NULL, aStatus));
       
   348 		}
       
   349 	}
       
   350 
       
   351 /** OBEX PUT operation.
       
   352 
       
   353 Any valid header that is also present in aObject’s header mask will be sent 
       
   354 to the server, along with the object body specified by the implementation 
       
   355 of aObject. 
       
   356 
       
   357 @param aObject OBEX object to put
       
   358 @param aStatus Asynchronous status word. On completion, KErrNone if the server 
       
   359 accepted the object and received it fully, or the appropriate file error if 
       
   360 the data file could not be opened 
       
   361 	
       
   362 @publishedAll
       
   363 @released
       
   364 */
       
   365 EXPORT_C void CObexClient::Put(CObexBaseObject& aObject, TRequestStatus& aStatus)
       
   366 	{
       
   367 	LOG_LINE
       
   368 	LOG_FUNC
       
   369 
       
   370 	if(!AlreadyActive(aStatus))
       
   371 		{
       
   372 		FLOG(_L("\tnot already active"));
       
   373 		EmptyHeaderSet();
       
   374 		OBEX_TRAP(Error, ClientCommandL(EOpPut, static_cast<TAny*>(&aObject), aStatus));
       
   375 		}
       
   376 	}
       
   377 
       
   378 /** OBEX GET operation.
       
   379 
       
   380 The caller specifies in aObject the headers to send to the server to specify 
       
   381 the object to get: normally just a name is expected. If the server can serve 
       
   382 the request, the object it returns will be loaded into aObject on completion. 
       
   383 All headers returned by the server that are also allowed by the object’s 
       
   384 header mask will be loaded into the relevant attributes of aObject. Any object 
       
   385 body is stored according to the implementation type of the CObexBaseObject 
       
   386 passed.
       
   387 
       
   388 @param aObject OBEX object to get; on completion, the retrieved object
       
   389 @param aStatus Asynchronous status word. On completion, KErrNone if the server 
       
   390 passed back an OBEX object, or the appropriate file error if the data file 
       
   391 could not be opened 
       
   392 	
       
   393 @publishedAll
       
   394 @released
       
   395 */
       
   396 EXPORT_C void CObexClient::Get(CObexBaseObject& aObject, TRequestStatus& aStatus)
       
   397 	{
       
   398 	LOG_LINE
       
   399 	LOG_FUNC
       
   400 
       
   401 	if(!AlreadyActive(aStatus))
       
   402 		{
       
   403 		FLOG(_L("CObexClient::Get\r\n"));
       
   404 		EmptyHeaderSet();
       
   405 		OBEX_TRAP(Error, ClientCommandL(EOpGet, static_cast<TAny*>(&aObject), aStatus));
       
   406 		}
       
   407 	}
       
   408 
       
   409 /** OBEX SETPATH operation.
       
   410 
       
   411 This changes the remote device's current path. 
       
   412 
       
   413 @param aPathInfo Information to send in the SETPATH command. If you do not 
       
   414 which to send a name, make sure CObex::TSetPathInfo::iNamePresent is set to 
       
   415 false.
       
   416 @param aStatus Asynchronous status word. On completion, KErrNone if successful, 
       
   417 or a system-wide error code 
       
   418 	
       
   419 @publishedAll
       
   420 @released
       
   421 */
       
   422 EXPORT_C void CObexClient::SetPath(TSetPathInfo& aPathInfo, TRequestStatus& aStatus)
       
   423 	{
       
   424 	LOG_LINE
       
   425 	LOG_FUNC
       
   426 
       
   427 	if(!AlreadyActive(aStatus))
       
   428 		{
       
   429 		FLOG(_L("CObexClient::SetPath\r\n"));
       
   430 		EmptyHeaderSet();
       
   431 		OBEX_TRAP(Error, ClientCommandL(EOpSetPath, static_cast<TAny*>(&aPathInfo), aStatus));
       
   432 		}
       
   433 	}
       
   434 
       
   435 /** OBEX ABORT operation.
       
   436 
       
   437 The function sends the OBEX abort command to the remote machine if a multi-packet 
       
   438 operation (i.e. PUT or GET) is in progress. An operation in progress will 
       
   439 complete with KErrAbort. 
       
   440 	
       
   441 @publishedAll
       
   442 @released
       
   443 */
       
   444 EXPORT_C void CObexClient::Abort()
       
   445 	{
       
   446 	LOG_LINE
       
   447 	LOG_FUNC
       
   448 
       
   449 	if(iPendingRequest &&(iCurrentOperation == EOpPut 
       
   450 							|| iCurrentOperation == EOpGet || iCurrentOperation == EOpGetResponse))
       
   451 		{
       
   452 		// We have two phase abort, async. abort request, followed by async. response
       
   453 		// To achive this without extra members we use extra operations in TOperation
       
   454 		// EOpAbortNoFBit for the asynchronous request
       
   455 		// EOpAbort for waiting for the response
       
   456 		iCurrentOperation = EOpAbortNoFBit;
       
   457 		}
       
   458 	}
       
   459 
       
   460 /**
       
   461 This function can be called following the successful completion of a Put,
       
   462 and will return a reference to a CObexHeaderSet containing all the headers
       
   463 that were contained in the final Put response packet returned from the 
       
   464 peer Obex server.
       
   465 
       
   466 The headers in the header set will be deleted by any subsequent call to 
       
   467 CObexClient functions that trigger Obex commands (ie. Connect, Disconnect, 
       
   468 Put, Get, SetPath).
       
   469 
       
   470 The reference should not be retained beyond the end of the lifetime of the
       
   471 CObexClient object.
       
   472 
       
   473 @publishedAll
       
   474 @released
       
   475 
       
   476 @return const reference to a Headerset containing headers returned in final
       
   477 Put response packet.
       
   478 */
       
   479 EXPORT_C const CObexHeaderSet& CObexClient::GetPutFinalResponseHeaders()
       
   480 	{
       
   481 	LOG_LINE
       
   482 	LOG_FUNC
       
   483 
       
   484 	return *iHeaderSet;
       
   485 	}
       
   486 
       
   487 /** Sets a final packet observer.
       
   488 
       
   489 This replaces any previous observer.  The observer will receive a callback
       
   490 when a final packet for a put or get request begins to be sent and 
       
   491 another when the send completes.  Although the start and finish callbacks
       
   492 are guaranteed to be in order, no guarantees are made about the ordering
       
   493 with respect to the completion of the put or get request.
       
   494 
       
   495 This does not transfer ownership.
       
   496 
       
   497 @publishedAll
       
   498 @released
       
   499 @param aObserver The observer to receive packet process events.  This may
       
   500 				 be NULL.
       
   501 */
       
   502 EXPORT_C void CObexClient::SetFinalPacketObserver(MObexFinalPacketObserver* aObserver)
       
   503 	{
       
   504 	iPacketProcessSignaller->SetFinalPacketObserver(aObserver);
       
   505 	}
       
   506 
       
   507 /** Get last server response code
       
   508 This method returns the last received OBEX response code.
       
   509 The method must not be called prior to a response notification being received by the
       
   510 client application.  If the method is called a panic will be raised. 
       
   511 
       
   512 @return The last received OBEX response code.
       
   513 @panic ENoResponseCodeToReturn   Panics if the method is called prior to a response being received from the OBEX server.  
       
   514 @publishedAll
       
   515 @released
       
   516 */
       
   517 EXPORT_C TObexResponse CObexClient::LastServerResponseCode() const
       
   518 	{	
       
   519 	LOG_LINE
       
   520 	LOG_FUNC
       
   521 	// If the last received response code has not been set (i.e., no response has been received) then panic
       
   522 	// the client.
       
   523 	__ASSERT_ALWAYS(iLastReceivedResponseOpcode != KUnpopulatedResponseCode, IrOBEXUtil::Panic(ENoResponseCodeToReturn));
       
   524 	return iLastReceivedResponseOpcode;
       
   525 	}
       
   526 
       
   527 /** Sets the Command Idle Time-out.
       
   528 
       
   529 This function sets the timer period to be observed during the progress of
       
   530 all OBEX commands. If the OBEX server does not respond within the set period
       
   531 the current OBEX command will be completed with an error of KErrIrObexRespTimedOut
       
   532 and the transport will be disconnected. 
       
   533 
       
   534 Setting a time-out value of 0, all OBEX commands will be allowed to continue
       
   535 indefinitely.
       
   536 
       
   537 @param aTimeOut The time-out period in Microseconds.
       
   538 @publishedAll
       
   539 @released
       
   540 */
       
   541 EXPORT_C void CObexClient::SetCommandTimeOut(TTimeIntervalMicroSeconds32 aTimeOut)
       
   542 	{
       
   543 	LOG_LINE
       
   544 	LOG_FUNC	
       
   545 	iCmdTimeOutDuration = aTimeOut;	
       
   546 	}
       
   547 
       
   548 TBool CObexClient::AlreadyActive(TRequestStatus& aStatus)
       
   549 //can't do more than one request at atime
       
   550 	{
       
   551 	if(iPendingRequest)
       
   552 		{
       
   553 		TRequestStatus* tempStatus = &aStatus;
       
   554 		User::RequestComplete(tempStatus,KErrAccessDenied);
       
   555 		return ETrue;
       
   556 		}
       
   557 	return EFalse;
       
   558 	}
       
   559 
       
   560 void CObexClient::ResetConnectionID()
       
   561 	{
       
   562 	iConnectionID = KConnIDInvalid;
       
   563 	iConnectionIdSet = EFalse;
       
   564 	}
       
   565 			
       
   566 void CObexClient::SetConnectionID(TUint32 aConnectionID)
       
   567 	{
       
   568 	iConnectionID = aConnectionID;
       
   569 	iConnectionIdSet = ETrue;
       
   570 	}
       
   571 	
       
   572 void CObexClient::ClientCommandL(TOperation aOp, TAny* aParam, TRequestStatus& aStatus)
       
   573 	{
       
   574 	LOG_LINE
       
   575 	LOG_FUNC
       
   576 	
       
   577 	// Note: Function Calls to this method must be enclosed with an if statement utilising
       
   578 	// 		 CObexClient::AlreadyActive
       
   579 
       
   580 	SetRequest(aStatus, aOp);
       
   581 	if(aOp != EOpConnect &&(GetConnectState() != EConnObex || iTransportController == NULL))
       
   582 		{
       
   583 		SET_LAST_ERROR(EDisconnected);
       
   584 		LEAVEIFERRORL(KErrDisconnected);
       
   585 		}
       
   586 
       
   587 	switch(aOp)
       
   588 		{
       
   589 	case EOpConnect:
       
   590 		{
       
   591 		switch(GetConnectState())
       
   592 			{
       
   593 		case EConnIdle:
       
   594 			{
       
   595 			// Don t start the Packet timer, It will be done once the Transport is up(see :onTransportUp)
       
   596 			ResetConnectionID(); //set connection ID to invalid and flag to EFalse
       
   597 			iCurrentObject = static_cast<CObexBaseObject*>(aParam);
       
   598 			TRAPD(err, iTransportController->ConnectL());
       
   599 			if (err != KErrNone)
       
   600 				{
       
   601 				SET_LAST_ERROR(ETransportUpFailed);
       
   602 				LEAVEIFERRORL(err);
       
   603 				}
       
   604 			}
       
   605  			break;
       
   606 		case EConnTransport:
       
   607 			iCurrentObject = static_cast<CObexBaseObject*>(aParam);
       
   608 			//Transport is already connected just do the connection
       
   609 			//Previously TransportUp was called.  However the transport is already connected
       
   610 			//thus the only required actions are the following.  
       
   611 			OnTransportUp();
       
   612 			iTransportController->Receive();
       
   613 			break;
       
   614 		default:
       
   615 			SET_LAST_ERROR(EAlreadyConnected);
       
   616 			CompleteRequest(KErrAlreadyExists);
       
   617 			}
       
   618 		}
       
   619 		break;
       
   620 	case EOpDisconnect:
       
   621 		{
       
   622 		iTransportController->SendPacket().Init(TUint8(EOpDisconnect));
       
   623 		iTransportController->SendPacket().SetFinal();
       
   624 
       
   625 		// Insert the ConnectionID if necessary
       
   626 		if (iConnectionIdSet)
       
   627 			{
       
   628 						 
       
   629 			TObexInternalHeader connectionID; 
       
   630 			connectionID.Set(TObexInternalHeader::EConnectionID, iConnectionID);
       
   631 			 
       
   632 			if(!iTransportController->SendPacket().InsertData(connectionID))
       
   633 				{
       
   634 				LEAVEIFERRORL(KErrOverflow);
       
   635 				}
       
   636 			}
       
   637 		SendRequestPacket();
       
   638 		}
       
   639 		break;
       
   640 	case EOpPut:
       
   641 	case EOpGet:
       
   642 	// The Put and Get "request" state machines are identical
       
   643 	// and live inside the object streamer.
       
   644 		{
       
   645 		//
       
   646 		// For 'Get' the params are what to 'Get' and where to put it
       
   647 		// For 'Put' the params are what to put
       
   648 		// Either way we need to send a request based on the params
       
   649 		iCurrentObject = static_cast<CObexBaseObject*>(aParam);
       
   650 
       
   651 		// Initialise the object ready for sending
       
   652 		TInt err = iCurrentObject->InitSend(TObexOpcode(aOp));
       
   653 		if (err != KErrNone)
       
   654 			{
       
   655 			SET_LAST_ERROR(ECannotInitialiseObject);
       
   656 			LEAVEIFERRORL(err);
       
   657 			}
       
   658 
       
   659 		//if a ConnectionID was added then it's important to add the Connection ID
       
   660 		//header here, allow it to be processed by PrepareNextSendPacket
       
   661 		if ( iConnectionIdSet )
       
   662 			{
       
   663 			FLOG(_L("\tiConnectionIdSet is true"));
       
   664 			TRAPD(err, iCurrentObject->SetConnectionIdL(iConnectionID));
       
   665 			if (err != KErrNone)
       
   666 				{
       
   667 				SET_LAST_ERROR(ECannotSetConnectionId);
       
   668 				LEAVEIFERRORL(err);
       
   669 				}
       
   670 			}
       
   671 
       
   672 		// If we can...
       
   673 		if(iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket()) != CObexBaseObject::EError)
       
   674 			{	
       
   675 			iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished);
       
   676 					
       
   677 			// ...send the first request packet
       
   678 			FLOG(_L("\tsending first request packet..."));
       
   679 			SendRequestPacket();
       
   680 			}
       
   681 		else
       
   682 			{
       
   683 			FLOG(_L("\tleaving..."));
       
   684 			SET_LAST_ERROR(ECannotPreparePacket);
       
   685 			LEAVEIFERRORL(KErrGeneral);
       
   686 			}
       
   687 		}
       
   688 		break;
       
   689 
       
   690 	case EOpSetPath:
       
   691 		{// Build up a setinfo packet and send it.
       
   692 		TSetPathInfo* info = static_cast<TSetPathInfo*>(aParam);
       
   693 
       
   694 		iTransportController->SendPacket().Init(TUint8(aOp)); 
       
   695 		iTransportController->SendPacket().SetFinal();
       
   696 
       
   697 		TObexSetPathData data;
       
   698 		data.iFlags = info->iFlags;
       
   699 		data.iConstants = info->iConstants;
       
   700 		if(!iTransportController->SendPacket().InsertData(data))
       
   701 			{
       
   702 			LEAVEIFERRORL(KErrOverflow);
       
   703 			}
       
   704 
       
   705 		//insert the ConnectionID if necessary
       
   706 		if ( iConnectionIdSet )
       
   707 			{ 
       
   708 			
       
   709 			TObexInternalHeader connectionID;
       
   710 			connectionID.Set(TObexInternalHeader::EConnectionID, iConnectionID); 
       
   711 			
       
   712 			if(!iTransportController->SendPacket().InsertData(connectionID))
       
   713 				{
       
   714 				LEAVEIFERRORL(KErrOverflow);
       
   715 				}
       
   716 			}
       
   717 		if(info->iNamePresent)
       
   718 			{
       
   719 			TObexInternalHeader name;
       
   720 			name.Set(TObexInternalHeader::EName, info->iName);
       
   721 			if(!iTransportController->SendPacket().InsertData(name))
       
   722 				{
       
   723 				LEAVEIFERRORL(KErrOverflow);
       
   724 				}
       
   725 			}
       
   726 		SendRequestPacket();
       
   727 		break;
       
   728 		}
       
   729 	default:
       
   730 		IrOBEXUtil::Fault(EClientCommandOpUnrecognised);
       
   731 		}
       
   732 
       
   733 	}
       
   734 
       
   735 void CObexClient::OnPacketReceive(CObexPacket& aPacket)
       
   736 	{
       
   737 	LOG_LINE
       
   738 	LOG_FUNC
       
   739 	
       
   740 	//Cancel the timer
       
   741 	if (iPacketTimer->IsActive())
       
   742 		{
       
   743 		iPacketTimer->Cancel();
       
   744 		}
       
   745 	
       
   746 	// Store the response code including the 'final bit'.
       
   747 	iLastReceivedResponseOpcode = static_cast<TObexResponse>(aPacket.Opcode() | (aPacket.IsFinal() ? KObexPacketFinalBit : 0));
       
   748 	
       
   749 	if(iTransportController->IsWriteActive())
       
   750 		{
       
   751 		FLOG(_L("OnPacketReceive received request whilst writing... dropping connection\r\n"));
       
   752 		SET_LAST_ERROR(EResponseWhileWriting);
       
   753 		CompleteRequest(KErrNone);
       
   754 		ControlledTransportDown();
       
   755 		return;
       
   756 		}
       
   757 
       
   758 	// Initialise the send packet to ensure that we do not
       
   759 	// accidentally send the same packet as last time!
       
   760 	iTransportController->SendPacket().Init(0);
       
   761 
       
   762 	switch(iCurrentOperation)
       
   763 		{
       
   764 	case EOpConnect:
       
   765 		{
       
   766 		FLOG(_L("CObexClient::OnPacketReceive Connect OpCode\r\n"));
       
   767 		if(ParseConnectPacket(aPacket) == KErrNone)
       
   768 			{
       
   769 			FLOG(_L("OnPacketReceive Connect Packet parsed \r\n"));
       
   770 
       
   771 			//the request is only completed if now connected
       
   772 			if(GetConnectState() == EConnObex)
       
   773 				{
       
   774 				SET_LAST_ERROR(ENoError);
       
   775 				CompleteRequest(KErrNone);
       
   776 				}
       
   777 			else //otherwise still some outstanding issues
       
   778 				{
       
   779 				iTransportController->SendPacket().Init(EOpConnect); 
       
   780 				TInt err = PrepareConnectPacket(iTransportController->SendPacket());
       
   781 				if( err == KErrNone )
       
   782 					{
       
   783 					FLOG(_L("OnPacketReceive PrepareConnectPacket SUCCESS\r\n"));
       
   784 
       
   785 					iTransportController->SendPacket().SetFinal();
       
   786 					SendRequestPacket();
       
   787 					}
       
   788 				else if ( GetConnectState() != EWaitForUserInput )
       
   789 					{
       
   790 					FLOG(_L("OnPacketReceive PrepareConnectPacket FAILED\r\n"));
       
   791 					// Last underlying error already set in PrepareConnectPacket().
       
   792 					Error(err);
       
   793 					}
       
   794 				}
       
   795 			}
       
   796 		else
       
   797 			{
       
   798 			FLOG(_L("OnPacketReceive Connect Packet Parse FAILED\r\n"));
       
   799 			// Last underlying error already set in ParseConnectPacket().
       
   800 			Error(KErrAbort);
       
   801 			}
       
   802 		}
       
   803 		break;
       
   804 	case EOpDisconnect:
       
   805 		{
       
   806 		FLOG(_L("CObexClient::OnPacketReceive DisConnect OpCode\r\n"));
       
   807 		switch (aPacket.Opcode())
       
   808 			{
       
   809 			case ERespSuccess:
       
   810 				{
       
   811 				SET_LAST_ERROR(ENoError);
       
   812 				CompleteRequest(KErrNone);
       
   813 				}
       
   814 				break;
       
   815 			case ERespServiceUnavailable:
       
   816 				{
       
   817 				SET_LAST_ERROR(EBadConnectionId);
       
   818 				CompleteRequest(KErrDisconnected);
       
   819 				}
       
   820 				break;
       
   821 			default:
       
   822 				{
       
   823 				SET_LAST_ERROR(EErrorResponseFromServer);
       
   824 				CompleteRequest(KErrDisconnected);
       
   825 				}
       
   826 			}
       
   827 		
       
   828 		ControlledTransportDown(); // Bring down the transport anyway, otherwise we could end up in a situation where we can't
       
   829 		}
       
   830 		break;
       
   831 	case EOpPut:
       
   832 		{
       
   833 		FLOG(_L("CObexClient::OnPacketReceive Put OpCode\r\n"));
       
   834 		if(!aPacket.IsFinal())
       
   835 			{// Multipacket responses not allowed.
       
   836 			SET_LAST_ERROR(EMultipacketResponse);
       
   837 			Error(KErrCommsOverrun);	
       
   838 			break;
       
   839 			}
       
   840 		if(aPacket.Opcode() != ERespContinue 
       
   841 			&& aPacket.Opcode() != ERespSuccess
       
   842 			&& aPacket.Opcode() != ERespPartialContent)
       
   843 			{// Server has returned an OBEX error response. Deal with it...
       
   844 			TInt err = IrOBEXUtil::EpocError(aPacket.Opcode());
       
   845 			LOG1(_L8("Put error: %d"), err);
       
   846 			SET_LAST_ERROR(EErrorResponseFromServer);
       
   847 			CompleteRequest(err);
       
   848 			break;
       
   849 			}
       
   850 
       
   851 		{
       
   852 		CObexBaseObject::TProgress progress = 
       
   853 			iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket());
       
   854 		iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished);
       
   855 
       
   856 		// Work around for a problem both with some DoCoMo phones and Windows 2000:
       
   857 		// Their server sends "Success" when it should actually send "Continue",
       
   858 		// so we accept either here.
       
   859 		if (((progress == CObexBaseObject::EContinue || progress == CObexBaseObject::ELastPacket)
       
   860 			&& (aPacket.Opcode () == ERespContinue || aPacket.Opcode () == ERespSuccess))||
       
   861 			(progress == CObexBaseObject::EComplete 
       
   862 			&& (aPacket.Opcode() == ERespContinue )))
       
   863 			{// More stuff to send.
       
   864 			SendRequestPacket();
       
   865 			}
       
   866 		else if(progress == CObexBaseObject::EComplete 
       
   867 			     && (aPacket.Opcode() == ERespSuccess || aPacket.Opcode() == ERespPartialContent ))
       
   868 			{// We've completed okay.
       
   869 			//	There may be headers to extract from this final put response
       
   870 			TObexInternalHeader header;
       
   871 
       
   872 			while(aPacket.ExtractData(header))
       
   873 				{
       
   874 				FLOG(_L("OnPacketReceive Extracting header from final Put Response"));
       
   875 				TInt err=IrOBEXHeaderUtil::ParseHeader(header, *iHeaderSet);
       
   876 				if(err != KErrNone)
       
   877 					{
       
   878 					SET_LAST_ERROR(ECannotExtractFinalPutHeader);
       
   879 					Error(err);
       
   880 					}
       
   881 				}
       
   882 			TInt err = IrOBEXUtil::EpocError(aPacket.Opcode());
       
   883 			if (err == KErrNone)
       
   884 				{
       
   885 				SET_LAST_ERROR(ENoError);
       
   886 				}
       
   887 			else
       
   888 				{
       
   889 				SET_LAST_ERROR(EErrorResponseFromServer);
       
   890 				}
       
   891 			CompleteRequest(err);
       
   892 			}
       
   893 		else
       
   894 			{// We're out of sync with server. Give up.
       
   895 			SET_LAST_ERROR(EPutOutOfSync);
       
   896 			Error(KErrGeneral);
       
   897 			}
       
   898 		}
       
   899 		break;
       
   900 		}
       
   901 	case EOpGet:
       
   902 		{
       
   903 		FLOG(_L("CObexClient::OnPacketReceive Get OpCode\r\n"));
       
   904 		if(!aPacket.IsFinal())
       
   905 			{
       
   906 			SET_LAST_ERROR(EMultipacketResponse);
       
   907 			Error(KErrCommsOverrun); //??? WTF? Comms overrun?
       
   908 			break;
       
   909 			}
       
   910 
       
   911 		// There's only two valid responses to a 'Get' Request...
       
   912 		TUint8 respCode = aPacket.Opcode();
       
   913 		if( respCode != ERespContinue &&
       
   914 			respCode != ERespSuccess )
       
   915 			// ... and if we didn't get one of them...
       
   916 			{
       
   917 			// ...there's not much else we can do
       
   918 			SET_LAST_ERROR(EErrorResponseFromServer);
       
   919 			CompleteRequest(IrOBEXUtil::EpocError(respCode));
       
   920 			break;
       
   921 			}
       
   922 
       
   923 		// Now we know the response was probably valid, see if we need 
       
   924 		// to send another request packet
       
   925 		CObexBaseObject::TProgress progress;
       
   926 		progress = iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket());
       
   927 		
       
   928 		if( progress != CObexBaseObject::EComplete &&
       
   929 		    progress != CObexBaseObject::ELastPacket)
       
   930 			// We're not done sending the request yet. 
       
   931 			{
       
   932 			// So we'd better not have got a 'Success' from the remote end
       
   933 			if( progress == CObexBaseObject::EContinue &&
       
   934 				respCode == ERespContinue)
       
   935 				{
       
   936 				iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished);
       
   937 				
       
   938 				// Not finished sending the request yet, so send the next packet
       
   939 				SendRequestPacket();
       
   940 				}
       
   941 			else
       
   942 				{
       
   943 				// Something went wrong - can't continue.
       
   944 				SET_LAST_ERROR(EGetPrematureSuccess);
       
   945 				CompleteRequest(KErrGeneral);
       
   946 				}
       
   947 
       
   948 			// We're done with this packet
       
   949 			break;
       
   950 			}
       
   951 
       
   952 		// Still here? We MUST have got an EComplete from the sending state 
       
   953 		// machine. That means that the response we're handling RIGHT NOW is 
       
   954 		// the first packet of the thing we are 'Get'ting.
       
   955 
       
   956 		// Must initialise the object to receive the data from the server
       
   957 		iCurrentObject->InitReceive();
       
   958 		// Change state so we handle the next response properly
       
   959 		iCurrentOperation = EOpGetResponse;
       
   960 		}
       
   961 		// ** NB ** NO BREAK - DROP THROUGH TO HANDLE THE RESPONSE
       
   962 	case EOpGetResponse:
       
   963 	// Expecting a possibly multi-packet 'Get' response
       
   964 		{
       
   965 		FLOG(_L("CObexClient::OnPacketReceive GetResponse OpCode"));
       
   966 
       
   967 		if(iCurrentObject->ParseNextReceivePacket(aPacket) == CObexBaseObject::EError)
       
   968 			{
       
   969 			SET_LAST_ERROR(EGetResponseParseError);
       
   970 			Error(KErrGeneral);
       
   971 			break;
       
   972 			}
       
   973 		if(aPacket.Opcode() == ERespContinue)
       
   974 			{
       
   975 			// Send a blank 'Get' request to solicit the next bit of the response
       
   976 			SendRequestPacket(EOpGet);
       
   977 			FTRACE(iTransportController->SendPacket().Dump());
       
   978 			}
       
   979 		else
       
   980 			{
       
   981 			// Got all of the response, give it to the user
       
   982 			if (aPacket.Opcode() == ERespSuccess)
       
   983 				{
       
   984 				SET_LAST_ERROR(ENoError);
       
   985 				}
       
   986 			else
       
   987 				{
       
   988 				SET_LAST_ERROR(EErrorResponseFromServer);
       
   989 				}
       
   990 			CompleteRequest(IrOBEXUtil::EpocError(aPacket.Opcode()));
       
   991 			}
       
   992 		}
       
   993 		break;
       
   994 	case EOpSetPath:
       
   995 		FLOG(_L("CObexClient::OnPacketReceive Set Path OpCode\r\n"));
       
   996 		if (aPacket.Opcode() == ERespSuccess)
       
   997 			{
       
   998 			SET_LAST_ERROR(ENoError);
       
   999 			}
       
  1000 		else
       
  1001 			{
       
  1002 			SET_LAST_ERROR(EErrorResponseFromServer);
       
  1003 			}
       
  1004 		CompleteRequest(IrOBEXUtil::EpocError(aPacket.Opcode()));
       
  1005 		break;
       
  1006 	case EOpAbortNoFBit:
       
  1007 		FLOG(_L("CObexClient::OnPacketReceive Abort NoFBit OpCode\r\n"));
       
  1008 		SendRequestPacket(EOpAbort);
       
  1009 		iCurrentOperation = EOpAbort;
       
  1010 		break;
       
  1011 	case EOpAbort:
       
  1012 		{
       
  1013 		FLOG(_L("CObexClient::OnPacketReceive Abort OpCode\r\n"));
       
  1014 
       
  1015 		SET_LAST_ERROR(EAborted);
       
  1016 		if(aPacket.IsFinal() && aPacket.Opcode() == ERespSuccess)
       
  1017 			{// Just complete the put/get with code aborted
       
  1018 			CompleteRequest(KErrAbort);
       
  1019 			}
       
  1020 		else
       
  1021 			{// Report an error while aborting -> causes a disconnect
       
  1022 			Error(KErrAbort);
       
  1023 			}
       
  1024 		}
       
  1025 		break;
       
  1026 	default:
       
  1027 //		FPrint(_L("CObexClient::OnPacketReceive unknown opcode 0x%X!"),
       
  1028 //			iCurrentOperation);
       
  1029 		break;
       
  1030 		}
       
  1031 
       
  1032 	// Client has finished with the read packet so queue the next read (if necessary)
       
  1033 	if(iConnectState >= EConnTransport)
       
  1034 		{
       
  1035 		iTransportController->Receive();
       
  1036 		}
       
  1037 
       
  1038 	}
       
  1039 
       
  1040 TInt CObexClient::ParseConnectPacket(CObexPacket& aPacket)
       
  1041 	{
       
  1042 	TInt retValue = KErrNone;
       
  1043 	TConnectState nextState = EDropLink;
       
  1044 
       
  1045 	if(!iTransportController || !iTransportController->ExtractRemoteConnectInfo(aPacket, iRemoteInfo.iVersion, iRemoteInfo.iFlags))
       
  1046 		{
       
  1047 		FLOG(_L("CObexClient::ParseConnectPacket Extract Remote Info FAILED\r\n"));
       
  1048 		SET_LAST_ERROR(ECannotExtractConnectInfo);
       
  1049 		return KErrGeneral;
       
  1050 		}
       
  1051 	FLOG(_L("CObexClient::ParseConnectPacket Extract Remote Info Success\r\n"));
       
  1052 
       
  1053 	TObexInternalHeader hdr;
       
  1054 
       
  1055 	if ( aPacket.Opcode() == ERespSuccess )
       
  1056 		{
       
  1057 		FLOG(_L("ParseConnectPacket ERespSuccess Opcode\r\n"));
       
  1058 
       
  1059 		//if a simple connect was originally requested
       
  1060 		//then a simple ERespSuccess without any headers is enough
       
  1061 		if ( GetConnectState() == ESimpleConnRequest )
       
  1062 			nextState = EConnObex;
       
  1063 		//if responding to a chall from the server
       
  1064 		if (( GetConnectState() == EWaitForFinalResponse)&&(!iChallenge)) 
       
  1065 			nextState = EConnObex;
       
  1066 		while(aPacket.ExtractData(hdr))
       
  1067 			{
       
  1068 			switch(hdr.HI()) 
       
  1069 				{
       
  1070 				case TObexInternalHeader::EWho:
       
  1071 					{
       
  1072 					FLOG(_L("ParseConnectPacket Extracting EWHO header\r\n"));
       
  1073 					iRemoteInfo.iWho.Copy(hdr.HVByteSeq(), hdr.HVSize() > iRemoteInfo.iWho.MaxSize() ? iRemoteInfo.iWho.MaxSize() : hdr.HVSize());
       
  1074 					}
       
  1075 				break;
       
  1076 				case TObexInternalHeader::EConnectionID:
       
  1077 					{
       
  1078 					FLOG(_L("ParseConnectPacket Extracting EConnectionID header\r\n"));
       
  1079 
       
  1080 					TUint32 newConnectionID = ((hdr.HVByteSeq()[0] << 24) + (hdr.HVByteSeq()[1] << 16) + (hdr.HVByteSeq()[2] << 8) + (hdr.HVByteSeq()[3]));
       
  1081 					SetConnectionID(newConnectionID);
       
  1082 					
       
  1083 					if ( GetConnectState() == ESimpleConnRequest )
       
  1084 						{
       
  1085 						nextState = EConnObex;
       
  1086 						}
       
  1087 					}		
       
  1088 					break;
       
  1089 				case TObexInternalHeader::EAuthResponse: 
       
  1090 					{
       
  1091 					if (iChallenge)
       
  1092 						{
       
  1093 						FLOG(_L("ParseConnectPacket Extracting EAuthResponse header\r\n"));
       
  1094 						//extract the response into it's constituent parts
       
  1095 						TRAPD(err, ProcessChallResponseL(hdr));
       
  1096 						if ( err == KErrNone )
       
  1097 							{
       
  1098 							FLOG(_L("ParseConnectPacket ProcessChallResponse Success\r\n"));
       
  1099 	
       
  1100 							if ((GetConnectState() == EChallConnRequested) || ( GetConnectState() == EWaitForFinalResponse))
       
  1101 								{
       
  1102 								nextState = EConnObex;
       
  1103 								}
       
  1104 							else
       
  1105 								{
       
  1106 								SET_LAST_ERROR(EUnexpectedChallengeResponse);
       
  1107 								nextState = EDropLink;
       
  1108 								retValue = KErrGeneral;
       
  1109 								}
       
  1110 							}
       
  1111 						else
       
  1112 							{
       
  1113 							FLOG(_L("ParseConnectPacket ProcessChallResponse FAILED\r\n"));
       
  1114 							SET_LAST_ERROR(ECannotProcessChallenge);
       
  1115 							nextState = EDropLink;
       
  1116 							retValue = KErrGeneral;
       
  1117 							}
       
  1118 						}
       
  1119 					else
       
  1120 						{
       
  1121 						// if no challenge was issued, then receiving a challenge response means the peer is badly
       
  1122 						// behaved. For this case we simply ignore the header, anything else would be too drastic.
       
  1123 						FLOG(_L("ParseConnectPacket Chall Response received when no Chall issued\r\n"));
       
  1124 						}
       
  1125 					}	
       
  1126 					break;
       
  1127 				default:
       
  1128 					break;
       
  1129 				}//end switch
       
  1130 			}//end while		
       
  1131 		}
       
  1132 	else if (aPacket.Opcode() == ERespUnauthorized )
       
  1133 		{
       
  1134 		FLOG(_L("ParseConnectPacket ERespUnauthorized Opcode\r\n"));
       
  1135 		// Only valid header here is AuthChallenge, if it's absent then authentication failed.
       
  1136 		TBool challengeAbsent = ETrue;
       
  1137 		while(aPacket.ExtractData(hdr))
       
  1138 			{
       
  1139 			switch(hdr.HI()) 
       
  1140 				{
       
  1141 				case TObexInternalHeader::EAuthChallenge: 
       
  1142 					{
       
  1143 					FLOG(_L("ParseConnectPacket Extracting EAuthChallenge header\r\n"));
       
  1144 					challengeAbsent = EFalse;
       
  1145 					TRAPD(err, ProcessChallengeL(hdr));
       
  1146 					if ( !err )
       
  1147 						{
       
  1148 						nextState = EConnChallRxed;
       
  1149 						retValue = KErrNone;
       
  1150 						}
       
  1151 					else
       
  1152 						{
       
  1153 						SET_LAST_ERROR(ECannotProcessChallenge);
       
  1154 						retValue = KErrGeneral;
       
  1155 						}
       
  1156 #ifdef TEST_CLIENT_CHANGES_ITS_MIND_ABOUT_CHALLENGE
       
  1157 						//this will force the client to challenge the server
       
  1158 						//even if it didn't challenge initially
       
  1159 						//this is not standard behaviour for our client
       
  1160 						//but the server must be capable of handling this situation
       
  1161 						iChallenge = ETrue;
       
  1162 #endif
       
  1163 					}
       
  1164 					break;
       
  1165 				default:
       
  1166 				break;
       
  1167 				}//end switch
       
  1168 			}//end while		
       
  1169 
       
  1170 		if (challengeAbsent)
       
  1171 			{
       
  1172 			SET_LAST_ERROR(EChallengeAbsent);
       
  1173 			retValue = KErrGeneral;
       
  1174 			}
       
  1175 		}
       
  1176 	else
       
  1177 		{
       
  1178 		FLOG(_L("ParseConnectPacket Unknown Opcode Opcode\r\n"));
       
  1179 		SET_LAST_ERROR(EBadOpcodeInConnectPacket);
       
  1180 		retValue = KErrGeneral;
       
  1181 		}
       
  1182 
       
  1183 
       
  1184 	SetConnectState(nextState);
       
  1185 	return(retValue);
       
  1186 	}
       
  1187 
       
  1188 void CObexClient::OnError(TInt aError)
       
  1189 	{
       
  1190 	LOG1(_L8("CObexClient::OnError(%d)"), aError);
       
  1191 	CompleteRequest(aError);
       
  1192 
       
  1193 	// Don't reset the Obex link for a normal disconnection, as
       
  1194 	// technically there is no real error requiring such drastic
       
  1195 	// action.  In the case of USB, stalling the IN endpoint will
       
  1196 	// cause another round of alternate interface changes which
       
  1197 	// appears to confuse either Obex or the USB connector.
       
  1198 
       
  1199 	// In other words the error KErrDisconnected occurs as a
       
  1200 	// result of the transport coming down, so there's no need to
       
  1201 	// signal a transport error in this case.
       
  1202 
       
  1203 	// If this is called during construction, iTransportController could be NULL
       
  1204 	if(aError!=KErrDisconnected && iTransportController)
       
  1205 		{
       
  1206 		iTransportController->SignalTransportError();
       
  1207 		}
       
  1208 	}
       
  1209 
       
  1210 
       
  1211 
       
  1212 TInt CObexClient::PrepareConnectPacket(CObexPacket& aPacket)
       
  1213 	{
       
  1214 	TInt retValue = KErrNone;
       
  1215 	TConnectState nextState = EDropLink;
       
  1216 
       
  1217 	if (!iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags))
       
  1218 		{
       
  1219 		FLOG(_L("CObexClient::PrepareConnectPacket local data insertion FAILED\r\n"));
       
  1220 		SET_LAST_ERROR(ECannotInsertConnectInfo);
       
  1221 		return(KErrGeneral);
       
  1222 		}
       
  1223 	FLOG(_L("CObexClient::PrepareConnectPacket local data inserted Succesfully\r\n"));
       
  1224 
       
  1225 	//iCurrentObject could be NULL if Connect with no headers was requested
       
  1226 	if ( iCurrentObject )
       
  1227 		iCurrentObject->PrepareConnectionHeader(iTransportController->SendPacket());
       
  1228 
       
  1229 
       
  1230 	if (( iChallenge )&&(!retValue))	//if a challenge is to be sent
       
  1231 		{
       
  1232 		FLOG(_L("PrepareConnectPacket Generating challenge\r\n"));
       
  1233 
       
  1234 		retValue = GenerateChallenge(aPacket);
       
  1235 		if ( retValue == KErrNone) 
       
  1236 			{
       
  1237 			nextState = EChallConnRequested;
       
  1238 			}
       
  1239 		else
       
  1240 			{
       
  1241 			nextState = EDropLink;
       
  1242 			}
       
  1243 		}
       
  1244 	
       
  1245 	
       
  1246 	//check the state of the connect instruction
       
  1247 	if ( GetConnectState() == EConnTransport ) //first time round the loop
       
  1248 		{
       
  1249 		//it's going to be a simple challenge unless
       
  1250 		//it's already been decides it's a EChallConnRequested
       
  1251 		if ( nextState == EDropLink )
       
  1252 			nextState = ESimpleConnRequest; 
       
  1253 		}
       
  1254 	else if (GetConnectState() == EConnChallRxed)
       
  1255 		{							
       
  1256 		if (iCallBack )
       
  1257 			{
       
  1258 			FLOG(_L("PrepareConnectPacket requesting password from user\r\n"));
       
  1259 
       
  1260 			//ask the user for a password
       
  1261 			//the callback does happens in the method OnPacketReceive()
       
  1262 			nextState = EWaitForUserInput;
       
  1263 			retValue = KErrGeneral; //mustn't send yet wait for reply from user
       
  1264 			}
       
  1265 		else
       
  1266 			{
       
  1267 			FLOG(_L("PrepareConnectPacket chall rxed but can't ask for password dropping link\r\n"));
       
  1268 			SET_LAST_ERROR(EChallengeRejected);
       
  1269 			retValue = KErrIrObexConnectChallRejected;
       
  1270 			nextState = EDropLink;
       
  1271 			}
       
  1272 		}					//or drop the link
       
  1273 	else
       
  1274 		{
       
  1275 		FLOG(_L("PrepareConnectPacket unknown connect state\r\n"));
       
  1276 		SET_LAST_ERROR(EPrepareConnectPacketIncorrectState);
       
  1277 		retValue = KErrGeneral;
       
  1278 		nextState = EDropLink;
       
  1279 		}
       
  1280 	SetConnectState(nextState);
       
  1281 
       
  1282 	return(retValue);
       
  1283 	}
       
  1284 
       
  1285 void CObexClient::OnTransportUp()
       
  1286 	{
       
  1287 	FLOG(_L("CObexClient::OnTransportUp\r\n"));
       
  1288 	ResetConnectionID();
       
  1289 
       
  1290 	iTransportController->SendPacket().Init(EOpConnect); 
       
  1291 	if (PrepareConnectPacket(iTransportController->SendPacket()) == KErrNone)
       
  1292 		{
       
  1293 		FLOG(_L("OnTransportUp PrepareConnectPacket Succesfull\r\n"));
       
  1294 
       
  1295 		iTransportController->SendPacket().SetFinal();
       
  1296 		FTRACE(iTransportController->SendPacket().Dump());
       
  1297 		SendRequestPacket();
       
  1298 		}
       
  1299 	}
       
  1300 
       
  1301 void CObexClient::OnTransportDown()
       
  1302 	{
       
  1303 	LOG_LINE
       
  1304 	LOG_FUNC
       
  1305 	
       
  1306 	// Cancel the timer
       
  1307 	if (iPacketTimer->IsActive())
       
  1308 		{
       
  1309 		iPacketTimer->Cancel();
       
  1310 		}
       
  1311 	// If there's an outstanding request, an error has occured
       
  1312 	// But don't do anything if an error has already been set (due to e.g. packet timer timeout)
       
  1313 	if(iPendingRequest && !iIsLastErrorSet)
       
  1314 		{
       
  1315 		SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1316 		Error(KErrIrObexClientPutPeerAborted); //extended error for IrObex,("Other IR device aborted the transfer")
       
  1317 		}
       
  1318 	}
       
  1319 
       
  1320 /** Signals an event has ocurred.
       
  1321 
       
  1322 @released
       
  1323 @internalComponent
       
  1324 @param aEvent The event that has ocurred (TObexPacketProcessEvent)
       
  1325 */
       
  1326 void CObexClient::SignalPacketProcessEvent(TInt aEvent)
       
  1327 	{
       
  1328 	if(aEvent & KObexPacketSignallerInterestingClientEvents)
       
  1329 		{
       
  1330 		// Currently all notifications are related to writes, so only need to
       
  1331 		// clear events from the SendPacket.
       
  1332 		iTransportController->SendPacket().RemovePacketProcessEvents(aEvent);
       
  1333 
       
  1334 		iPacketProcessSignaller->Signal(static_cast<TObexPacketProcessEvent>(aEvent));
       
  1335 		}
       
  1336 	}
       
  1337 
       
  1338 void CObexClient::SetRequest(TRequestStatus& aStatus, TOperation aOperation)
       
  1339 	{
       
  1340 	aStatus = KRequestPending;
       
  1341 	iPendingRequest = &aStatus;
       
  1342 	iCurrentOperation = aOperation;
       
  1343 	}
       
  1344 
       
  1345 void CObexClient::CompleteRequest(const TInt aCompletion)
       
  1346 	{
       
  1347 	LOG_LINE
       
  1348 	LOG_FUNC
       
  1349 	
       
  1350 	if(iPendingRequest)
       
  1351 		{
       
  1352 		// Some errors, particularly IR, only come up through OnError().
       
  1353 		// Thus the setting of underlying error happens here.
       
  1354 		switch (aCompletion)
       
  1355 			{
       
  1356 			case KErrIrObexRespTimedOut:
       
  1357 				{
       
  1358 				SET_LAST_ERROR(EResponseTimeout);
       
  1359 				}
       
  1360 				break;
       
  1361 			case KErrDisconnected:
       
  1362 				{
       
  1363 				// There are at least two ways of getting here.
       
  1364 				// The first is disruption to the transport (e.g. IrDA beam blocked)
       
  1365 				// and the second is attempting an operation other than connect when
       
  1366 				// there is no connection (see CObexClient::ClientCommandL()).
       
  1367 				// We don't want to set the last error twice in the second case,
       
  1368 				// so check that the last error is not set before setting it here.
       
  1369 				if (!iIsLastErrorSet)
       
  1370 					{
       
  1371 					SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1372 					}
       
  1373 				}
       
  1374 				break;
       
  1375 			case KErrCompletion:
       
  1376 				{
       
  1377 				// This is an error from the destructor.
       
  1378 				// Operation is complete, successfully or otherwise.
       
  1379 				// Since the operation is still outstanding and the interruption
       
  1380 				// was initiated locally, the operation is effectively aborted.
       
  1381 				SET_LAST_ERROR(EAborted);
       
  1382 				}
       
  1383 				break;
       
  1384 			case KErrNotReady:
       
  1385 				{
       
  1386 				// This error occurs when the BT link times out.
       
  1387 				SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1388 				}
       
  1389 				break;
       
  1390 			case KErrCouldNotConnect:
       
  1391 				{
       
  1392 				// BT could not connect.
       
  1393 				SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1394 				}
       
  1395 				break;
       
  1396 			case KErrGeneral:
       
  1397 				{
       
  1398 				// Since Obex also uses this error elsewhere, only set a last error
       
  1399 				// if none has been set previously.
       
  1400 				if (!iIsLastErrorSet)
       
  1401 					{
       
  1402 					SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1403 					}
       
  1404 				}
       
  1405 				break;
       
  1406 			default:
       
  1407 				{
       
  1408 				// If an error has not yet been set, then set the last error as appropriate.
       
  1409 				if (!iIsLastErrorSet)
       
  1410 					{
       
  1411 					// For all other errors.
       
  1412 					SET_LAST_ERROR(EOpOutstandingOnTransportDown);
       
  1413 					}
       
  1414 				}
       
  1415 			}
       
  1416 		CHECK_LAST_ERROR_IS_SET;
       
  1417 		User::RequestComplete(iPendingRequest, aCompletion);// Sets iPendingRequest = NULL
       
  1418 		}
       
  1419 	iPendingRequest=NULL;
       
  1420 	iCurrentOperation = EOpIdle;
       
  1421 	
       
  1422 	if (iPacketTimer)
       
  1423 		{
       
  1424 		iPacketTimer->Cancel();
       
  1425 		}
       
  1426 	}
       
  1427 
       
  1428 void CObexClient::EmptyHeaderSet()
       
  1429 	{
       
  1430 	LOG_LINE
       
  1431 	LOG_FUNC
       
  1432 	
       
  1433 	iHeaderSet->First();
       
  1434 	while(iHeaderSet->This(iHeader) == KErrNone)
       
  1435 		{
       
  1436 		iHeaderSet->DeleteCurrentHeader();
       
  1437 		}
       
  1438 	}
       
  1439 	
       
  1440 void CObexClient::TimeOutCompletion()
       
  1441 	{
       
  1442 	LOG_LINE
       
  1443 	LOG_FUNC
       
  1444 	
       
  1445 	CompleteRequest(KErrIrObexRespTimedOut);
       
  1446 	// Disconnect transport to prevent the client entering an invalid state
       
  1447 	ForcedTransportDown();
       
  1448 	}
       
  1449 
       
  1450 void CObexClient::SendRequestPacket()
       
  1451 	{
       
  1452 	//Send the request.
       
  1453 	iTransportController->Send();
       
  1454 	
       
  1455 	//Set the Timer.
       
  1456 	iPacketTimer->SetTimer(iCmdTimeOutDuration);
       
  1457 	}
       
  1458 
       
  1459 void CObexClient::SendRequestPacket(TObexOpcode aObexOpcode)
       
  1460 	{
       
  1461 	//Send the request.
       
  1462 	iTransportController->Send(aObexOpcode);
       
  1463 	
       
  1464 	//Set the Timer.
       
  1465 	iPacketTimer->SetTimer(iCmdTimeOutDuration);
       
  1466 	}
       
  1467 
       
  1468 /**
       
  1469 Provides additional interfaces for CObexClient.
       
  1470 
       
  1471 @param aUid The UID of the interface that is required.
       
  1472 @return A pointer to an instance implementing the interface represented by aUid.
       
  1473 */
       
  1474 EXPORT_C TAny* CObexClient::ExtensionInterface(TUid aUid)
       
  1475 	{
       
  1476 	TAny* ret = NULL;
       
  1477 
       
  1478 	if (aUid == KObexClientErrorResolverInterface)
       
  1479 		{
       
  1480 		ret = static_cast<MObexClientErrorResolver*>(iErrorEngine);
       
  1481 		}
       
  1482 
       
  1483 	return ret;
       
  1484 	}
       
  1485 
       
  1486