|
1 // Copyright (c) 2007-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 #include <s32mem.h> |
|
17 #include <e32svr.h> |
|
18 |
|
19 // KMimeVCardExtension is defined in miutmsg.h however including miutmsg.h also includes |
|
20 // flogger.h and conflicts with our inclusion of commsdebug via btaccesshostlog.h |
|
21 //#include <miutmsg.h> |
|
22 _LIT(KMimeVCardExtension, ".vcf"); |
|
23 |
|
24 #include <bt_sock.h> |
|
25 #include <obex.h> |
|
26 #include <obexbttransportinfo.h> |
|
27 |
|
28 #include <cntdb.h> |
|
29 |
|
30 #include "clientserver.h" |
|
31 #include "pbapserver.h" |
|
32 #include "pbapsession.h" |
|
33 #include "pbapappheader.h" |
|
34 #include "pbapfoldertree.h" |
|
35 #include "pbapfoldertelecom.h" |
|
36 #include "pbapfolderroot.h" |
|
37 #include "pbapfoldernodepb.h" |
|
38 #include "pbapfoldernodech.h" |
|
39 #include "pbapfoldersim.h" |
|
40 #include "pbapcontactdbviews.h" |
|
41 #include "pbapauthpasswordgetter.h" |
|
42 #include "pbapxml.h" |
|
43 #include "pbapserversecuritypolicy.h" |
|
44 #include "pbaplogeng.h" |
|
45 |
|
46 #include "btaccesshostlog.h" |
|
47 |
|
48 |
|
49 _LIT8(KPBAPLocalWho, "\x79\x61\x35\xf0\xf0\xc5\x11\xd8\x09\x66\x08\x00\x20\x0c\x9a\x66"); |
|
50 |
|
51 |
|
52 const TInt KBufGranularity = 100; |
|
53 const TInt KContactsDbOpenAttempts = 10; |
|
54 const TInt KContactsDbOpenDelay = 100000; //0.1 secs |
|
55 |
|
56 // |
|
57 // TCleanupItem operations - CPbapServer::ReleaseObex() |
|
58 // |
|
59 void PbapServerReleaseObex(TAny* aPtr) |
|
60 { |
|
61 LOG_STATIC_FUNC |
|
62 reinterpret_cast<CPbapServer*>(aPtr)->ReleaseObex(); |
|
63 } |
|
64 |
|
65 |
|
66 void CleanupPbapServerReleaseObexPushL(CPbapServer& aPbapServer) |
|
67 { |
|
68 LOG_STATIC_FUNC |
|
69 TCleanupItem item(PbapServerReleaseObex, &aPbapServer); |
|
70 CleanupStack::PushL(item); |
|
71 } |
|
72 |
|
73 |
|
74 // |
|
75 // CPbapServerShutdown |
|
76 // |
|
77 /*static*/ CPbapServerShutdown* CPbapServerShutdown::NewL() |
|
78 { |
|
79 LOG_STATIC_FUNC |
|
80 CPbapServerShutdown* self=new(ELeave) CPbapServerShutdown; |
|
81 CleanupStack::PushL(self); |
|
82 self->ConstructL(); |
|
83 CleanupStack::Pop(self); |
|
84 return self; |
|
85 } |
|
86 |
|
87 inline CPbapServerShutdown::CPbapServerShutdown() |
|
88 : CTimer(EPriorityLow) |
|
89 { |
|
90 LOG_FUNC |
|
91 CActiveScheduler::Add(this); |
|
92 } |
|
93 |
|
94 inline void CPbapServerShutdown::ConstructL() |
|
95 { |
|
96 LOG_FUNC |
|
97 CTimer::ConstructL(); |
|
98 } |
|
99 |
|
100 inline void CPbapServerShutdown::Start() |
|
101 { |
|
102 LOG_FUNC |
|
103 After(KPbapServerShutdownDelay); |
|
104 } |
|
105 |
|
106 void CPbapServerShutdown::RunL() |
|
107 { |
|
108 LOG_FUNC |
|
109 CActiveScheduler::Stop(); |
|
110 } |
|
111 |
|
112 |
|
113 // |
|
114 // CPbapServer |
|
115 // |
|
116 /*static*/ CPbapServer* CPbapServer::NewL() |
|
117 { |
|
118 LOG_STATIC_FUNC |
|
119 CPbapServer* self=new(ELeave) CPbapServer; |
|
120 CleanupStack::PushL(self); |
|
121 self->ConstructL(); |
|
122 CleanupStack::Pop(self); |
|
123 return self; |
|
124 } |
|
125 |
|
126 |
|
127 CPbapServer::CPbapServer() |
|
128 : CPolicyServer(EPriorityStandard, KPbapServerPolicy, ESharableSessions) |
|
129 { |
|
130 LOG_FUNC |
|
131 } |
|
132 |
|
133 |
|
134 CPbapServer::~CPbapServer() |
|
135 { |
|
136 LOG_FUNC |
|
137 |
|
138 // delete the obex server first because its destructor may call |
|
139 // functions which this class implements |
|
140 ReleaseObex(); |
|
141 |
|
142 if (iAsyncRestartObex) |
|
143 { |
|
144 iAsyncRestartObex->Cancel(); |
|
145 delete iAsyncRestartObex; |
|
146 } |
|
147 |
|
148 delete iPasswordGetter; |
|
149 delete iPassword; |
|
150 delete iOutboundObject; |
|
151 delete iOutboundBuffer; |
|
152 delete iVCardExporter; |
|
153 delete iShutdown; |
|
154 |
|
155 // the database must still be open when closing contact views so always |
|
156 // delete the object owning the views before the database |
|
157 delete iContactViews; |
|
158 |
|
159 delete iFolderTree; |
|
160 delete iLogWrapper; |
|
161 delete iContacts; |
|
162 iFs.Close(); |
|
163 iBufStreamer.Close(); |
|
164 iAppHeaderDetails.Close(); |
|
165 } |
|
166 |
|
167 |
|
168 void CPbapServer::ConstructL() |
|
169 { |
|
170 LOG_FUNC |
|
171 |
|
172 StartL(KPbapServerName); |
|
173 |
|
174 // ensure that the server will exit even if the 1st client fails to connect |
|
175 iShutdown = CPbapServerShutdown::NewL(); |
|
176 |
|
177 // create buffers ready for first obex get request |
|
178 iOutboundBuffer = CBufFlat::NewL(KBufGranularity); |
|
179 iOutboundObject = CObexBufObject::NewL(iOutboundBuffer); |
|
180 |
|
181 OpenContactsDbL(); |
|
182 |
|
183 // create contact database view manager |
|
184 iContactViews = CPbapContactDbViews::NewL(*iContacts); |
|
185 |
|
186 // if there is a problem with creating a logeng client then we will continue |
|
187 // but without any call history folders |
|
188 TRAP_IGNORE(CreateLogEngineClientL()); |
|
189 |
|
190 // create vCard exporter |
|
191 iVCardExporter = CPbapVCardExporterUtil::NewL(*iContacts, iLogWrapper); |
|
192 |
|
193 // create the restart obex callback used when an obex error occurs |
|
194 TCallBack callback(RestartObex, this); |
|
195 iAsyncRestartObex = new(ELeave) CAsyncCallBack(callback, CActive::EPriorityStandard); |
|
196 |
|
197 // start shutdown timer now |
|
198 iShutdown->Start(); |
|
199 } |
|
200 |
|
201 |
|
202 void CPbapServer::OpenContactsDbL() |
|
203 { |
|
204 LOG_FUNC |
|
205 TInt attempts=0; |
|
206 TInt error=KErrNone; |
|
207 while (attempts < KContactsDbOpenAttempts) |
|
208 { |
|
209 TRAP(error, iContacts = CContactDatabase::OpenL()); |
|
210 |
|
211 if (error==KErrLocked || error==KErrInUse) |
|
212 { |
|
213 // db maybe locked due to race condition so try again |
|
214 ++attempts; |
|
215 User::After(KContactsDbOpenDelay); |
|
216 } |
|
217 else |
|
218 { |
|
219 // success or not a db locked error so exit loop |
|
220 break; |
|
221 } |
|
222 } |
|
223 if (error) |
|
224 { |
|
225 LOG1(_L("Contacts database failed to open, error=%d"), error); |
|
226 User::Leave(error); |
|
227 } |
|
228 } |
|
229 |
|
230 |
|
231 void CPbapServer::CreateLogEngineClientL() |
|
232 { |
|
233 LOG_FUNC |
|
234 User::LeaveIfError(iFs.Connect()); |
|
235 |
|
236 // create access to call history information |
|
237 iLogWrapper = CPbapLogWrapper::NewL(iFs); |
|
238 } |
|
239 |
|
240 |
|
241 void CPbapServer::BuildVirtualFolderTreeL() |
|
242 { |
|
243 LOG_FUNC |
|
244 |
|
245 // create the root folder |
|
246 CVirtualFolders* rootFolder = CVirtualFolders::NewLC(); |
|
247 |
|
248 rootFolder->PlaceFolderL(CFolderRoot::NewL(*this)); //ownership passed |
|
249 rootFolder->AttachSubtree(TelecomSubTreeL()); //ownership passed |
|
250 |
|
251 #ifdef __INCLUDE_SIM1_FOLDERS__ |
|
252 // create the SIM1 folder below root |
|
253 CVirtualFolders* sim1Folder = CVirtualFolders::NewLC(); |
|
254 |
|
255 sim1Folder->PlaceFolderL(CFolderSIM1::NewL(*this)); //ownership passed |
|
256 sim1Folder->AttachSubtree(SIMTelecomSubTreeL()); //ownership passed |
|
257 rootFolder->AttachSubtree(sim1Folder); //ownership passed |
|
258 |
|
259 CleanupStack::Pop(sim1Folder); |
|
260 #endif // __INCLUDE_SIM1_FOLDERS__ |
|
261 |
|
262 CleanupStack::Pop(rootFolder); |
|
263 iFolderTree = rootFolder; |
|
264 iCurrentFolder = iFolderTree; |
|
265 } |
|
266 |
|
267 |
|
268 CVirtualFolders* CPbapServer::TelecomSubTreeL() |
|
269 { |
|
270 LOG_FUNC |
|
271 |
|
272 // create telecom folder |
|
273 CVirtualFolders* telecomFolder = CVirtualFolders::NewLC(); |
|
274 telecomFolder->PlaceFolderL(CFolderTelecom::NewL(*this)); //ownership passed |
|
275 |
|
276 // create pb sub folder |
|
277 CVirtualFolders* pbFolder = CVirtualFolders::NewLC(); |
|
278 |
|
279 pbFolder->PlaceFolderL(CFolderNodePb::NewL(*this)); //ownership passed |
|
280 telecomFolder->AttachSubtree(pbFolder); //ownership passed |
|
281 |
|
282 CleanupStack::Pop(pbFolder); |
|
283 |
|
284 // make sure that we successfully created a logeng client |
|
285 if (iLogWrapper && (iLogWrapper->ClientAvailable())) |
|
286 { |
|
287 // create ich sub folder |
|
288 CVirtualFolders* ichFolder = CVirtualFolders::NewLC(); |
|
289 |
|
290 ichFolder->PlaceFolderL(CFolderNodeIch::NewL(*this)); //ownership passed |
|
291 telecomFolder->AttachSubtree(ichFolder); //ownership passed |
|
292 |
|
293 CleanupStack::Pop(ichFolder); |
|
294 |
|
295 //create och sub folder |
|
296 CVirtualFolders* ochFolder = CVirtualFolders::NewLC(); |
|
297 |
|
298 ochFolder->PlaceFolderL(CFolderNodeOch::NewL(*this)); //ownership passed |
|
299 telecomFolder->AttachSubtree(ochFolder); //ownership passed |
|
300 |
|
301 CleanupStack::Pop(ochFolder); |
|
302 |
|
303 // create mch sub folder |
|
304 CVirtualFolders* mchFolder = CVirtualFolders::NewLC(); |
|
305 |
|
306 mchFolder->PlaceFolderL(CFolderNodeMch::NewL(*this)); //ownership passed |
|
307 telecomFolder->AttachSubtree(mchFolder); //ownership passed |
|
308 |
|
309 CleanupStack::Pop(mchFolder); |
|
310 |
|
311 // create cch sub folder |
|
312 CVirtualFolders* cchFolder = CVirtualFolders::NewLC(); |
|
313 |
|
314 cchFolder->PlaceFolderL(CFolderNodeCch::NewL(*this)); //ownership passed |
|
315 telecomFolder->AttachSubtree(cchFolder); //ownership passed |
|
316 |
|
317 CleanupStack::Pop(cchFolder); |
|
318 } |
|
319 |
|
320 CleanupStack::Pop(telecomFolder); |
|
321 return telecomFolder; |
|
322 } |
|
323 |
|
324 #ifdef __INCLUDE_SIM1_FOLDERS__ |
|
325 CVirtualFolders* CPbapServer::SIMTelecomSubTreeL() |
|
326 { |
|
327 LOG_FUNC |
|
328 |
|
329 // create SIM1 telecom folder |
|
330 CVirtualFolders* telecomFolder = CVirtualFolders::NewLC(); |
|
331 |
|
332 telecomFolder->PlaceFolderL(CFolderSIM1Telecom::NewL(*this)); //ownership passed |
|
333 |
|
334 // create SIM1 pb sub folder |
|
335 CVirtualFolders* pbFolder = CVirtualFolders::NewLC(); |
|
336 |
|
337 pbFolder->PlaceFolderL(CFolderSIM1NodePb::NewL(*this)); //ownership passed |
|
338 telecomFolder->AttachSubtree(pbFolder); //ownership passed |
|
339 |
|
340 CleanupStack::Pop(pbFolder); |
|
341 |
|
342 // create SIM1 ich sub folder |
|
343 CVirtualFolders* ichFolder = CVirtualFolders::NewLC(); |
|
344 |
|
345 ichFolder->PlaceFolderL(CFolderSIM1NodeIch::NewL(*this)); //ownership passed |
|
346 telecomFolder->AttachSubtree(ichFolder); //ownership passed |
|
347 |
|
348 CleanupStack::Pop(ichFolder); |
|
349 |
|
350 // create SIM1 och sub folder |
|
351 CVirtualFolders* ochFolder = CVirtualFolders::NewLC(); |
|
352 |
|
353 ochFolder->PlaceFolderL(CFolderSIM1NodeOch::NewL(*this)); //ownership passed |
|
354 telecomFolder->AttachSubtree(ochFolder); //ownership passed |
|
355 |
|
356 CleanupStack::Pop(ochFolder); |
|
357 |
|
358 // create SIM1 mch sub folder |
|
359 CVirtualFolders* mchFolder = CVirtualFolders::NewLC(); |
|
360 |
|
361 mchFolder->PlaceFolderL(CFolderSIM1NodeMch::NewL(*this)); //ownership passed |
|
362 telecomFolder->AttachSubtree(mchFolder); //ownership passed |
|
363 |
|
364 CleanupStack::Pop(mchFolder); |
|
365 |
|
366 // create SIM1 cch sub folder |
|
367 CVirtualFolders* cchFolder = CVirtualFolders::NewLC(); |
|
368 |
|
369 cchFolder->PlaceFolderL(CFolderSIM1NodeCch::NewL(*this)); //ownership passed |
|
370 telecomFolder->AttachSubtree(cchFolder); //ownership passed |
|
371 |
|
372 CleanupStack::Pop(cchFolder); |
|
373 |
|
374 CleanupStack::Pop(telecomFolder); |
|
375 return telecomFolder; |
|
376 } |
|
377 #endif // __INCLUDE_SIM1_FOLDERS__ |
|
378 |
|
379 /*virtual*/ CContactDatabase& CPbapServer::ContactDB() const |
|
380 { |
|
381 LOG_FUNC |
|
382 return *iContacts; |
|
383 } |
|
384 |
|
385 |
|
386 /*virtual*/ CPbapContactDbViews& CPbapServer::ContactDbViews() |
|
387 { |
|
388 LOG_FUNC |
|
389 return *iContactViews; |
|
390 } |
|
391 |
|
392 /*virtual*/ CPbapLogWrapper& CPbapServer::LogClient() const |
|
393 { |
|
394 LOG_FUNC |
|
395 return *iLogWrapper; |
|
396 } |
|
397 |
|
398 /*virtual*/ MPbapExporter& CPbapServer::Exporter() |
|
399 { |
|
400 LOG_FUNC |
|
401 return *static_cast<MPbapExporter*>(this); |
|
402 } |
|
403 |
|
404 |
|
405 /*virtual*/ MPbapErrorReporter& CPbapServer::ErrorReporter() |
|
406 { |
|
407 LOG_FUNC |
|
408 return *static_cast<MPbapErrorReporter*>(this); |
|
409 } |
|
410 |
|
411 |
|
412 /*virtual*/ void CPbapServer::StartExport() |
|
413 { |
|
414 LOG_FUNC |
|
415 __ASSERT_ALWAYS(!iExportInProgress, Panic(EPbapServerPanicExportInProgress)); |
|
416 |
|
417 // open the obex stream ready for export |
|
418 iBufStreamer.Open(*iOutboundBuffer); |
|
419 |
|
420 // set flag to indicate export started |
|
421 iExportInProgress=ETrue; |
|
422 } |
|
423 |
|
424 |
|
425 /*virtual*/ void CPbapServer::ExportListingBeginL() |
|
426 { |
|
427 LOG_FUNC |
|
428 if(iExportInProgress == EFalse) |
|
429 { |
|
430 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
431 User::Leave(KErrNotReady); |
|
432 } |
|
433 if (iExportInProgress) |
|
434 { |
|
435 // write the XML DTD header |
|
436 PbapDTD::WriteBeginL(iBufStreamer); |
|
437 } |
|
438 } |
|
439 |
|
440 |
|
441 /*virtual*/ void CPbapServer::ExportListingEntryL(TInt aHandle, const TDesC& aName) |
|
442 { |
|
443 LOG_FUNC |
|
444 if(iExportInProgress == EFalse) |
|
445 { |
|
446 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
447 User::Leave(KErrNotReady); |
|
448 } |
|
449 if (iExportInProgress) |
|
450 { |
|
451 // write listing entry to stream |
|
452 PbapDTD::WriteListingEntryL(iBufStreamer, aHandle, aName); |
|
453 } |
|
454 } |
|
455 |
|
456 |
|
457 /*virtual*/ void CPbapServer::ExportListingEndL() |
|
458 { |
|
459 LOG_FUNC |
|
460 if(iExportInProgress == EFalse) |
|
461 { |
|
462 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
463 User::Leave(KErrNotReady); |
|
464 } |
|
465 if (iExportInProgress) |
|
466 { |
|
467 // write the XML DTD end tag |
|
468 PbapDTD::WriteEndL(iBufStreamer); |
|
469 } |
|
470 } |
|
471 |
|
472 |
|
473 /*virtual*/ void CPbapServer::ExportCallHistoryL(const CLogEvent& aEvent, TVCardVersion aFormat, TUint64 aFilter) |
|
474 { |
|
475 LOG_FUNC |
|
476 if(iExportInProgress == EFalse) |
|
477 { |
|
478 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
479 User::Leave(KErrNotReady); |
|
480 } |
|
481 if (iExportInProgress) |
|
482 { |
|
483 // convert log event to a vCard and add to stream |
|
484 iVCardExporter->ExportCallHistoryL(aEvent, iBufStreamer, aFormat, aFilter); |
|
485 } |
|
486 } |
|
487 |
|
488 |
|
489 /*virtual*/ void CPbapServer::ExportContactL(TContactItemId aContactId, TVCardVersion aFormat, TUint64 aFilter) |
|
490 { |
|
491 LOG_FUNC |
|
492 if(iExportInProgress == EFalse) |
|
493 { |
|
494 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
495 User::Leave(KErrNotReady); |
|
496 } |
|
497 if (iExportInProgress) |
|
498 { |
|
499 // convert contact to a vCard and add to stream |
|
500 iVCardExporter->ExportContactL(aContactId, iBufStreamer, aFormat, aFilter); |
|
501 } |
|
502 } |
|
503 |
|
504 |
|
505 /*virtual*/ void CPbapServer::ExportEmptyVCardL(TVCardVersion aFormat) |
|
506 { |
|
507 LOG_FUNC |
|
508 if(iExportInProgress == EFalse) |
|
509 { |
|
510 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
511 User::Leave(KErrNotReady); |
|
512 } |
|
513 if (iExportInProgress) |
|
514 { |
|
515 // create empty vCard and add to stream |
|
516 iVCardExporter->ExportEmptyVCardL(iBufStreamer, aFormat); |
|
517 } |
|
518 } |
|
519 |
|
520 |
|
521 /*virtual*/ void CPbapServer::ExportPhonebookSizeL(TInt aCount) |
|
522 { |
|
523 LOG_FUNC |
|
524 if(iExportInProgress == EFalse) |
|
525 { |
|
526 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
527 User::Leave(KErrNotReady); |
|
528 } |
|
529 if (iExportInProgress) |
|
530 { |
|
531 // add phonebook size to obex header, total size is 4 bytes |
|
532 TInt currentLength = iAppHeaderDetails.Length(); |
|
533 iAppHeaderDetails.ReAllocL(currentLength+4); |
|
534 iAppHeaderDetails.SetMax(); |
|
535 |
|
536 // add 1 byte tag id |
|
537 iAppHeaderDetails[currentLength] = CPbapAppHeader::EPhonebookSize; |
|
538 |
|
539 // add length of arguments, 2 bytes |
|
540 iAppHeaderDetails[currentLength+1] = 2; |
|
541 |
|
542 // add phonebook size, 2 bytes |
|
543 BigEndian::Put16(&iAppHeaderDetails[currentLength+2], aCount); |
|
544 } |
|
545 } |
|
546 |
|
547 |
|
548 /*virtual*/ void CPbapServer::ExportNewMissedCallsL(TInt aCount) |
|
549 { |
|
550 LOG_FUNC |
|
551 if(iExportInProgress == EFalse) |
|
552 { |
|
553 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
554 User::Leave(KErrNotReady); |
|
555 } |
|
556 if (iExportInProgress) |
|
557 { |
|
558 // add new missed call count to obex header, total size is 3 bytes |
|
559 TInt currentLength = iAppHeaderDetails.Length(); |
|
560 iAppHeaderDetails.ReAllocL(currentLength+3); |
|
561 iAppHeaderDetails.SetMax(); |
|
562 |
|
563 // add 1 byte tag id |
|
564 iAppHeaderDetails[currentLength] = CPbapAppHeader::ENewMissedCalls; |
|
565 |
|
566 // add length of arguments, 1 byte |
|
567 iAppHeaderDetails[currentLength+1] = 1; |
|
568 |
|
569 // add missed call count, 1 byte |
|
570 iAppHeaderDetails[currentLength+2] = aCount; |
|
571 } |
|
572 } |
|
573 |
|
574 |
|
575 /*virtual*/ void CPbapServer::FinaliseExportL() |
|
576 { |
|
577 LOG_FUNC |
|
578 if(iExportInProgress == EFalse) |
|
579 { |
|
580 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNotReadyForExport)); |
|
581 User::Leave(KErrNotReady); |
|
582 } |
|
583 // set flag to indicate no more writing to the stream |
|
584 if (iExportInProgress) |
|
585 { |
|
586 // close the stream |
|
587 iBufStreamer.Close(); |
|
588 |
|
589 // add header information |
|
590 if (iAppHeaderDetails.Length()) |
|
591 { |
|
592 iOutboundObject->SetAppParamL(iAppHeaderDetails); |
|
593 } |
|
594 |
|
595 // reset app header |
|
596 iAppHeaderDetails.Zero(); |
|
597 |
|
598 // request active mode to improve sending if object is large enough |
|
599 const TObexTransportInfo* transInfo = iObex->TransportInfo(); |
|
600 if (transInfo && (iOutboundObject->DataBuf()->Size() > transInfo->iTransmitMtu)) |
|
601 { |
|
602 // ignore any error, the Open() may have failed |
|
603 iPhysLinkAdaptor.ActivateActiveRequester(); |
|
604 } |
|
605 |
|
606 // send over obex |
|
607 User::LeaveIfError(iObex->RequestIndicationCallback(iOutboundObject)); |
|
608 |
|
609 iExportInProgress=EFalse; |
|
610 } |
|
611 } |
|
612 |
|
613 |
|
614 /*virtual*/ void CPbapServer::CancelExport() |
|
615 { |
|
616 LOG_FUNC |
|
617 // set flag to indicate |
|
618 iExportInProgress=EFalse; |
|
619 iAppHeaderDetails.Zero(); |
|
620 |
|
621 // cleanup the buffers used for the get requests |
|
622 CleanupGetRequest(); |
|
623 } |
|
624 |
|
625 |
|
626 |
|
627 /*virtual*/ void CPbapServer::SendServiceUnavailableError() |
|
628 { |
|
629 LOG_FUNC |
|
630 ReportObexError(KErrGeneral); |
|
631 } |
|
632 |
|
633 |
|
634 /*virtual*/ void CPbapServer::SendPreconditionFailedError() |
|
635 { |
|
636 LOG_FUNC |
|
637 ReportObexError(KErrArgument); |
|
638 } |
|
639 |
|
640 |
|
641 /*virtual*/ void CPbapServer::SendNotFoundError() |
|
642 { |
|
643 LOG_FUNC |
|
644 ReportObexError(KErrNotFound); |
|
645 } |
|
646 |
|
647 |
|
648 /** |
|
649 create new session |
|
650 */ |
|
651 CSession2* CPbapServer::NewSessionL(const TVersion &aVersion, const RMessage2& /*aMessage*/) const |
|
652 { |
|
653 LOG_FUNC |
|
654 TVersion v(KPbapServerMajorVersionNumber,KPbapServerMinorVersionNumber,KPbapServerBuildVersionNumber); |
|
655 if (!User::QueryVersionSupported(v,aVersion)) |
|
656 { |
|
657 User::Leave(KErrNotSupported); |
|
658 } |
|
659 |
|
660 // we only support one active session |
|
661 if (iActiveSession) |
|
662 { |
|
663 User::Leave(KErrInUse); |
|
664 } |
|
665 |
|
666 return new(ELeave) CPbapSession(); |
|
667 } |
|
668 |
|
669 |
|
670 /** |
|
671 a new session is being created Cancel the shutdown timer if it was running |
|
672 */ |
|
673 void CPbapServer::AddSession() |
|
674 { |
|
675 LOG_FUNC |
|
676 iActiveSession = ETrue; |
|
677 iShutdown->Cancel(); |
|
678 } |
|
679 |
|
680 |
|
681 /** |
|
682 a session is being destroyed. Start the shutdown timer if it is the last session. |
|
683 */ |
|
684 void CPbapServer::DropSession() |
|
685 { |
|
686 LOG_FUNC |
|
687 iActiveSession = EFalse; |
|
688 iShutdown->Start(); |
|
689 } |
|
690 |
|
691 |
|
692 void CPbapServer::StartObexL() |
|
693 { |
|
694 LOG_FUNC |
|
695 |
|
696 if (!iObex) |
|
697 { |
|
698 TBTServiceSecurity serv; |
|
699 serv.SetUid(KPbapServerUid); |
|
700 |
|
701 serv.SetAuthentication(ETrue); // note: this needs to be reconsidered in light of SSP. |
|
702 serv.SetAuthorisation(ETrue); |
|
703 serv.SetEncryption(ETrue); |
|
704 |
|
705 // now set up Obex... |
|
706 TObexBluetoothProtocolInfo info; |
|
707 info.iTransport = KObexRfcommProtocol; |
|
708 info.iAddr.SetPort(KRfcommPassiveAutoBind); |
|
709 info.iAddr.SetSecurity(serv); |
|
710 |
|
711 iObex = CObexServer::NewL(info); |
|
712 iObex->SetLocalWho(KPBAPLocalWho); |
|
713 iObex->SetTargetChecking(CObexServer::EAlways); |
|
714 |
|
715 // push self onto cleanup stack to ReleaseObex if a leave |
|
716 CleanupPbapServerReleaseObexPushL(*this); |
|
717 |
|
718 // start accepting requests to obex server |
|
719 TInt error = iObex->Start(this); |
|
720 if (error != KErrNone) |
|
721 { |
|
722 LOG1(_L("Error %d starting Obex server"), error); |
|
723 User::Leave(error); |
|
724 } |
|
725 |
|
726 if (iPassword) |
|
727 { |
|
728 // a password has been set so enable obex authentication |
|
729 TRAP(error, iObex->SetChallengeL(*iPassword)); |
|
730 if (error != KErrNone) |
|
731 { |
|
732 LOG1(_L("Error %d setting authentication challenge"), error); |
|
733 User::Leave(error); |
|
734 } |
|
735 } |
|
736 |
|
737 // obex started succesfully, retrieve assigned RFCOMM channel |
|
738 const TObexBtTransportInfo* transportInfo = static_cast<const TObexBtTransportInfo*>(iObex->TransportInfo()); |
|
739 TUint rfcommChannel = transportInfo->iAddr.Port(); |
|
740 |
|
741 // now the RFCOMM channel is known register the SDP record to allow bluetooth connections |
|
742 TRAP(error, RegisterWithSdpL(rfcommChannel)); |
|
743 if (error != KErrNone) |
|
744 { |
|
745 LOG1(_L("Error %d registering SDP record"), error); |
|
746 User::Leave(error); |
|
747 } |
|
748 |
|
749 // enable client authentication challenge handling |
|
750 iObex->SetCallBack(*this); |
|
751 CleanupStack::Pop(this); |
|
752 } |
|
753 } |
|
754 |
|
755 |
|
756 void CPbapServer::ReleaseObex() |
|
757 { |
|
758 LOG_FUNC |
|
759 |
|
760 // stop all connections to the obex server (we need to delete the server rather |
|
761 // than just call Stop() otherwise the rfcomm channel will not be assigned |
|
762 // a new value when starting it again) |
|
763 delete iObex; |
|
764 iObex = NULL; |
|
765 |
|
766 // delete the stored password |
|
767 delete iPassword; |
|
768 iPassword = NULL; |
|
769 |
|
770 // release the SDP record |
|
771 ReleaseSdpRegistration(); |
|
772 } |
|
773 |
|
774 /*static*/ TInt CPbapServer::RestartObex(TAny* aAny) |
|
775 { |
|
776 LOG_STATIC_FUNC |
|
777 CPbapServer* self = static_cast<CPbapServer*>(aAny); |
|
778 self->DoRestartObex(); |
|
779 return KErrNone; |
|
780 } |
|
781 |
|
782 void CPbapServer::DoRestartObex() |
|
783 { |
|
784 LOG_FUNC |
|
785 |
|
786 // We need to keep the authentication password as this re-start was not initiated |
|
787 // by the Client side application. |
|
788 HBufC* currentPassword = iPassword; |
|
789 iPassword = NULL; |
|
790 ReleaseObex(); |
|
791 |
|
792 iPassword = currentPassword; |
|
793 TRAPD(err, StartObexL()); |
|
794 |
|
795 if (err != KErrNone) |
|
796 { |
|
797 LOG1(_L("Error %d restarting Obex server"), err); |
|
798 |
|
799 // nothing left to do, panic server to inform client |
|
800 Panic(EPbapServerPanicUnrecoverableObexError); |
|
801 } |
|
802 } |
|
803 |
|
804 #ifdef _DEBUG |
|
805 void CPbapServer::ErrorIndication(TInt aError) |
|
806 #else |
|
807 void CPbapServer::ErrorIndication(TInt /*aError*/) |
|
808 #endif |
|
809 { |
|
810 LOG_FUNC |
|
811 LOG1(_L("Obex Error Indication: %d"), aError); |
|
812 |
|
813 // this is a fatal OBEX error so reset our state... |
|
814 CleanupOnDisconnect(); |
|
815 |
|
816 // ...and re-start the obex server (needs to be done async from this error indication callback) |
|
817 iAsyncRestartObex->CallBack(); |
|
818 } |
|
819 |
|
820 |
|
821 void CPbapServer::TransportUpIndication() |
|
822 { |
|
823 LOG_FUNC |
|
824 // Availablity is updated here in a deviation from the specification which |
|
825 // defines the Pbap session as existing from the time the OBEX connection is |
|
826 // established. Since OBEX can only maintain one connection over BT in the |
|
827 // current implemenation it is more practical for us to set our availablity now |
|
828 // instead of waiting for the OBEX connection as the RFComm channel is already |
|
829 // closed effectively making our service unavailable |
|
830 UpdateAvailability(EPbapUnavailable); |
|
831 } |
|
832 |
|
833 |
|
834 void CPbapServer::TransportDownIndication() |
|
835 { |
|
836 LOG_FUNC |
|
837 // underlying transport has disconnected |
|
838 UpdateAvailability(EPbapAvailable); |
|
839 CleanupOnDisconnect(); |
|
840 } |
|
841 |
|
842 |
|
843 void CPbapServer::ObexConnectIndication(const TObexConnectInfo& aRemoteInfo, const TDesC8& /*aInfo*/) |
|
844 { |
|
845 LOG_FUNC |
|
846 LOG(_L("Connect packet target header:")); |
|
847 LOGHEXDESC(aRemoteInfo.iTargetHeader); |
|
848 |
|
849 if (aRemoteInfo.iTargetHeader!=KPBAPLocalWho) |
|
850 { |
|
851 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicInvalidTargetHeader)); |
|
852 } |
|
853 |
|
854 else |
|
855 { |
|
856 // build the virtual folder tree at the start of the session. Failure to build |
|
857 // the folder tree is handled later with error respones to get/set path requests |
|
858 TRAP_IGNORE(BuildVirtualFolderTreeL()); |
|
859 |
|
860 // get remote address |
|
861 TSockAddr sockAddr; |
|
862 iObex->RemoteAddr(sockAddr); |
|
863 TBTDevAddr devAddr = static_cast<TBTSockAddr>(sockAddr).BTAddr(); |
|
864 |
|
865 // create a physical links adaptor |
|
866 if (iSocketServ.Connect() == KErrNone) |
|
867 { |
|
868 // don't store the error from Open, any further sniff/active requests will not |
|
869 // succeed but this will not stop any functionality |
|
870 if (iPhysLinkAdaptor.Open(iSocketServ, devAddr) == KErrNone) |
|
871 { |
|
872 // request sniff straight away as we will request active mode when it is |
|
873 // required |
|
874 iPhysLinkAdaptor.ActivateSniffRequester(); |
|
875 } |
|
876 } |
|
877 } |
|
878 } |
|
879 |
|
880 |
|
881 void CPbapServer::ObexDisconnectIndication(const TDesC8& /*aInfo*/) |
|
882 { |
|
883 LOG_FUNC |
|
884 CleanupOnDisconnect(); |
|
885 } |
|
886 |
|
887 |
|
888 void CPbapServer::PutRequestIndication() |
|
889 { |
|
890 LOG_FUNC |
|
891 // Always return a Bad Request error in response to PUT requests |
|
892 ReportObexError(KErrCorrupt); |
|
893 } |
|
894 |
|
895 |
|
896 TInt CPbapServer::PutPacketIndication() |
|
897 { |
|
898 LOG_FUNC |
|
899 // the remote device should have handled the PUT request error and not sent |
|
900 // any data. If not then just respond to each packet with another error |
|
901 return KErrIrObexRespForbidden; |
|
902 } |
|
903 |
|
904 |
|
905 void CPbapServer::PutCompleteIndication() |
|
906 { |
|
907 LOG_FUNC |
|
908 // the remote device should have handled the PUT request error and not sent |
|
909 // any data. If not then just respond with an error |
|
910 ReportObexError(KErrAccessDenied); |
|
911 } |
|
912 |
|
913 |
|
914 // report an OBEX error based on a Symbian global error code |
|
915 void CPbapServer::ReportObexError(TInt aSymbianError) |
|
916 { |
|
917 TObexResponse obexErr = ERespSuccess; |
|
918 |
|
919 switch (aSymbianError) |
|
920 { |
|
921 case KErrAccessDenied: // the request is barred |
|
922 obexErr = ERespForbidden; |
|
923 break; |
|
924 |
|
925 case KErrNotFound: // the requested folder doesnot exist |
|
926 obexErr = ERespNotFound; |
|
927 break; |
|
928 |
|
929 case KErrNotSupported: // the folder does not support get requests (e.g SIM repositories not implemented) |
|
930 obexErr = ERespNotImplemented; |
|
931 break; |
|
932 |
|
933 case KErrArgument: // invalid parameter value in header |
|
934 obexErr = ERespPreCondFailed; |
|
935 break; |
|
936 |
|
937 case KErrCorrupt: // badly formatted header |
|
938 obexErr = ERespBadRequest; |
|
939 break; |
|
940 |
|
941 case KErrGeneral: |
|
942 default: // another error stopped request completing (e.g out of memory) |
|
943 obexErr = ERespServiceUnavailable; |
|
944 break; |
|
945 } |
|
946 iObex->RequestIndicationCallbackWithError(obexErr); |
|
947 |
|
948 // get request failed so clean up for the next one |
|
949 CleanupGetRequest(); |
|
950 } |
|
951 |
|
952 void CPbapServer::GetRequestIndication(CObexBaseObject* aRequiredObject) |
|
953 { |
|
954 LOG_FUNC |
|
955 TRAPD(error, DoGetRequestIndicationL(aRequiredObject)); |
|
956 if (error != KErrNone) |
|
957 { |
|
958 ReportObexError(error); |
|
959 } |
|
960 } |
|
961 |
|
962 |
|
963 void CPbapServer::DoGetRequestIndicationL(CObexBaseObject* aRequiredObject) |
|
964 { |
|
965 LOG_FUNC |
|
966 CPbapAppHeader* appHeader = CPbapAppHeader::NewL(); |
|
967 CleanupStack::PushL(appHeader); |
|
968 |
|
969 // parse the application parameters |
|
970 appHeader->ParseL(aRequiredObject->AppParam()); |
|
971 |
|
972 // determine the operation from the object type and parsed application params |
|
973 TPbapOperation operation = appHeader->DeterminePBAPOperationL(aRequiredObject->Type()); |
|
974 |
|
975 // we only allow one get operation at a time |
|
976 if (iGetRequestFolder) |
|
977 { |
|
978 // get operation in progress |
|
979 User::Leave(KErrInUse); |
|
980 } |
|
981 |
|
982 // check name for .vcf extension |
|
983 TPtrC name = aRequiredObject->Name(); |
|
984 if (name.Right(KMimeVCardExtension().Length())==KMimeVCardExtension()) |
|
985 { |
|
986 if (operation == EPullVCardListing) |
|
987 { |
|
988 // we found a .vcf extension but shouldn't have |
|
989 User::Leave(KErrArgument); |
|
990 } |
|
991 |
|
992 // trim extension |
|
993 name.Set(name.Left(name.Length()-KMimeVCardExtension().Length())); |
|
994 } |
|
995 else if ((operation == EPullPhoneBook) || (operation == EPullVCard)) |
|
996 { |
|
997 // we didn't find a .vcf extension but should have |
|
998 User::Leave(KErrArgument); |
|
999 } |
|
1000 |
|
1001 // create a copy of the trimmed name so that it can be modified to remove the path |
|
1002 // information when we set iGetRequestFolder below |
|
1003 RBuf objectName; |
|
1004 objectName.CleanupClosePushL(); |
|
1005 objectName.CreateL(name); |
|
1006 |
|
1007 // navigate to folder (the path is always absolute for x-bt/phonebook type requests) |
|
1008 iGetRequestFolder = ResolvePath(objectName, appHeader->IsAbsolutePathOp()); |
|
1009 |
|
1010 // the remaining object name might be a file representation of a phonebook |
|
1011 // (e.g pb.vcf) if so it should have a matching folder representation. If this |
|
1012 // is true then route the get request to this folder |
|
1013 if (iGetRequestFolder && objectName.Length() && operation != EPullVCard) |
|
1014 { |
|
1015 LOG(_L("Re-routing Get request from file representation to folder representation")); |
|
1016 CVirtualFolders* subFolder = iGetRequestFolder->NavigateFolder(objectName); |
|
1017 if (subFolder) |
|
1018 { |
|
1019 iGetRequestFolder = subFolder; |
|
1020 objectName.Zero(); // no more information so set length of objectName to zero |
|
1021 } |
|
1022 } |
|
1023 |
|
1024 // let the folder handle the get request. The request is completed asynchronously |
|
1025 // so it is the folders responsibilty to notify obex when processing is complete |
|
1026 if (iGetRequestFolder) |
|
1027 { |
|
1028 // To supress false positive coverity error for alias and double_free from cleanup stack for appHeader. |
|
1029 // The function Get takes ownership of appHeader by aliasing and does its own destruction of it either immediately on error |
|
1030 // or when finnished with the object. |
|
1031 // coverity[double_free] |
|
1032 TInt error = iGetRequestFolder->Folder().Get(objectName, appHeader); |
|
1033 if (error != KErrNone) |
|
1034 { |
|
1035 LOG1(_L("Error %d from issuing Get to folder object"), error); |
|
1036 ReportObexError(error); |
|
1037 } |
|
1038 |
|
1039 // ownership of appHeader passed so don't destroy it |
|
1040 CleanupStack::PopAndDestroy(); //objectName |
|
1041 CleanupStack::Pop(); //appHeader |
|
1042 } |
|
1043 else |
|
1044 { |
|
1045 CleanupStack::PopAndDestroy(2); //appHeader, objectName |
|
1046 ReportObexError(KErrNotFound); |
|
1047 } |
|
1048 } |
|
1049 |
|
1050 |
|
1051 /** |
|
1052 Return folder which request will be operating on, and modify passed in path |
|
1053 descriptor to contain only the file name |
|
1054 */ |
|
1055 CVirtualFolders* CPbapServer::ResolvePath(TDes& aPath, TBool aAbsolute) const |
|
1056 { |
|
1057 LOG_FUNC |
|
1058 LOG2(_L("Resolving path %S, [absolute=%d]"), &aPath, aAbsolute); |
|
1059 |
|
1060 const TChar KSlash('/'); |
|
1061 TInt index = 0; |
|
1062 |
|
1063 // it is ok to have a NULL iFolderTree as we ignore any problems we had when |
|
1064 // building it so just return NULL |
|
1065 if (!iFolderTree) |
|
1066 { |
|
1067 return NULL; |
|
1068 } |
|
1069 |
|
1070 // if we have a iFolderTree then we must have a iCurrentFolder |
|
1071 if(!iCurrentFolder) |
|
1072 { |
|
1073 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNoCurrentFolder)); |
|
1074 return NULL; |
|
1075 } |
|
1076 |
|
1077 // start at root if absolute path or the current folder if relative path |
|
1078 CVirtualFolders* nextTree = aAbsolute ? iFolderTree : iCurrentFolder; |
|
1079 |
|
1080 if (aPath.Length()>=1) // blank means dont change folder |
|
1081 { |
|
1082 if (aPath[index]==KSlash) |
|
1083 { |
|
1084 aPath.Delete(index,1); |
|
1085 nextTree = iFolderTree; |
|
1086 } |
|
1087 |
|
1088 do |
|
1089 { |
|
1090 index = aPath.Locate(KSlash); |
|
1091 if (index!=KErrNotFound) |
|
1092 { |
|
1093 // try to enter subfolder |
|
1094 TPtrC folder(aPath.Left(index)); |
|
1095 nextTree = nextTree->NavigateFolder(folder); |
|
1096 if (!nextTree) |
|
1097 { |
|
1098 // faulty path spec |
|
1099 nextTree = NULL; |
|
1100 break; |
|
1101 } |
|
1102 else |
|
1103 { |
|
1104 // trim off this bit of path AND the '/'! |
|
1105 aPath.Delete(0, index+1); |
|
1106 } |
|
1107 } |
|
1108 } while (index!=KErrNotFound); |
|
1109 } |
|
1110 |
|
1111 return nextTree; |
|
1112 } |
|
1113 |
|
1114 |
|
1115 TInt CPbapServer::GetPacketIndication() |
|
1116 { |
|
1117 LOG_FUNC |
|
1118 // do nothing (the PSE doesnot support a UI with progress updates) |
|
1119 return KErrNone; |
|
1120 } |
|
1121 |
|
1122 |
|
1123 void CPbapServer::GetCompleteIndication() |
|
1124 { |
|
1125 LOG_FUNC |
|
1126 |
|
1127 TInt err = iObex->RequestCompleteIndicationCallback(KErrNone); |
|
1128 __ASSERT_DEBUG(err==KErrNone, Panic(EPbapServerPanicUnexpectedError)); |
|
1129 |
|
1130 // prepare for next request |
|
1131 CleanupGetRequest(); |
|
1132 } |
|
1133 |
|
1134 |
|
1135 void CPbapServer::SetPathIndication(const CObex::TSetPathInfo& aPathInfo, const TDesC8& /*aInfo*/) |
|
1136 { |
|
1137 LOG_FUNC |
|
1138 |
|
1139 TInt err = KErrNone; |
|
1140 |
|
1141 // it is ok to have a NULL iFolderTree as we ignore any problems we had when |
|
1142 // building it |
|
1143 if (!iFolderTree) |
|
1144 { |
|
1145 LOG(_L("Folder tree not created")); |
|
1146 err = KErrNotFound; |
|
1147 } |
|
1148 else if (aPathInfo.Parent()) |
|
1149 { |
|
1150 LOG(_L("Set folder to parent")); |
|
1151 |
|
1152 // if we have a iFolderTree then we must have a iCurrentFolder |
|
1153 if(!iCurrentFolder) |
|
1154 { |
|
1155 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNoCurrentFolder)); |
|
1156 err = KErrNotFound; |
|
1157 } |
|
1158 else |
|
1159 { |
|
1160 // move to parent folder if it exists (it will not if already at root) |
|
1161 CVirtualFolders* folder = iCurrentFolder->ParentFolder(); |
|
1162 if (folder) |
|
1163 { |
|
1164 iCurrentFolder = folder; |
|
1165 } |
|
1166 else |
|
1167 { |
|
1168 err = KErrNotFound; |
|
1169 } |
|
1170 } |
|
1171 } |
|
1172 else if (aPathInfo.iNamePresent) |
|
1173 { |
|
1174 if (aPathInfo.iName!=KNullDesC) |
|
1175 { |
|
1176 LOG1(_L("Set folder to child [%S]"), &aPathInfo.iName); |
|
1177 |
|
1178 // if we have a iFolderTree then we must have a iCurrentFolder |
|
1179 if(!iCurrentFolder) |
|
1180 { |
|
1181 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNoCurrentFolder)); |
|
1182 err = KErrNotFound; |
|
1183 } |
|
1184 else |
|
1185 { |
|
1186 CVirtualFolders* folder = iCurrentFolder->NavigateFolder(aPathInfo.iName); |
|
1187 if (folder) |
|
1188 { |
|
1189 iCurrentFolder = folder; |
|
1190 } |
|
1191 else |
|
1192 { |
|
1193 err = KErrNotFound; |
|
1194 } |
|
1195 } |
|
1196 } |
|
1197 else |
|
1198 { |
|
1199 LOG(_L("Set folder to root")); |
|
1200 |
|
1201 // if we have a iFolderTree then we must have a iCurrentFolder |
|
1202 if(!iCurrentFolder) |
|
1203 { |
|
1204 __ASSERT_DEBUG(EFalse, Panic(EPbapServerPanicNoCurrentFolder)); |
|
1205 err = KErrNotFound; |
|
1206 } |
|
1207 |
|
1208 iCurrentFolder = iFolderTree; |
|
1209 } |
|
1210 } |
|
1211 else |
|
1212 { |
|
1213 // this is not a request to change to the parent folder therefore we should have a name |
|
1214 // header but we don't, return error |
|
1215 LOG(_L("No Name header present")); |
|
1216 err = KErrArgument; |
|
1217 } |
|
1218 |
|
1219 // return any obex errors |
|
1220 if (err == KErrNotFound) |
|
1221 { |
|
1222 LOG(_L("Error folder does not exist")); |
|
1223 iObex->RequestCompleteIndicationCallback(ERespNotFound); |
|
1224 } |
|
1225 else if (err == KErrArgument) |
|
1226 { |
|
1227 LOG(_L("Error invalid argument")); |
|
1228 iObex->RequestCompleteIndicationCallback(ERespPreCondFailed); |
|
1229 } |
|
1230 else |
|
1231 { |
|
1232 iObex->RequestCompleteIndicationCallback(KErrNone); |
|
1233 } |
|
1234 } |
|
1235 |
|
1236 |
|
1237 void CPbapServer::AbortIndication() |
|
1238 { |
|
1239 LOG_FUNC |
|
1240 |
|
1241 // the get request was aborted during the obex transfer (i.e. after processing |
|
1242 // the request had completed). So just clean up the obex buffers |
|
1243 CleanupGetRequest(); |
|
1244 } |
|
1245 |
|
1246 |
|
1247 void CPbapServer::CancelIndicationCallback() |
|
1248 { |
|
1249 LOG_FUNC |
|
1250 // the get request was cancelled before sending any data. |
|
1251 // so cancel any ongoing asynchronous processing and cleanup obex buffers |
|
1252 if (iGetRequestFolder) |
|
1253 { |
|
1254 iGetRequestFolder->Folder().CancelGet(); |
|
1255 } |
|
1256 |
|
1257 CleanupGetRequest(); |
|
1258 } |
|
1259 |
|
1260 void CPbapServer::GetUserPasswordL(const TDesC& aRealm) |
|
1261 { |
|
1262 LOG_FUNC |
|
1263 LOG1(_L("Authentication challenge [Realm = %S]"), &aRealm); |
|
1264 |
|
1265 delete iPasswordGetter; |
|
1266 iPasswordGetter = NULL; |
|
1267 iPasswordGetter = CPbapAuthPasswordGetter::NewL(*this); |
|
1268 |
|
1269 // get the Bluetooth device address of the client making the authentication challenge |
|
1270 TSockAddr sockAddr; |
|
1271 iObex->RemoteAddr(sockAddr); |
|
1272 TBTDevAddr devAddr = static_cast<TBTSockAddr>(sockAddr).BTAddr(); |
|
1273 |
|
1274 // start async password request |
|
1275 iPasswordGetter->GetPassword(aRealm, devAddr); |
|
1276 } |
|
1277 |
|
1278 void CPbapServer::HandlePasswordRetrieved(TInt aError, const TDesC& aPassword) |
|
1279 { |
|
1280 LOG_FUNC |
|
1281 |
|
1282 if (aError == KErrNone) |
|
1283 { |
|
1284 // if we successfully got a password, pass it to obex |
|
1285 TRAP(aError, iObex->UserPasswordL(aPassword)); |
|
1286 } |
|
1287 |
|
1288 if (aError != KErrNone) |
|
1289 { |
|
1290 LOG1(_L("Error %d creating response to authentication challenge"), aError); |
|
1291 // creating the challenge response has failed. Since there is no way to report |
|
1292 // the error to the obex server the only option is to force a reset of the |
|
1293 // connection state by restarting the server |
|
1294 iObex->Stop(); |
|
1295 aError = iObex->Start(this); |
|
1296 if (aError != KErrNone) |
|
1297 { |
|
1298 LOG1(_L("Error %d restarting Obex server"), aError); |
|
1299 ReleaseObex(); |
|
1300 |
|
1301 // nothing left to do, panic server to inform client |
|
1302 Panic(EPbapServerPanicUnrecoverableObexError); |
|
1303 } |
|
1304 } |
|
1305 } |
|
1306 |
|
1307 void CPbapServer::SetPasswordL(HBufC* aPassword) |
|
1308 { |
|
1309 LOG_FUNC |
|
1310 if (iObex) |
|
1311 { |
|
1312 // the obex server exists so set its challenge now |
|
1313 iObex->SetChallengeL(*aPassword); |
|
1314 } |
|
1315 // store the password (transfers ownership) |
|
1316 delete iPassword; |
|
1317 iPassword = aPassword; |
|
1318 } |
|
1319 |
|
1320 void CPbapServer::CleanupGetRequest() |
|
1321 { |
|
1322 LOG_FUNC |
|
1323 |
|
1324 // request sniff mode again as get request finished, ignore errors |
|
1325 iPhysLinkAdaptor.ActivateSniffRequester(); |
|
1326 |
|
1327 // clean the exporter |
|
1328 if (iGetRequestFolder) |
|
1329 { |
|
1330 iGetRequestFolder->Folder().GetComplete(); |
|
1331 } |
|
1332 |
|
1333 iGetRequestFolder = NULL; |
|
1334 iOutboundBuffer->Reset(); |
|
1335 iOutboundObject->Reset(); |
|
1336 iBufStreamer.Close(); |
|
1337 } |
|
1338 |
|
1339 |
|
1340 void CPbapServer::CleanupOnDisconnect() |
|
1341 { |
|
1342 LOG_FUNC |
|
1343 |
|
1344 CleanupGetRequest(); |
|
1345 |
|
1346 // close physical links adaptor |
|
1347 iPhysLinkAdaptor.Close(); |
|
1348 iSocketServ.Close(); |
|
1349 |
|
1350 // destroy the virtual folder tree when the session ends |
|
1351 delete iFolderTree; |
|
1352 iFolderTree = NULL; |
|
1353 iCurrentFolder = NULL; |
|
1354 |
|
1355 // close contacts views to save memory (this will also cancel any current requests to sort and search views) |
|
1356 iContactViews->CloseAllViews(); |
|
1357 |
|
1358 // make sure the authentication notifier is cancelled by deleting its handler |
|
1359 delete iPasswordGetter; |
|
1360 iPasswordGetter = NULL; |
|
1361 } |
|
1362 |
|
1363 |
|
1364 void Panic(TPbapServerPanicCode aPanic) |
|
1365 { |
|
1366 LOG_STATIC_FUNC |
|
1367 User::Panic(KPbapServerPanic, aPanic); |
|
1368 } |
|
1369 |
|
1370 |
|
1371 /** |
|
1372 Perform all server initialisation, in particular creation of the |
|
1373 scheduler and server and then run the scheduler |
|
1374 */ |
|
1375 static void RunServerL() |
|
1376 { |
|
1377 LOG_STATIC_FUNC |
|
1378 |
|
1379 // naming the server thread after the server helps to debug panics |
|
1380 User::RenameThread(KPbapServerName); |
|
1381 |
|
1382 // create and install the active scheduler we need |
|
1383 CActiveScheduler* scheduler=new(ELeave) CActiveScheduler; |
|
1384 CleanupStack::PushL(scheduler); |
|
1385 CActiveScheduler::Install(scheduler); |
|
1386 |
|
1387 // create the server (leave it on the cleanup stack) |
|
1388 CPbapServer* server = CPbapServer::NewL(); |
|
1389 CleanupStack::PushL(server); |
|
1390 |
|
1391 // initialisation complete, now signal the client thread |
|
1392 RProcess::Rendezvous(KErrNone); |
|
1393 |
|
1394 // ready to run |
|
1395 CActiveScheduler::Start(); |
|
1396 |
|
1397 // cleanup the server and scheduler |
|
1398 CleanupStack::PopAndDestroy(2, scheduler); |
|
1399 } |
|
1400 |
|
1401 |
|
1402 /** |
|
1403 Server process entry-point. |
|
1404 @return KErrNone or a standard Symbian error code. |
|
1405 */ |
|
1406 TInt E32Main() |
|
1407 { |
|
1408 __UHEAP_MARK; |
|
1409 |
|
1410 #ifdef __FLOG_ACTIVE |
|
1411 // connect to logger |
|
1412 (void)CBtLog::Connect(); |
|
1413 #endif |
|
1414 |
|
1415 CTrapCleanup* cleanup=CTrapCleanup::New(); |
|
1416 TInt r=KErrNoMemory; |
|
1417 if (cleanup) |
|
1418 { |
|
1419 TRAP(r, RunServerL()); |
|
1420 delete cleanup; |
|
1421 } |
|
1422 |
|
1423 #ifdef __FLOG_ACTIVE |
|
1424 // close logger connection |
|
1425 CBtLog::Close(); |
|
1426 #endif |
|
1427 |
|
1428 __UHEAP_MARKEND; |
|
1429 return r; |
|
1430 } |