messagingappbase/obexmtms/obexmtm/obexserver/source/obexSendOp_common.cpp
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 2001-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 //class include
       
    17 #include <obexsendop.h>
       
    18 
       
    19 //System includes
       
    20 #include <msvids.h>
       
    21 #include <msventry.h>	//CMsvServerEntry
       
    22 #include <btmsgtypeuid.h>	//KUidMsgTypeBt
       
    23 #include <irmsgtypeuid.h>	//KUidMsgTypeIr
       
    24 #include <obexheaderlist.h>
       
    25 
       
    26 #include <mmsvattachmentmanager.h>
       
    27 #include <cmsvattachment.h>
       
    28 #include <apparc.h>		// CApaApplication::GenerateFileName
       
    29 #include <apgcli.h>		// RApaLsSession   <-- data recognition.
       
    30 
       
    31 //user includes
       
    32 
       
    33 // Following are named KErrIrObexClientXXXXX because they are using the irobex.dll (which 
       
    34 // should really be called obex.dll now that it supports more than IR)
       
    35 const TInt KErrIrObexClientFirstPutFailed = -5510;
       
    36 const TInt KErrIrObexClientSubsequentPutFailed = -5511;
       
    37 const TInt KMaxBufSizeForRecognition = 1024;
       
    38 
       
    39 
       
    40 EXPORT_C CObexServerSendOperation::CObexServerSendOperation(TUid aMsgTypeUid, CMsvServerEntry& aSendObj, TInt aConnectTimeoutMicroSeconds, TInt aPutTimeoutMicroSeconds, TRequestStatus& aObserverRequestStatus)
       
    41 	:CActive(CActive::EPriorityHigh),
       
    42 		iAsyncInit(EFalse),
       
    43 		iObserverRequestStatus(aObserverRequestStatus),
       
    44 		iMsvSendParent(aSendObj), 
       
    45 		iConnectTimeout(aConnectTimeoutMicroSeconds),
       
    46 		iPutTimeout(aPutTimeoutMicroSeconds),
       
    47 		iCancelWithoutCompleting(EFalse),
       
    48 		iProgressPckg(TObexMtmProgress()),
       
    49 		iMtm(aMsgTypeUid)
       
    50 /**
       
    51  * Constructor.
       
    52  *
       
    53  *  @param aMsgTypeUid UID of message type
       
    54  *  @param aSendObj Reference to the object to send.
       
    55  *  @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
       
    56  *  @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
       
    57  *  @param aObserverRequestStatus TRequestStatus of owning active object.
       
    58  */
       
    59 	{
       
    60 	}
       
    61 
       
    62 EXPORT_C CObexServerSendOperation::CObexServerSendOperation
       
    63                                    (TUid aMsgTypeUid, CMsvServerEntry& aSendObj,TInt aConnectTimeoutMicroSeconds,
       
    64                                     TInt aPutTimeoutMicroSeconds, TRequestStatus& aObserverRequestStatus,
       
    65                                     TBool aLastSendAttempt)
       
    66 	:CActive(CActive::EPriorityHigh),
       
    67 		iAsyncInit(EFalse),
       
    68 		iLastSendAttempt(aLastSendAttempt),
       
    69 		iObserverRequestStatus(aObserverRequestStatus),
       
    70 		iMsvSendParent(aSendObj), 
       
    71 		iConnectTimeout(aConnectTimeoutMicroSeconds),
       
    72 		iPutTimeout(aPutTimeoutMicroSeconds),
       
    73 		iCancelWithoutCompleting(EFalse),
       
    74 		iProgressPckg(TObexMtmProgress()),
       
    75 		iMtm(aMsgTypeUid)
       
    76 		
       
    77 /**
       
    78  * Constructor.
       
    79  *
       
    80  *  @param aMsgTypeUid UID of message type
       
    81  *  @param aSendObj Reference to the object to send.
       
    82  *  @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
       
    83  *  @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
       
    84  *  @param aObserverRequestStatus TRequestStatus of owning active object.
       
    85  *  @param aLastSendAttempt TBool flag to check for second send attempt and also for sending headers.  EFalse sends full headers, ETrue only sends name and size
       
    86  */
       
    87 	{
       
    88 	}
       
    89 
       
    90 
       
    91 EXPORT_C void CObexServerSendOperation::ConstructL(const TDesC* aConnectPassword)
       
    92 /**
       
    93  * Second phase constructor. Sets up connection to the FileServer, initialises attachments or filename list then 
       
    94  * starts sending process by initialising.
       
    95  *
       
    96  * @param aConnectPassword Pointer to the password to be used for authentication.
       
    97  * @leave Leaves if insufficient memory.
       
    98  * @leave Leaves if cannot connect to FileServer.
       
    99  */
       
   100 	{
       
   101 	if (aConnectPassword->Length())
       
   102 		{
       
   103 		// take our own copy of the connection password
       
   104 		HBufC* password=aConnectPassword->AllocL();
       
   105 		iConnectPassword=password;
       
   106 		}
       
   107 
       
   108 	BuildSpecificConstructL();
       
   109 
       
   110 	
       
   111 
       
   112 	TRequestStatus* observerStatus = &iObserverRequestStatus;
       
   113 	*observerStatus = KRequestPending;
       
   114 	
       
   115 
       
   116 
       
   117 	// If no attachments have been found, try using the Attachment API
       
   118 		// Try Attachment API...
       
   119 		CMsvStore* store = iMsvSendParent.ReadStoreL();
       
   120 		CleanupStack::PushL(store);
       
   121 		MMsvAttachmentManager& manager = store->AttachmentManagerL();
       
   122 		iAttachmentEntryCount = manager.AttachmentCount();
       
   123 		iNextAttachment = iAttachmentEntryCount-1;
       
   124 		CleanupStack::PopAndDestroy(store);
       
   125 
       
   126 
       
   127 	iTimeoutTimer = CObexSendOpTimeout::NewL(this);
       
   128 
       
   129 	CActiveScheduler::Add(this);
       
   130 	iStatus = KRequestPending;
       
   131 	SetActive();
       
   132 
       
   133 	if ( iAttachmentEntryCount > 0 )
       
   134 		{
       
   135 		// START SENDING
       
   136 		iSendState = TObexMtmProgress::EInitialise;
       
   137 		CompleteSelf(KErrNone);
       
   138 		}
       
   139 	else
       
   140 		{
       
   141 		//Nothing to send
       
   142 		iSendState = TObexMtmProgress::ESendError;
       
   143 		CompleteSelf(KErrNone);
       
   144 		}
       
   145 	}
       
   146 
       
   147 EXPORT_C CObexServerSendOperation::~CObexServerSendOperation()
       
   148 /**
       
   149  * Destructor. Cancel()s, deletes owned objects and Close()s the connection to the FileServer.
       
   150  */
       
   151 	{
       
   152 	Cancel();
       
   153 	delete iObexClient;
       
   154 	delete iObexObject;
       
   155 	delete iTimeoutTimer;
       
   156 	delete iConnectPassword;
       
   157 	delete iMoveOperation;
       
   158 	delete iMoveEntrySelection;
       
   159 
       
   160 
       
   161 	BuildSpecificDestructor();
       
   162 	}
       
   163 
       
   164 void CObexServerSendOperation::TimeOut()
       
   165 /**
       
   166  * Called when the current operation times out. Causes the current operation to be cancelled, then reactivates with
       
   167  * the appropriate error code (KErrIrObexClientNoDevicesFound or KErrIrObexClientPutPeerAborted).
       
   168  */
       
   169 	{
       
   170 	switch (iSendState)
       
   171 		{
       
   172 	case TObexMtmProgress::EInitialise:
       
   173 	case TObexMtmProgress::EConnect:
       
   174 	case TObexMtmProgress::EConnectAttemptComplete:
       
   175 		ActivateRunLWithError(KErrIrObexClientNoDevicesFound);
       
   176 		break;
       
   177 	case TObexMtmProgress::ESendObject:		// Next RunL: start first send (not started sending yet)
       
   178 	case TObexMtmProgress::ESendNextObject:	// Next RunL: start next send (still sending current object)
       
   179 	case TObexMtmProgress::ESendComplete:		// Next RunL: nothing left to send (still sending current object)
       
   180 	case TObexMtmProgress::EDisconnected:		// Trying to disconnect
       
   181 		ActivateRunLWithError(KErrIrObexClientPutPeerAborted);
       
   182 		break;
       
   183 	default:
       
   184 		Panic(EObexSendOperationUnexpectedTimeout);
       
   185 		}
       
   186 	}
       
   187 
       
   188 void CObexServerSendOperation::ActivateRunLWithError(TInt aError)
       
   189 /**
       
   190  * Cancels the current operation, then reactivates with the given error code.
       
   191  *
       
   192  * @param aError Error code to be passed to CompleteSelf.
       
   193  */
       
   194 {
       
   195 	ExplicitCancel();
       
   196 	
       
   197 	// Ensure RunL() is called to handle the error
       
   198 	iSendState=TObexMtmProgress::ESendError;
       
   199 	SetActive(); // Schedule so can CompleteObserverL() using given error code when RunL() is called again
       
   200 	CompleteSelf(aError);
       
   201 }
       
   202 
       
   203 void CObexServerSendOperation::ExplicitCancel()
       
   204 /**
       
   205  * Cancel any pending obex operation without completing the observer. 
       
   206  */
       
   207 	{
       
   208 	// Cancel any pending obex operation without completing the observer (the observer
       
   209 	// owns this messaging operation, it's request status is iObserverRequestStatus)
       
   210 	iCancelWithoutCompleting = ETrue; //this prevents the observer from completing when DoCancel() is called by the active object framework
       
   211 	Cancel();
       
   212 	iCancelWithoutCompleting = EFalse;
       
   213 	}
       
   214 
       
   215 EXPORT_C void CObexServerSendOperation::DoCancel()
       
   216 /**
       
   217  * Cancels the current operation, deletes the client and Cancel()s the timeout timer. Only completes the observer
       
   218  * (by a call to CompleteObserverL) if an external entity (i.e. the owner) has called Cancel().
       
   219  * Otherwise the observer is not completed.
       
   220  */
       
   221 	{
       
   222 	// Have to delete the Obex client here or it mucks up the active scheduler. 
       
   223 	// Abort doesn't cut the mustard.
       
   224 	delete iObexClient;
       
   225 	iObexClient=NULL;
       
   226 
       
   227 	// Delete the Obex object as we may try to delete the message store entry
       
   228 	// when we complete the observer and this will fail as the iObexObject has the
       
   229 	// associated attachment file open.
       
   230 	delete iObexObject;
       
   231 	iObexObject = NULL;
       
   232 
       
   233 	iTimeoutTimer->Cancel();
       
   234 
       
   235 	if(!iCancelWithoutCompleting)
       
   236 		{
       
   237 		// We will only get here if an external entity has called Cancel() on us, only
       
   238 		// the user (owner) of this active object will do this. In most cases this
       
   239 		// will be the direct result of a user action, e.g. cancelling a dialog
       
   240 		iSendState = TObexMtmProgress::EUserCancelled;
       
   241 		CompleteObserverL(); // complete the observer which owns this messaging op
       
   242 		}
       
   243 	}
       
   244 
       
   245 EXPORT_C TBool CObexServerSendOperation::CompletingObserver(TInt aErrorCode)
       
   246 /**
       
   247 * This is the default implementation that allows the server mtm to continue normally.
       
   248 * Tells the derived class that the base class is about to complete the observer.
       
   249 * This is the first thing called when CompleteObserverL is called.
       
   250 * Since the behaviour of CompleteObserverL is to clean up the message that it was trying to send,
       
   251 * this calls gives the derived class an opportunity to either stop this deletion or recover any information
       
   252 * synchronously from the message.
       
   253 * If the derived class has no need to use this functionality, the default implementation allows deletion.
       
   254 * @param aErrorCode The last error code encountered during operation
       
   255 * @return TBool True delete the message
       
   256 * @return TBool False DO NOT delete the message
       
   257 */
       
   258 	{
       
   259 	(void)aErrorCode;
       
   260 
       
   261 	return ETrue;
       
   262 	}
       
   263 
       
   264 void CObexServerSendOperation::CompleteObserverL() //CMsvOperation completed.
       
   265 /**
       
   266  * Complete the observer, reporting any error via the progress. THIS METHOD MUST BE CALLED ONCE ONLY.
       
   267  *
       
   268  */
       
   269 	{
       
   270 	ProgressL();
       
   271 	TObexMtmProgress& progress = iProgressPckg();
       
   272 
       
   273 	// If the message should be deleted then do it here.
       
   274 #ifndef MOVE_MESSAGE_TO_SENT
       
   275 
       
   276 	// this call gives the derived class an opportunity to control this behaviour.
       
   277 	
       
   278 	// note that the error passed into this is the final one which the server mtm wants to
       
   279 	// report to the UI - occasionally, this will be KErrNone when in fact an Obex error
       
   280 	// did occur.  To make sure that we tell the derived class exactly what happened, we
       
   281 	// pass the current state of the progress indicator out to it.
       
   282 
       
   283 	if(CompletingObserver(progress.iError))
       
   284 		SynchronousEntryDelete();
       
   285 #endif
       
   286 
       
   287 	TRequestStatus* status = &iObserverRequestStatus;
       
   288 	User::RequestComplete(status, KErrNone);
       
   289 	}
       
   290 
       
   291 void CObexServerSendOperation::CompleteSelf(TInt aError)
       
   292 /**
       
   293  * This causes this active object's request to complete which means
       
   294  * RunL() will be called again if we are active (immediately if there 
       
   295  * are no higher priority active objects in the active scheduler).
       
   296  *
       
   297  * @param aError Error to be passed forward to the next step of the state machine
       
   298  */
       
   299 	{
       
   300 	// This causes this active objects request to complete which means
       
   301 	// RunL() will be called again if we are active (immediately if there 
       
   302 	// are no higher priority active objects in the active scheduler).
       
   303 	TRequestStatus* status = &iStatus;
       
   304 	User::RequestComplete(status, aError);
       
   305 	}
       
   306 
       
   307 EXPORT_C void CObexServerSendOperation::RunL()
       
   308 /**
       
   309  * Calls RealRunL(), and traps errors
       
   310  *
       
   311  * @leave Leaves with errors from RealRunL()
       
   312  */
       
   313 	{
       
   314 	TRAPD(err, RealRunL());
       
   315 
       
   316 	if(err)
       
   317 		{
       
   318 		ExplicitCancel(); //don't complete the observer, just cancel sending activity
       
   319 
       
   320 		// if RealRunL left in ESendError, sending it back would cause an endless loop!
       
   321 		if (iSendState == TObexMtmProgress::ESendError)
       
   322 			{
       
   323 			iStatus = err;
       
   324 			CompleteObserverL();
       
   325 
       
   326 			// update iStatus "manually" so that it shows the REAL error (the error that 
       
   327 			// made RealRunL leave, not the previous error that made it go to ESendError)
       
   328 			// NOTE: if we left iStatus unchanged here, the observer would get the error
       
   329 			// that caused the send operation to fail. If for any reason this were thought to be
       
   330 			// better, just removing the following line would do.
       
   331 			}
       
   332 		else
       
   333 			{
       
   334 			iSendState = TObexMtmProgress::ESendError;
       
   335 
       
   336 			// this is so that RunL-RealRunL are called immediately to handle the error
       
   337 			// (the observer will be completed in RealRunL)
       
   338 
       
   339 			SetActive();
       
   340 			CompleteSelf(err);
       
   341 			}
       
   342 
       
   343 		User::Leave(err); // Allow system to display an error.
       
   344 		}
       
   345 	}
       
   346 
       
   347 /**
       
   348  * This is not required to do anything in the base implementation.
       
   349  */
       
   350 
       
   351 EXPORT_C void CObexServerSendOperation::SecondPhaseObexClientInitL()
       
   352 	{
       
   353 	}
       
   354 
       
   355 EXPORT_C void CObexServerSendOperation::PreConnectOperations()
       
   356 	{
       
   357 	}
       
   358 
       
   359 EXPORT_C void CObexServerSendOperation::PostConnectOperations()
       
   360 	{
       
   361 	}
       
   362 
       
   363 EXPORT_C void CObexServerSendOperation::PreSendOperations()
       
   364 	{
       
   365 	}
       
   366 
       
   367 EXPORT_C void CObexServerSendOperation::PostSendOperations()
       
   368 	{
       
   369 	}
       
   370 
       
   371 TInt CObexServerSendOperation::SynchronousEntryDelete()
       
   372 /**
       
   373  * Delete the outbox entry as operation has 'completed'.
       
   374  * Will be invisible&InPreparation anyway (MS delete will delete it the next 
       
   375  * time it starts).
       
   376  */
       
   377 	{
       
   378 	// Delete the outbox entry as operation has 'completed'.
       
   379 	// Will be invisible&InPreparation anyway (MS delete will delete it the next 
       
   380 	// time it starts).
       
   381 	TInt err;
       
   382 	const TMsvEntry& tMsvSentEntry = iMsvSendParent.Entry();
       
   383 	TInt messageId = tMsvSentEntry.Id();
       
   384 	err = iMsvSendParent.SetEntry(tMsvSentEntry.Parent());
       
   385 	if (err == KErrNone)
       
   386 		{
       
   387 		err = iMsvSendParent.DeleteEntry(messageId);
       
   388 		}
       
   389 	return err;
       
   390  	}
       
   391 	
       
   392 void CObexServerSendOperation::InitialiseAttachmentL(CMsvServerEntry& aParent, TInt aWhichAttachment)
       
   393 /**
       
   394  * Load an attachment into the obex sending buffer, and create a new Obex object of name TMsvEntry::iDetails.
       
   395  *
       
   396  * @param aParent Reference to CMsvServerEntry to be sent.
       
   397  * @param aWhichAttachment Zero-based index of attachment to send.
       
   398  * @leave KErrXXX system wide error codes
       
   399  */
       
   400 	{
       
   401 	// Load an attachment into the obex sending buffer
       
   402 
       
   403 		// use the Attachment API to load the attachment files
       
   404 		CMsvStore* store = aParent.ReadStoreL();
       
   405 		CleanupStack::PushL(store);
       
   406 		CMsvAttachment* attachment = store->AttachmentManagerL().GetAttachmentInfoL(aWhichAttachment);
       
   407 		CleanupStack::PushL(attachment);
       
   408 		LoadFileIntoObjectL(attachment->FilePath(), attachment->AttachmentName(), attachment->MimeType());
       
   409 		
       
   410 		// if any additional obex headers have been provided, set them
       
   411 		// in the obex object
       
   412 		TPtrC8 headerData;
       
   413 		if( attachment->GetDesC8Attribute(KUidObexHeaders, headerData) == KErrNone )
       
   414 			{
       
   415 			// header data exists, try to build an obex header list
       
   416 			CObexHeaderList* headerList = CObexHeaderList::NewLC();
       
   417 			headerList->ImportFromAttachmentL(*attachment);
       
   418 			headerList->AddHeadersToBaseObjectL(*iObexObject);
       
   419 			CleanupStack::PopAndDestroy(headerList);
       
   420 			}
       
   421 			
       
   422 		CleanupStack::PopAndDestroy(2, store); // attachment, store
       
   423 	}
       
   424 
       
   425 void CObexServerSendOperation::LoadFileIntoObjectL(const TDesC& aFileName, const TDesC& aObexName, const TDesC8& aMimeType)
       
   426 	{
       
   427 	// Load the file into our send data buffer.
       
   428 	// Create a new Obex object from the file.
       
   429 
       
   430 	// Check we actually have a file
       
   431 	TEntry fileEntry;
       
   432 	User::LeaveIfError( FileSession().Entry(aFileName, fileEntry) );
       
   433 	if(fileEntry.IsDir())
       
   434 		User::Leave(KErrNotSupported); //Can't send a directory.
       
   435 
       
   436 	//Store the filename associated with the obex object
       
   437 	iSendFile = aFileName;
       
   438 	
       
   439 	// Get the file length
       
   440 	RFile file;
       
   441 	User::LeaveIfError( file.Open(FileSession(), aFileName, EFileRead  | EFileShareReadersOnly) );
       
   442 	CleanupClose<RFile>::PushL(file);
       
   443 	TInt fileLength;
       
   444 	User::LeaveIfError( file.Size(fileLength) );
       
   445 
       
   446 	// To allow file type recognition, read the file into sendBody
       
   447 	// only need the first KMaxBufSizeForRecognition bytes
       
   448 	HBufC8* sendBody = HBufC8::NewLC(fileLength < KMaxBufSizeForRecognition ? fileLength : KMaxBufSizeForRecognition);
       
   449 	TPtr8 sendBodyPtr = sendBody->Des();
       
   450 	User::LeaveIfError( file.Read(sendBodyPtr) );
       
   451 	CleanupStack::Pop(); //sendBodyPtr;
       
   452 	CleanupStack::PopAndDestroy(); //file.Close();
       
   453 	CleanupStack::PushL(sendBody);	//Must be a better way to do this!
       
   454 
       
   455 	// Create an Obex object from the file.
       
   456 	delete iObexObject;
       
   457 	iObexObject=NULL;
       
   458 	iObexObject = CObexFileObject::NewL(iSendFile);
       
   459 
       
   460 	// Set the obex object name field 
       
   461 	if(aObexName.Length()!=0)
       
   462 		{
       
   463 		iObexObject->SetNameL(aObexName); // Only *set* a header field if have some data, otherwise Obex will assert.
       
   464 		}
       
   465 	
       
   466 	if( aMimeType.Length() > 0 )
       
   467 		{
       
   468 		iObexObject->SetTypeL(aMimeType);
       
   469 		}
       
   470 	else
       
   471 		{
       
   472 		// Attempt to recognise the datatype (MIME type) of the data in the send buffer
       
   473 		// but only set obex object type field if we are pretty confident of the 
       
   474 		// Recogniser's result
       
   475 		RApaLsSession lsSess;
       
   476 		if( lsSess.Connect() == KErrNone)
       
   477 			{
       
   478 			CleanupClosePushL(lsSess);
       
   479 
       
   480 			TDataRecognitionResult result;
       
   481 			User::LeaveIfError( lsSess.RecognizeData(aObexName, sendBodyPtr, result) );
       
   482 			if (result.iConfidence>=CApaDataRecognizerType::EProbable)
       
   483 				{
       
   484 				iObexObject->SetTypeL(result.iDataType.Des8());	//only set a header field if have some data, otherwise Obex will assert.
       
   485 				}
       
   486 			CleanupStack::PopAndDestroy();	// lsSess;
       
   487 			}
       
   488 		}
       
   489 
       
   490 	// Set obex object length field for benefit of remote device's UI
       
   491 	iObexObject->SetLengthL(fileLength);
       
   492 
       
   493 	// Set obex object time field
       
   494 	TTime modifiedTime;
       
   495 	FileSession().Modified(aFileName, modifiedTime);
       
   496 	iObexObject->SetTimeL(modifiedTime);
       
   497 
       
   498 	//Cleanup
       
   499 	CleanupStack::PopAndDestroy();	//sendBody
       
   500 	}
       
   501 
       
   502 
       
   503 EXPORT_C void CObexServerSendOperation::GetUserPasswordL(const TDesC& /*aRelm*/)
       
   504 /**
       
   505  * Called by the Obex Client when authentication is requested to pass the password back. If the password is invalid, this
       
   506  * call should succeed but the send operation as a whole will inevitably fail.
       
   507  *
       
   508  * @param aRelm ignored, but could be used to indicate which password to use.
       
   509  * @leave KErrXXX system wide error codes. Shouldn't leave just because the password is invalid.
       
   510  * @leave KErrIrObexConnectChallRejected, if password is found empty.
       
   511  */
       
   512 	{
       
   513 	//A "pusher" may not know in advance that the remote will issue an OBEX authentication challenge when connecting an OBEX session.  
       
   514 	// As such if a password is not provided the MTM will return, KErrIrObexConnectChallRejected
       
   515 	if(!iConnectPassword)
       
   516 		{
       
   517 		User::Leave(KErrIrObexConnectChallRejected);		
       
   518 		}
       
   519 	
       
   520 	//Simply pass back the default user password
       
   521 	iObexClient->UserPasswordL(*iConnectPassword);
       
   522 	}
       
   523 
       
   524 
       
   525 TBool CObexServerSendOperation::CheckStatusOfLastObject(TInt aStatus, TObexMtmProgress::TSendState aSendState)
       
   526 /**
       
   527  * Checks the last object was sent correctly, and tries to action appropriate error feedback if not. Only to be called
       
   528  * from ESendObject/ESendNextObject or ESendComplete states. 
       
   529  *
       
   530  * @param aStatus Status of last object
       
   531  * @return ETrue if message was OK--EFalse if message failed and this function has taken the necessary action
       
   532  */
       
   533 	{
       
   534 	if(aStatus != KErrNone)
       
   535 		{ 
       
   536 		if ((aStatus==KErrInUse) || (aStatus==KErrArgument))
       
   537 			{
       
   538 			//May indicate a problem with sending the previous object, or an error with a previous connection still
       
   539 			//being active--try and decide which
       
   540 			if (aSendState == TObexMtmProgress::ESendNextObject)
       
   541 				{
       
   542 				// Have managed to send at least one object - receiver might not be 
       
   543 				// able to accept multiple objects.
       
   544 				CompleteSelf(KErrIrObexClientSubsequentPutFailed); //would be useful if this err was handled with a "Try sending one at a time" message to the user
       
   545 				}
       
   546 			else
       
   547 				{
       
   548 				// Have connected OK but couldn't send, so receiver might be dealing with
       
   549 				// a previous connection
       
   550 				CompleteSelf(KErrIrObexClientFirstPutFailed); //different to EMultiObjectSendError
       
   551 				}
       
   552 			}
       
   553 		else
       
   554 			{
       
   555 			// May indicate an error with the first or subsequent object
       
   556 			// Pass error code onto the owner of this messaging operation
       
   557 			CompleteSelf(aStatus); // General error.
       
   558 			}
       
   559 
       
   560 		iSendState=TObexMtmProgress::ESendError;
       
   561 		SetActive();
       
   562 		return EFalse;
       
   563 		}
       
   564 	else
       
   565 		{
       
   566 		return ETrue;
       
   567 		}
       
   568 	}
       
   569 
       
   570 TInt CObexServerSendOperation::PrepareCurrentObjectAndSetStateL()
       
   571 /**
       
   572  * Loads the next object to be sent, whether an attachment or a file in the file list.
       
   573  *
       
   574  * @return KErrXXX standard error code
       
   575  * @return KErrNotFound if there were neither attachments nor files in the file list
       
   576  * @leave KErrXXX system wide error codes
       
   577  */
       
   578 	{
       
   579 		// Have attachment(s) to be sent.
       
   580 		InitialiseAttachmentL(iMsvSendParent, iNextAttachment); //Load data into send buffer.
       
   581 		--iNextAttachment;
       
   582 		if(iNextAttachment<0) //iNextAttachment is 0 for a 1 attachment entry.
       
   583 			{
       
   584 			// Send will be complete after the current object has been sent so
       
   585 			// go to next state after the send operation completes
       
   586 			iSendState=TObexMtmProgress::ESendComplete;
       
   587 			}
       
   588 		else
       
   589 			{
       
   590 			// Still have another object to send after current object has been
       
   591 			// sent so return to this state after the send operation completes
       
   592 			iSendState=TObexMtmProgress::ESendNextObject;
       
   593 			}
       
   594 
       
   595 		//Successfully sent an attachment specified object
       
   596 		return KErrNone;
       
   597 	}
       
   598 
       
   599 void CObexServerSendOperation::MoveToSentAndSetActiveL()
       
   600 /**
       
   601  * Moves the newly sent message to the global sent items folder, and sets active ready for its completion.
       
   602  *
       
   603  * @leave KErrXXX system wide error codes
       
   604  */
       
   605 	{
       
   606 	iMoveEntrySelection = new (ELeave) CMsvEntrySelection;
       
   607 	iMoveEntrySelection->AppendL(iMsvSendParent.Entry().Id());		//i.e. just the sent message
       
   608 	iMsvSendParent.SetEntry(iMsvSendParent.Entry().Parent());		//Move to the parent
       
   609 	iMsvSendParent.MoveEntriesL(*iMoveEntrySelection, KMsvSentEntryId, iStatus);
       
   610 	iSendState = TObexMtmProgress::EMovedToSent;
       
   611 	SetActive();
       
   612 	}
       
   613 
       
   614 void CObexServerSendOperation::CleanupAfterMovedToSent()
       
   615 /**
       
   616  * Restores after the message has been moved to the inbox, and marks the message as visible.
       
   617  */
       
   618 	{
       
   619 	iMsvSendParent.SetEntry(iMoveEntrySelection->At(0));	//Switch back to actual message
       
   620 	TMsvEntry entry = iMsvSendParent.Entry();
       
   621 	entry.SetVisible(ETrue);			// Moved OK. Make the entry visible and flag it as complete.
       
   622 	entry.SetInPreparation(EFalse);
       
   623 	iMsvSendParent.ChangeEntry(entry);		//Commit changes
       
   624 	iMsvSendParent.SetEntry(KMsvNullIndexEntryId);	//Unlock the entry
       
   625 	}
       
   626 
       
   627 
       
   628 RFs& CObexServerSendOperation::FileSession()
       
   629 /**
       
   630  * Returns a reference to the file session (RFs) of the message
       
   631  *
       
   632  * @return A reference to the file session of the the message 
       
   633  */
       
   634 	{
       
   635 	return iMsvSendParent.FileSession();
       
   636 	}
       
   637 
       
   638 
       
   639 //
       
   640 //
       
   641 // CObexSendOpTimeout 
       
   642 //
       
   643 //
       
   644 
       
   645 CObexSendOpTimeout* CObexSendOpTimeout::NewL(CObexServerSendOperation* aSendOperation)
       
   646 /**
       
   647  *Canonical NewL function, which also sets the owner operation.
       
   648  *
       
   649  *@param aSendOperation Obex send operation which will be "timed out" when the timer expires
       
   650  */
       
   651 	{
       
   652 	CObexSendOpTimeout* self=new (ELeave) CObexSendOpTimeout;
       
   653 	CleanupStack::PushL(self);
       
   654 	self->ConstructL();
       
   655 	self->iSendOperation = aSendOperation;
       
   656 	CleanupStack::Pop();
       
   657 	return self;
       
   658 	}
       
   659 
       
   660 CObexSendOpTimeout::CObexSendOpTimeout()
       
   661 	: CTimer(CActive::EPriorityStandard)
       
   662 	  // Construct  zero-priority active object
       
   663 /**
       
   664  * Constructor. Calls CTimer's constructor with priority EPriorityStandard
       
   665  */
       
   666 	{};
       
   667 
       
   668 void CObexSendOpTimeout::ConstructL()
       
   669 /**
       
   670  * Second phase constructor. Calls CTimer::ConstructL(), and adds itself to the active scheduler
       
   671  *
       
   672  * @leave KErrXXX system wide error codes
       
   673  */
       
   674 	{
       
   675 	CTimer::ConstructL();
       
   676 	CActiveScheduler::Add(this); 
       
   677 	}
       
   678 
       
   679 void CObexSendOpTimeout::RunL()
       
   680 /**
       
   681  * Calls the TimeOut method of the associated CObexServerSendOperation when the timer expires
       
   682  *
       
   683  * @leave KErrXXX system wide error codes
       
   684  */
       
   685 	{
       
   686 	iSendOperation->TimeOut();
       
   687 	}
       
   688 
       
   689 
       
   690 
       
   691 
       
   692 //
       
   693 //
       
   694 // Panic
       
   695 //
       
   696 //
       
   697 
       
   698 GLDEF_C void Panic(TObexSendOperationPanic aPanic)
       
   699 	{
       
   700 	_LIT(KObexSendOperationPanic,"ObexSendOp");
       
   701 	User::Panic(KObexSendOperationPanic,aPanic);
       
   702 	}
       
   703