|
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 |