--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/obexmtms/obexmtm/obexserver/source/obexSendOp_common.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,703 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+//class include
+#include <obexsendop.h>
+
+//System includes
+#include <msvids.h>
+#include <msventry.h> //CMsvServerEntry
+#include <btmsgtypeuid.h> //KUidMsgTypeBt
+#include <irmsgtypeuid.h> //KUidMsgTypeIr
+#include <obexheaderlist.h>
+
+#include <mmsvattachmentmanager.h>
+#include <cmsvattachment.h>
+#include <apparc.h> // CApaApplication::GenerateFileName
+#include <apgcli.h> // RApaLsSession <-- data recognition.
+
+//user includes
+
+// Following are named KErrIrObexClientXXXXX because they are using the irobex.dll (which
+// should really be called obex.dll now that it supports more than IR)
+const TInt KErrIrObexClientFirstPutFailed = -5510;
+const TInt KErrIrObexClientSubsequentPutFailed = -5511;
+const TInt KMaxBufSizeForRecognition = 1024;
+
+
+EXPORT_C CObexServerSendOperation::CObexServerSendOperation(TUid aMsgTypeUid, CMsvServerEntry& aSendObj, TInt aConnectTimeoutMicroSeconds, TInt aPutTimeoutMicroSeconds, TRequestStatus& aObserverRequestStatus)
+ :CActive(CActive::EPriorityHigh),
+ iAsyncInit(EFalse),
+ iObserverRequestStatus(aObserverRequestStatus),
+ iMsvSendParent(aSendObj),
+ iConnectTimeout(aConnectTimeoutMicroSeconds),
+ iPutTimeout(aPutTimeoutMicroSeconds),
+ iCancelWithoutCompleting(EFalse),
+ iProgressPckg(TObexMtmProgress()),
+ iMtm(aMsgTypeUid)
+/**
+ * Constructor.
+ *
+ * @param aMsgTypeUid UID of message type
+ * @param aSendObj Reference to the object to send.
+ * @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
+ * @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
+ * @param aObserverRequestStatus TRequestStatus of owning active object.
+ */
+ {
+ }
+
+EXPORT_C CObexServerSendOperation::CObexServerSendOperation
+ (TUid aMsgTypeUid, CMsvServerEntry& aSendObj,TInt aConnectTimeoutMicroSeconds,
+ TInt aPutTimeoutMicroSeconds, TRequestStatus& aObserverRequestStatus,
+ TBool aLastSendAttempt)
+ :CActive(CActive::EPriorityHigh),
+ iAsyncInit(EFalse),
+ iLastSendAttempt(aLastSendAttempt),
+ iObserverRequestStatus(aObserverRequestStatus),
+ iMsvSendParent(aSendObj),
+ iConnectTimeout(aConnectTimeoutMicroSeconds),
+ iPutTimeout(aPutTimeoutMicroSeconds),
+ iCancelWithoutCompleting(EFalse),
+ iProgressPckg(TObexMtmProgress()),
+ iMtm(aMsgTypeUid)
+
+/**
+ * Constructor.
+ *
+ * @param aMsgTypeUid UID of message type
+ * @param aSendObj Reference to the object to send.
+ * @param aConnectTimeoutMicroSeconds Timeout period for Connect operation in microseconds.
+ * @param aPutTimeoutMicroseconds Timeout period for Put operation in microseconds.
+ * @param aObserverRequestStatus TRequestStatus of owning active object.
+ * @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
+ */
+ {
+ }
+
+
+EXPORT_C void CObexServerSendOperation::ConstructL(const TDesC* aConnectPassword)
+/**
+ * Second phase constructor. Sets up connection to the FileServer, initialises attachments or filename list then
+ * starts sending process by initialising.
+ *
+ * @param aConnectPassword Pointer to the password to be used for authentication.
+ * @leave Leaves if insufficient memory.
+ * @leave Leaves if cannot connect to FileServer.
+ */
+ {
+ if (aConnectPassword->Length())
+ {
+ // take our own copy of the connection password
+ HBufC* password=aConnectPassword->AllocL();
+ iConnectPassword=password;
+ }
+
+ BuildSpecificConstructL();
+
+
+
+ TRequestStatus* observerStatus = &iObserverRequestStatus;
+ *observerStatus = KRequestPending;
+
+
+
+ // If no attachments have been found, try using the Attachment API
+ // Try Attachment API...
+ CMsvStore* store = iMsvSendParent.ReadStoreL();
+ CleanupStack::PushL(store);
+ MMsvAttachmentManager& manager = store->AttachmentManagerL();
+ iAttachmentEntryCount = manager.AttachmentCount();
+ iNextAttachment = iAttachmentEntryCount-1;
+ CleanupStack::PopAndDestroy(store);
+
+
+ iTimeoutTimer = CObexSendOpTimeout::NewL(this);
+
+ CActiveScheduler::Add(this);
+ iStatus = KRequestPending;
+ SetActive();
+
+ if ( iAttachmentEntryCount > 0 )
+ {
+ // START SENDING
+ iSendState = TObexMtmProgress::EInitialise;
+ CompleteSelf(KErrNone);
+ }
+ else
+ {
+ //Nothing to send
+ iSendState = TObexMtmProgress::ESendError;
+ CompleteSelf(KErrNone);
+ }
+ }
+
+EXPORT_C CObexServerSendOperation::~CObexServerSendOperation()
+/**
+ * Destructor. Cancel()s, deletes owned objects and Close()s the connection to the FileServer.
+ */
+ {
+ Cancel();
+ delete iObexClient;
+ delete iObexObject;
+ delete iTimeoutTimer;
+ delete iConnectPassword;
+ delete iMoveOperation;
+ delete iMoveEntrySelection;
+
+
+ BuildSpecificDestructor();
+ }
+
+void CObexServerSendOperation::TimeOut()
+/**
+ * Called when the current operation times out. Causes the current operation to be cancelled, then reactivates with
+ * the appropriate error code (KErrIrObexClientNoDevicesFound or KErrIrObexClientPutPeerAborted).
+ */
+ {
+ switch (iSendState)
+ {
+ case TObexMtmProgress::EInitialise:
+ case TObexMtmProgress::EConnect:
+ case TObexMtmProgress::EConnectAttemptComplete:
+ ActivateRunLWithError(KErrIrObexClientNoDevicesFound);
+ break;
+ case TObexMtmProgress::ESendObject: // Next RunL: start first send (not started sending yet)
+ case TObexMtmProgress::ESendNextObject: // Next RunL: start next send (still sending current object)
+ case TObexMtmProgress::ESendComplete: // Next RunL: nothing left to send (still sending current object)
+ case TObexMtmProgress::EDisconnected: // Trying to disconnect
+ ActivateRunLWithError(KErrIrObexClientPutPeerAborted);
+ break;
+ default:
+ Panic(EObexSendOperationUnexpectedTimeout);
+ }
+ }
+
+void CObexServerSendOperation::ActivateRunLWithError(TInt aError)
+/**
+ * Cancels the current operation, then reactivates with the given error code.
+ *
+ * @param aError Error code to be passed to CompleteSelf.
+ */
+{
+ ExplicitCancel();
+
+ // Ensure RunL() is called to handle the error
+ iSendState=TObexMtmProgress::ESendError;
+ SetActive(); // Schedule so can CompleteObserverL() using given error code when RunL() is called again
+ CompleteSelf(aError);
+}
+
+void CObexServerSendOperation::ExplicitCancel()
+/**
+ * Cancel any pending obex operation without completing the observer.
+ */
+ {
+ // Cancel any pending obex operation without completing the observer (the observer
+ // owns this messaging operation, it's request status is iObserverRequestStatus)
+ iCancelWithoutCompleting = ETrue; //this prevents the observer from completing when DoCancel() is called by the active object framework
+ Cancel();
+ iCancelWithoutCompleting = EFalse;
+ }
+
+EXPORT_C void CObexServerSendOperation::DoCancel()
+/**
+ * Cancels the current operation, deletes the client and Cancel()s the timeout timer. Only completes the observer
+ * (by a call to CompleteObserverL) if an external entity (i.e. the owner) has called Cancel().
+ * Otherwise the observer is not completed.
+ */
+ {
+ // Have to delete the Obex client here or it mucks up the active scheduler.
+ // Abort doesn't cut the mustard.
+ delete iObexClient;
+ iObexClient=NULL;
+
+ // Delete the Obex object as we may try to delete the message store entry
+ // when we complete the observer and this will fail as the iObexObject has the
+ // associated attachment file open.
+ delete iObexObject;
+ iObexObject = NULL;
+
+ iTimeoutTimer->Cancel();
+
+ if(!iCancelWithoutCompleting)
+ {
+ // We will only get here if an external entity has called Cancel() on us, only
+ // the user (owner) of this active object will do this. In most cases this
+ // will be the direct result of a user action, e.g. cancelling a dialog
+ iSendState = TObexMtmProgress::EUserCancelled;
+ CompleteObserverL(); // complete the observer which owns this messaging op
+ }
+ }
+
+EXPORT_C TBool CObexServerSendOperation::CompletingObserver(TInt aErrorCode)
+/**
+* This is the default implementation that allows the server mtm to continue normally.
+* Tells the derived class that the base class is about to complete the observer.
+* This is the first thing called when CompleteObserverL is called.
+* Since the behaviour of CompleteObserverL is to clean up the message that it was trying to send,
+* this calls gives the derived class an opportunity to either stop this deletion or recover any information
+* synchronously from the message.
+* If the derived class has no need to use this functionality, the default implementation allows deletion.
+* @param aErrorCode The last error code encountered during operation
+* @return TBool True delete the message
+* @return TBool False DO NOT delete the message
+*/
+ {
+ (void)aErrorCode;
+
+ return ETrue;
+ }
+
+void CObexServerSendOperation::CompleteObserverL() //CMsvOperation completed.
+/**
+ * Complete the observer, reporting any error via the progress. THIS METHOD MUST BE CALLED ONCE ONLY.
+ *
+ */
+ {
+ ProgressL();
+ TObexMtmProgress& progress = iProgressPckg();
+
+ // If the message should be deleted then do it here.
+#ifndef MOVE_MESSAGE_TO_SENT
+
+ // this call gives the derived class an opportunity to control this behaviour.
+
+ // note that the error passed into this is the final one which the server mtm wants to
+ // report to the UI - occasionally, this will be KErrNone when in fact an Obex error
+ // did occur. To make sure that we tell the derived class exactly what happened, we
+ // pass the current state of the progress indicator out to it.
+
+ if(CompletingObserver(progress.iError))
+ SynchronousEntryDelete();
+#endif
+
+ TRequestStatus* status = &iObserverRequestStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+
+void CObexServerSendOperation::CompleteSelf(TInt aError)
+/**
+ * This causes this active object's request to complete which means
+ * RunL() will be called again if we are active (immediately if there
+ * are no higher priority active objects in the active scheduler).
+ *
+ * @param aError Error to be passed forward to the next step of the state machine
+ */
+ {
+ // This causes this active objects request to complete which means
+ // RunL() will be called again if we are active (immediately if there
+ // are no higher priority active objects in the active scheduler).
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, aError);
+ }
+
+EXPORT_C void CObexServerSendOperation::RunL()
+/**
+ * Calls RealRunL(), and traps errors
+ *
+ * @leave Leaves with errors from RealRunL()
+ */
+ {
+ TRAPD(err, RealRunL());
+
+ if(err)
+ {
+ ExplicitCancel(); //don't complete the observer, just cancel sending activity
+
+ // if RealRunL left in ESendError, sending it back would cause an endless loop!
+ if (iSendState == TObexMtmProgress::ESendError)
+ {
+ iStatus = err;
+ CompleteObserverL();
+
+ // update iStatus "manually" so that it shows the REAL error (the error that
+ // made RealRunL leave, not the previous error that made it go to ESendError)
+ // NOTE: if we left iStatus unchanged here, the observer would get the error
+ // that caused the send operation to fail. If for any reason this were thought to be
+ // better, just removing the following line would do.
+ }
+ else
+ {
+ iSendState = TObexMtmProgress::ESendError;
+
+ // this is so that RunL-RealRunL are called immediately to handle the error
+ // (the observer will be completed in RealRunL)
+
+ SetActive();
+ CompleteSelf(err);
+ }
+
+ User::Leave(err); // Allow system to display an error.
+ }
+ }
+
+/**
+ * This is not required to do anything in the base implementation.
+ */
+
+EXPORT_C void CObexServerSendOperation::SecondPhaseObexClientInitL()
+ {
+ }
+
+EXPORT_C void CObexServerSendOperation::PreConnectOperations()
+ {
+ }
+
+EXPORT_C void CObexServerSendOperation::PostConnectOperations()
+ {
+ }
+
+EXPORT_C void CObexServerSendOperation::PreSendOperations()
+ {
+ }
+
+EXPORT_C void CObexServerSendOperation::PostSendOperations()
+ {
+ }
+
+TInt CObexServerSendOperation::SynchronousEntryDelete()
+/**
+ * Delete the outbox entry as operation has 'completed'.
+ * Will be invisible&InPreparation anyway (MS delete will delete it the next
+ * time it starts).
+ */
+ {
+ // Delete the outbox entry as operation has 'completed'.
+ // Will be invisible&InPreparation anyway (MS delete will delete it the next
+ // time it starts).
+ TInt err;
+ const TMsvEntry& tMsvSentEntry = iMsvSendParent.Entry();
+ TInt messageId = tMsvSentEntry.Id();
+ err = iMsvSendParent.SetEntry(tMsvSentEntry.Parent());
+ if (err == KErrNone)
+ {
+ err = iMsvSendParent.DeleteEntry(messageId);
+ }
+ return err;
+ }
+
+void CObexServerSendOperation::InitialiseAttachmentL(CMsvServerEntry& aParent, TInt aWhichAttachment)
+/**
+ * Load an attachment into the obex sending buffer, and create a new Obex object of name TMsvEntry::iDetails.
+ *
+ * @param aParent Reference to CMsvServerEntry to be sent.
+ * @param aWhichAttachment Zero-based index of attachment to send.
+ * @leave KErrXXX system wide error codes
+ */
+ {
+ // Load an attachment into the obex sending buffer
+
+ // use the Attachment API to load the attachment files
+ CMsvStore* store = aParent.ReadStoreL();
+ CleanupStack::PushL(store);
+ CMsvAttachment* attachment = store->AttachmentManagerL().GetAttachmentInfoL(aWhichAttachment);
+ CleanupStack::PushL(attachment);
+ LoadFileIntoObjectL(attachment->FilePath(), attachment->AttachmentName(), attachment->MimeType());
+
+ // if any additional obex headers have been provided, set them
+ // in the obex object
+ TPtrC8 headerData;
+ if( attachment->GetDesC8Attribute(KUidObexHeaders, headerData) == KErrNone )
+ {
+ // header data exists, try to build an obex header list
+ CObexHeaderList* headerList = CObexHeaderList::NewLC();
+ headerList->ImportFromAttachmentL(*attachment);
+ headerList->AddHeadersToBaseObjectL(*iObexObject);
+ CleanupStack::PopAndDestroy(headerList);
+ }
+
+ CleanupStack::PopAndDestroy(2, store); // attachment, store
+ }
+
+void CObexServerSendOperation::LoadFileIntoObjectL(const TDesC& aFileName, const TDesC& aObexName, const TDesC8& aMimeType)
+ {
+ // Load the file into our send data buffer.
+ // Create a new Obex object from the file.
+
+ // Check we actually have a file
+ TEntry fileEntry;
+ User::LeaveIfError( FileSession().Entry(aFileName, fileEntry) );
+ if(fileEntry.IsDir())
+ User::Leave(KErrNotSupported); //Can't send a directory.
+
+ //Store the filename associated with the obex object
+ iSendFile = aFileName;
+
+ // Get the file length
+ RFile file;
+ User::LeaveIfError( file.Open(FileSession(), aFileName, EFileRead | EFileShareReadersOnly) );
+ CleanupClose<RFile>::PushL(file);
+ TInt fileLength;
+ User::LeaveIfError( file.Size(fileLength) );
+
+ // To allow file type recognition, read the file into sendBody
+ // only need the first KMaxBufSizeForRecognition bytes
+ HBufC8* sendBody = HBufC8::NewLC(fileLength < KMaxBufSizeForRecognition ? fileLength : KMaxBufSizeForRecognition);
+ TPtr8 sendBodyPtr = sendBody->Des();
+ User::LeaveIfError( file.Read(sendBodyPtr) );
+ CleanupStack::Pop(); //sendBodyPtr;
+ CleanupStack::PopAndDestroy(); //file.Close();
+ CleanupStack::PushL(sendBody); //Must be a better way to do this!
+
+ // Create an Obex object from the file.
+ delete iObexObject;
+ iObexObject=NULL;
+ iObexObject = CObexFileObject::NewL(iSendFile);
+
+ // Set the obex object name field
+ if(aObexName.Length()!=0)
+ {
+ iObexObject->SetNameL(aObexName); // Only *set* a header field if have some data, otherwise Obex will assert.
+ }
+
+ if( aMimeType.Length() > 0 )
+ {
+ iObexObject->SetTypeL(aMimeType);
+ }
+ else
+ {
+ // Attempt to recognise the datatype (MIME type) of the data in the send buffer
+ // but only set obex object type field if we are pretty confident of the
+ // Recogniser's result
+ RApaLsSession lsSess;
+ if( lsSess.Connect() == KErrNone)
+ {
+ CleanupClosePushL(lsSess);
+
+ TDataRecognitionResult result;
+ User::LeaveIfError( lsSess.RecognizeData(aObexName, sendBodyPtr, result) );
+ if (result.iConfidence>=CApaDataRecognizerType::EProbable)
+ {
+ iObexObject->SetTypeL(result.iDataType.Des8()); //only set a header field if have some data, otherwise Obex will assert.
+ }
+ CleanupStack::PopAndDestroy(); // lsSess;
+ }
+ }
+
+ // Set obex object length field for benefit of remote device's UI
+ iObexObject->SetLengthL(fileLength);
+
+ // Set obex object time field
+ TTime modifiedTime;
+ FileSession().Modified(aFileName, modifiedTime);
+ iObexObject->SetTimeL(modifiedTime);
+
+ //Cleanup
+ CleanupStack::PopAndDestroy(); //sendBody
+ }
+
+
+EXPORT_C void CObexServerSendOperation::GetUserPasswordL(const TDesC& /*aRelm*/)
+/**
+ * Called by the Obex Client when authentication is requested to pass the password back. If the password is invalid, this
+ * call should succeed but the send operation as a whole will inevitably fail.
+ *
+ * @param aRelm ignored, but could be used to indicate which password to use.
+ * @leave KErrXXX system wide error codes. Shouldn't leave just because the password is invalid.
+ * @leave KErrIrObexConnectChallRejected, if password is found empty.
+ */
+ {
+ //A "pusher" may not know in advance that the remote will issue an OBEX authentication challenge when connecting an OBEX session.
+ // As such if a password is not provided the MTM will return, KErrIrObexConnectChallRejected
+ if(!iConnectPassword)
+ {
+ User::Leave(KErrIrObexConnectChallRejected);
+ }
+
+ //Simply pass back the default user password
+ iObexClient->UserPasswordL(*iConnectPassword);
+ }
+
+
+TBool CObexServerSendOperation::CheckStatusOfLastObject(TInt aStatus, TObexMtmProgress::TSendState aSendState)
+/**
+ * Checks the last object was sent correctly, and tries to action appropriate error feedback if not. Only to be called
+ * from ESendObject/ESendNextObject or ESendComplete states.
+ *
+ * @param aStatus Status of last object
+ * @return ETrue if message was OK--EFalse if message failed and this function has taken the necessary action
+ */
+ {
+ if(aStatus != KErrNone)
+ {
+ if ((aStatus==KErrInUse) || (aStatus==KErrArgument))
+ {
+ //May indicate a problem with sending the previous object, or an error with a previous connection still
+ //being active--try and decide which
+ if (aSendState == TObexMtmProgress::ESendNextObject)
+ {
+ // Have managed to send at least one object - receiver might not be
+ // able to accept multiple objects.
+ CompleteSelf(KErrIrObexClientSubsequentPutFailed); //would be useful if this err was handled with a "Try sending one at a time" message to the user
+ }
+ else
+ {
+ // Have connected OK but couldn't send, so receiver might be dealing with
+ // a previous connection
+ CompleteSelf(KErrIrObexClientFirstPutFailed); //different to EMultiObjectSendError
+ }
+ }
+ else
+ {
+ // May indicate an error with the first or subsequent object
+ // Pass error code onto the owner of this messaging operation
+ CompleteSelf(aStatus); // General error.
+ }
+
+ iSendState=TObexMtmProgress::ESendError;
+ SetActive();
+ return EFalse;
+ }
+ else
+ {
+ return ETrue;
+ }
+ }
+
+TInt CObexServerSendOperation::PrepareCurrentObjectAndSetStateL()
+/**
+ * Loads the next object to be sent, whether an attachment or a file in the file list.
+ *
+ * @return KErrXXX standard error code
+ * @return KErrNotFound if there were neither attachments nor files in the file list
+ * @leave KErrXXX system wide error codes
+ */
+ {
+ // Have attachment(s) to be sent.
+ InitialiseAttachmentL(iMsvSendParent, iNextAttachment); //Load data into send buffer.
+ --iNextAttachment;
+ if(iNextAttachment<0) //iNextAttachment is 0 for a 1 attachment entry.
+ {
+ // Send will be complete after the current object has been sent so
+ // go to next state after the send operation completes
+ iSendState=TObexMtmProgress::ESendComplete;
+ }
+ else
+ {
+ // Still have another object to send after current object has been
+ // sent so return to this state after the send operation completes
+ iSendState=TObexMtmProgress::ESendNextObject;
+ }
+
+ //Successfully sent an attachment specified object
+ return KErrNone;
+ }
+
+void CObexServerSendOperation::MoveToSentAndSetActiveL()
+/**
+ * Moves the newly sent message to the global sent items folder, and sets active ready for its completion.
+ *
+ * @leave KErrXXX system wide error codes
+ */
+ {
+ iMoveEntrySelection = new (ELeave) CMsvEntrySelection;
+ iMoveEntrySelection->AppendL(iMsvSendParent.Entry().Id()); //i.e. just the sent message
+ iMsvSendParent.SetEntry(iMsvSendParent.Entry().Parent()); //Move to the parent
+ iMsvSendParent.MoveEntriesL(*iMoveEntrySelection, KMsvSentEntryId, iStatus);
+ iSendState = TObexMtmProgress::EMovedToSent;
+ SetActive();
+ }
+
+void CObexServerSendOperation::CleanupAfterMovedToSent()
+/**
+ * Restores after the message has been moved to the inbox, and marks the message as visible.
+ */
+ {
+ iMsvSendParent.SetEntry(iMoveEntrySelection->At(0)); //Switch back to actual message
+ TMsvEntry entry = iMsvSendParent.Entry();
+ entry.SetVisible(ETrue); // Moved OK. Make the entry visible and flag it as complete.
+ entry.SetInPreparation(EFalse);
+ iMsvSendParent.ChangeEntry(entry); //Commit changes
+ iMsvSendParent.SetEntry(KMsvNullIndexEntryId); //Unlock the entry
+ }
+
+
+RFs& CObexServerSendOperation::FileSession()
+/**
+ * Returns a reference to the file session (RFs) of the message
+ *
+ * @return A reference to the file session of the the message
+ */
+ {
+ return iMsvSendParent.FileSession();
+ }
+
+
+//
+//
+// CObexSendOpTimeout
+//
+//
+
+CObexSendOpTimeout* CObexSendOpTimeout::NewL(CObexServerSendOperation* aSendOperation)
+/**
+ *Canonical NewL function, which also sets the owner operation.
+ *
+ *@param aSendOperation Obex send operation which will be "timed out" when the timer expires
+ */
+ {
+ CObexSendOpTimeout* self=new (ELeave) CObexSendOpTimeout;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ self->iSendOperation = aSendOperation;
+ CleanupStack::Pop();
+ return self;
+ }
+
+CObexSendOpTimeout::CObexSendOpTimeout()
+ : CTimer(CActive::EPriorityStandard)
+ // Construct zero-priority active object
+/**
+ * Constructor. Calls CTimer's constructor with priority EPriorityStandard
+ */
+ {};
+
+void CObexSendOpTimeout::ConstructL()
+/**
+ * Second phase constructor. Calls CTimer::ConstructL(), and adds itself to the active scheduler
+ *
+ * @leave KErrXXX system wide error codes
+ */
+ {
+ CTimer::ConstructL();
+ CActiveScheduler::Add(this);
+ }
+
+void CObexSendOpTimeout::RunL()
+/**
+ * Calls the TimeOut method of the associated CObexServerSendOperation when the timer expires
+ *
+ * @leave KErrXXX system wide error codes
+ */
+ {
+ iSendOperation->TimeOut();
+ }
+
+
+
+
+//
+//
+// Panic
+//
+//
+
+GLDEF_C void Panic(TObexSendOperationPanic aPanic)
+ {
+ _LIT(KObexSendOperationPanic,"ObexSendOp");
+ User::Panic(KObexSendOperationPanic,aPanic);
+ }
+