31
|
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 "ObexSdpUtils.h"
|
|
18 |
//system includes
|
|
19 |
#include <es_sock.h>
|
|
20 |
|
|
21 |
|
|
22 |
//
|
|
23 |
// Bluetooth Assigned Numbers
|
|
24 |
// The following constants come from the Bluetooth Specification Version 1.0B
|
|
25 |
//
|
|
26 |
|
|
27 |
const TUint32 KObexProtocolUUIDValue = 0x0008;
|
|
28 |
const TUint32 KObexObjectPushUUIDValue = 0x1105;
|
|
29 |
const TUint32 K_L2CAP_UUID_Value = 0x0100;
|
|
30 |
const TUint32 K_RFCOMM_UUID_Value = 0x0003;
|
|
31 |
|
|
32 |
const TUint16 KServiceClassIdAttributeId = 0x0001;
|
|
33 |
const TUint16 KProtocolDescriptorListAttributeId = 0x0004;
|
|
34 |
const TUint16 KBluetoothProfileDescriptorListAttributeId = 0x0009;
|
|
35 |
const TUint16 KSupportedFormatsListAttributeId = 0x0303;
|
|
36 |
|
|
37 |
|
|
38 |
//
|
|
39 |
// The following structures are used to validate the record we receive from a remote
|
|
40 |
// device
|
|
41 |
//
|
|
42 |
|
|
43 |
const TInt KAttributes = 4;
|
|
44 |
const TInt KMaxComponents = 8;
|
|
45 |
const TInt KTAttributeComponentMembers = 3;
|
|
46 |
|
|
47 |
const TUint16 KExpectedAttributes[KAttributes] =
|
|
48 |
{
|
|
49 |
KServiceClassIdAttributeId,
|
|
50 |
KProtocolDescriptorListAttributeId,
|
|
51 |
KBluetoothProfileDescriptorListAttributeId,
|
|
52 |
KSupportedFormatsListAttributeId
|
|
53 |
};
|
|
54 |
|
|
55 |
const TUint32 KExpectedComponents[KAttributes][KMaxComponents][KTAttributeComponentMembers] =
|
|
56 |
{
|
|
57 |
// KServiceClassIdAttributeId
|
|
58 |
{
|
|
59 |
{CObexSdpUtils::EUint, ETrue, KServiceClassIdAttributeId},
|
|
60 |
{CObexSdpUtils::EAnythingUntilNextExpectedValue, EFalse, 0},
|
|
61 |
{CObexSdpUtils::EUUID, ETrue, KObexObjectPushUUIDValue},
|
|
62 |
{CObexSdpUtils::EAnythingUntilEnd, EFalse, 0}
|
|
63 |
},
|
|
64 |
// KProtocolDescriptorListAttributeId
|
|
65 |
{
|
|
66 |
{CObexSdpUtils::EUint, ETrue, KProtocolDescriptorListAttributeId},
|
|
67 |
{CObexSdpUtils::EAnythingUntilNextExpectedValue, EFalse, 0},
|
|
68 |
{CObexSdpUtils::EUUID, ETrue, K_L2CAP_UUID_Value},
|
|
69 |
{CObexSdpUtils::EUintPossible, ETrue, K_RFCOMM_UUID_Value}, //NOT MANDATORY TO RECEIVE THIS UINT
|
|
70 |
{CObexSdpUtils::EUUID, ETrue, K_RFCOMM_UUID_Value},
|
|
71 |
{CObexSdpUtils::EUint, EFalse, 0}, //REMOTE OBEX PORT NUMBER
|
|
72 |
{CObexSdpUtils::EUUID, ETrue, KObexProtocolUUIDValue},
|
|
73 |
{CObexSdpUtils::EAnythingUntilEnd, EFalse, 0}
|
|
74 |
},
|
|
75 |
// KBluetoothProfileDescriptorListAttributeId - NOT MANDATORY ATTRIBUTE BUT IF PRESENT INDICATES THAT REMOTE DEVICE CONFORMS 100% TO OBEX OBJECT PUSH PROFILE
|
|
76 |
{
|
|
77 |
{CObexSdpUtils::EUint, ETrue, KBluetoothProfileDescriptorListAttributeId},
|
|
78 |
{CObexSdpUtils::EAnythingUntilNextExpectedValue, EFalse, 0},
|
|
79 |
{CObexSdpUtils::EUUID, ETrue, KObexObjectPushUUIDValue},
|
|
80 |
{CObexSdpUtils::EUint, EFalse, 0}, //VERSION OF OBEX OBJECT PUT SUPPORTED
|
|
81 |
{CObexSdpUtils::EAnythingUntilEnd, EFalse, 0}
|
|
82 |
},
|
|
83 |
// KSupportedFormatsListAttributeId
|
|
84 |
{
|
|
85 |
{CObexSdpUtils::EUint, ETrue, KSupportedFormatsListAttributeId},
|
|
86 |
{CObexSdpUtils::EUintListUntilEnd, EFalse, 0}, // FORMATS SUPPORTED - LIST OF UINTS OF UNSPECIFIED LENGTH
|
|
87 |
{CObexSdpUtils::ENoComponent, EFalse, 0}
|
|
88 |
}
|
|
89 |
};
|
|
90 |
|
|
91 |
|
|
92 |
//
|
|
93 |
// CObexSdpUtils
|
|
94 |
//
|
|
95 |
|
|
96 |
|
|
97 |
EXPORT_C CObexSdpUtils* CObexSdpUtils::NewL(MObexSdpUtilsObserver& aObserver)
|
|
98 |
/**
|
|
99 |
* Leave safe constructor
|
|
100 |
*
|
|
101 |
* @param aObserver Used to indicate results of SDP query
|
|
102 |
*/
|
|
103 |
{
|
|
104 |
CObexSdpUtils* self = new(ELeave) CObexSdpUtils(aObserver);
|
|
105 |
CleanupStack::PushL(self);
|
|
106 |
self->ConstructL();
|
|
107 |
CleanupStack::Pop();
|
|
108 |
return self;
|
|
109 |
}
|
|
110 |
|
|
111 |
EXPORT_C CObexSdpUtils* CObexSdpUtils::NewLC(MObexSdpUtilsObserver& aObserver)
|
|
112 |
/**
|
|
113 |
* Leave safe constructor (which adds the newly created object to the cleanup stack)
|
|
114 |
*
|
|
115 |
* @param aObserver Used to indicate results of SDP query
|
|
116 |
*/
|
|
117 |
{
|
|
118 |
CObexSdpUtils* self = new(ELeave) CObexSdpUtils(aObserver);
|
|
119 |
CleanupStack::PushL(self);
|
|
120 |
self->ConstructL();
|
|
121 |
return self;
|
|
122 |
}
|
|
123 |
|
|
124 |
void CObexSdpUtils::ConstructL()
|
|
125 |
/**
|
|
126 |
* Necessary initial construction - Creates various structures used to check
|
|
127 |
* results obtained through CSdpAgent
|
|
128 |
*/
|
|
129 |
{
|
|
130 |
// Set up structures containing expected components
|
|
131 |
iAttributeArray = new(ELeave) CArrayPtrFlat<CAttribute>(1); //granularity of 1
|
|
132 |
|
|
133 |
TInt attrCount;
|
|
134 |
for (attrCount=0; attrCount<KAttributes; attrCount++)
|
|
135 |
{
|
|
136 |
CObexSdpUtils::CAttribute* attr = new(ELeave) CAttribute;
|
|
137 |
CleanupStack::PushL(attr);
|
|
138 |
attr->iAttributeComponentArray = new(ELeave) CArrayFixFlat<TAttributeComponent>(1); //granularity of 1
|
|
139 |
|
|
140 |
TInt compCount = -1;
|
|
141 |
do
|
|
142 |
{
|
|
143 |
compCount++;
|
|
144 |
TAttributeComponent comp;
|
|
145 |
comp.iType = (TType)KExpectedComponents[attrCount][compCount][0];
|
|
146 |
comp.iSpecificValue = KExpectedComponents[attrCount][compCount][1];
|
|
147 |
comp.iValue = KExpectedComponents[attrCount][compCount][2];
|
|
148 |
attr->iAttributeComponentArray->AppendL(comp);
|
|
149 |
} while (KExpectedComponents[attrCount][compCount][0]!=ENoComponent);
|
|
150 |
|
|
151 |
attr->iAttributeId = KExpectedAttributes[attrCount];
|
|
152 |
iAttributeArray->AppendL(attr);
|
|
153 |
CleanupStack::Pop(attr);
|
|
154 |
}
|
|
155 |
}
|
|
156 |
|
|
157 |
|
|
158 |
CObexSdpUtils::CObexSdpUtils(MObexSdpUtilsObserver& aObserver) : iObserver(aObserver), iIsActiveSDPQuery(EFalse)
|
|
159 |
|
|
160 |
/**
|
|
161 |
* Simple constructor
|
|
162 |
*
|
|
163 |
* @param aObserver Used to indicate results of SDP query
|
|
164 |
*/
|
|
165 |
{
|
|
166 |
}
|
|
167 |
|
|
168 |
CObexSdpUtils::~CObexSdpUtils()
|
|
169 |
/**
|
|
170 |
* Destructor. This can be called before the SDP Query completes to safely cancel the
|
|
171 |
* query - N.B. this is the only way to cancel a pending query
|
|
172 |
*/
|
|
173 |
{
|
|
174 |
if (iIsActiveSDPQuery)
|
|
175 |
// if we are in the middle of a query
|
|
176 |
{
|
|
177 |
HaltQueryWithError(KErrAbort);
|
|
178 |
//iObserver.RemoteBtObexQueryResult(KErrAbort,KErrNotFound,EFalse,KErrNotFound,iSupportedFormatsList);
|
|
179 |
//iSdpAgent->Cancel();
|
|
180 |
}
|
|
181 |
|
|
182 |
if(iSdpAgent)
|
|
183 |
// if we have started a SDP agent
|
|
184 |
{
|
|
185 |
delete iSdpAgent;
|
|
186 |
|
|
187 |
}
|
|
188 |
|
|
189 |
if(iAttributeArray)
|
|
190 |
iAttributeArray->ResetAndDestroy();
|
|
191 |
delete iAttributeArray;
|
|
192 |
}
|
|
193 |
|
|
194 |
|
|
195 |
EXPORT_C void CObexSdpUtils::RemoteBtObexQueryL(TBTDevAddr aBtDevAddr)
|
|
196 |
/**
|
|
197 |
* Perform SDP query on a remote bluetooth device. Result is returned through the MObexSdpUtilsObserver
|
|
198 |
* observer class. The query can be cancelled at any time by destroying this CObexSdpUtils
|
|
199 |
* object.
|
|
200 |
*
|
|
201 |
* @param aBtDevAddr The address of the bluetooth device
|
|
202 |
*/
|
|
203 |
{
|
|
204 |
if(iSdpAgent)
|
|
205 |
{
|
|
206 |
iSdpAgent->Cancel();
|
|
207 |
}
|
|
208 |
else
|
|
209 |
{
|
|
210 |
iSdpAgent = CSdpAgent::NewL(*this,aBtDevAddr);
|
|
211 |
}
|
|
212 |
|
|
213 |
// Set up search for SDP records containing the OBEX Object Push Service
|
|
214 |
// UUID.
|
|
215 |
// We also specify that the record must contain L2CAP and RFCOMM UUIDS as
|
|
216 |
// these are mandatory according to the BT Spec
|
|
217 |
CSdpSearchPattern* searchPattern = CSdpSearchPattern::NewL();
|
|
218 |
CleanupStack::PushL(searchPattern);
|
|
219 |
searchPattern->AddL(TUUID(KObexObjectPushUUIDValue));
|
|
220 |
searchPattern->AddL(TUUID(K_L2CAP_UUID_Value));
|
|
221 |
searchPattern->AddL(TUUID(K_RFCOMM_UUID_Value));
|
|
222 |
iSdpAgent->SetRecordFilterL(*searchPattern); //makes COPY of searchPattern
|
|
223 |
CleanupStack::PopAndDestroy(searchPattern);
|
|
224 |
|
|
225 |
// Start the search
|
|
226 |
iSdpRecordCount=0;
|
|
227 |
iSdpAgent->NextRecordRequestL(); //Will result in call to NextRecordRequestComplete()
|
|
228 |
iIsActiveSDPQuery = ETrue; //Keep record of the fact that we are mid query
|
|
229 |
}
|
|
230 |
|
|
231 |
void CObexSdpUtils::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount)
|
|
232 |
/**
|
|
233 |
* Got an SDP record from the remote device, so check for errors and then request the
|
|
234 |
* first attribute.
|
|
235 |
*
|
|
236 |
* @param aError Error code
|
|
237 |
* @param aHandle Handle to the service recorde
|
|
238 |
* @param aTotalRecordsCount The total number of records
|
|
239 |
*/
|
|
240 |
{
|
|
241 |
iSdpRecordCount++;
|
|
242 |
|
|
243 |
if (aError)
|
|
244 |
{
|
|
245 |
// return the error that has prevented us from continuing with our query
|
|
246 |
HaltQueryWithError(aError);
|
|
247 |
return;
|
|
248 |
}
|
|
249 |
|
|
250 |
if(iSdpRecordCount>aTotalRecordsCount)
|
|
251 |
{
|
|
252 |
// return KErrEof because we have gone through all the records and
|
|
253 |
// the port hasn't been found
|
|
254 |
HaltQueryWithError(KErrEof);
|
|
255 |
return;
|
|
256 |
}
|
|
257 |
|
|
258 |
// Got a record so let's request our first attribute
|
|
259 |
iNotThisSdpRecord = EFalse;
|
|
260 |
iRemoteObexPort = KErrNotFound;
|
|
261 |
iFullComplianceWithObexObjectPush = EFalse;
|
|
262 |
iObexObjectPushProfileVersion = KErrNotFound;
|
|
263 |
iSupportedFormatsList.SetLength(0);
|
|
264 |
|
|
265 |
iAttribute = -1;
|
|
266 |
RequestNextAttribute(aHandle); //will increment iAttribute to 0
|
|
267 |
}
|
|
268 |
|
|
269 |
void CObexSdpUtils::AttributeRequestResult(TSdpServRecordHandle /*aHandle*/, TSdpAttributeID /*aAttrID*/, CSdpAttrValue* /*aAttrValue*/)
|
|
270 |
/**
|
|
271 |
* The overload of AttributeRequestL() that we are using in NextRecordRequestComplete()
|
|
272 |
* should NOT result in this function being called, if it does then halt the query with an
|
|
273 |
* error.
|
|
274 |
*
|
|
275 |
* @param aHandle The handle to the service record
|
|
276 |
* @param aAttrID The SDP Attribute ID
|
|
277 |
* @param aAttrValue The SDP Attribute Value
|
|
278 |
*/
|
|
279 |
{
|
|
280 |
// The overload of AttributeRequestL() that we are using in NextRecordRequestComplete
|
|
281 |
// should NOT result in this function being called
|
|
282 |
HaltQueryWithError(KErrUnknown);
|
|
283 |
}
|
|
284 |
|
|
285 |
void CObexSdpUtils::AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError)
|
|
286 |
/**
|
|
287 |
* Called after we have got all the attribute components for current attribute being
|
|
288 |
* processed. If everything is OK get the next attribute or record.
|
|
289 |
*
|
|
290 |
* @param aHandle The handle to the service record
|
|
291 |
* @param aError The error code
|
|
292 |
*/
|
|
293 |
{
|
|
294 |
if (!aError && !iNotThisSdpRecord && iAttribute>=iAttributeArray->Count()-1 && iExpectedType==EUintListUntilEnd)
|
|
295 |
{
|
|
296 |
// Query is complete - got all the attributes and we have finished in the middle
|
|
297 |
// of compiling the list of supported obex formats (we can not know in advance the
|
|
298 |
// no. of formats a remote device supports)
|
|
299 |
iObserver.RemoteBtObexQueryResult(KErrNone,iRemoteObexPort,iFullComplianceWithObexObjectPush,iObexObjectPushProfileVersion,iSupportedFormatsList);
|
|
300 |
HaltQuery();
|
|
301 |
}
|
|
302 |
else
|
|
303 |
{
|
|
304 |
// See if we should continue looking at the attributes for this record
|
|
305 |
if (iNotThisSdpRecord //there was a problem with attribute UUIDs and Uints
|
|
306 |
|| (iExpectedType==EAnythingUntilNextExpectedValue) //we should have got whatever we expected next!
|
|
307 |
|| (iExpectedType==EUint) //we should always get the Uint we are looking for
|
|
308 |
|| (iExpectedType==EUUID) //we should always get the UUID we are looking for
|
|
309 |
|| (aError)) //an error has occurred, note that not finding an attribute does NOT result in KErrNotFound
|
|
310 |
{
|
|
311 |
// following is an exception to the rules above...
|
|
312 |
if (iCurrentAttributeId==KBluetoothProfileDescriptorListAttributeId) //it OK to not find what we expect in for attribute because attribute is not mandatory
|
|
313 |
{
|
|
314 |
// therefore everything is OK with the record so far - Request the next attribute
|
|
315 |
RequestNextAttribute(aHandle);
|
|
316 |
}
|
|
317 |
else
|
|
318 |
{
|
|
319 |
// this record didn't satisfy our query so try the next one
|
|
320 |
TRAPD(err,iSdpAgent->NextRecordRequestL()); //results in call to NextRecordRequestComplete()
|
|
321 |
if (err)
|
|
322 |
{
|
|
323 |
HaltQueryWithError(err);
|
|
324 |
}
|
|
325 |
}
|
|
326 |
}
|
|
327 |
else
|
|
328 |
{
|
|
329 |
// Everything is OK with the record so far - Request the next attribute
|
|
330 |
RequestNextAttribute(aHandle);
|
|
331 |
}
|
|
332 |
}
|
|
333 |
}
|
|
334 |
|
|
335 |
MSdpElementBuilder* CObexSdpUtils::BuildUUIDL(const TUUID& aUUID)
|
|
336 |
/**
|
|
337 |
* Got a UUID attribute component. Check it is what we expected to receive. Get the next attribute component.
|
|
338 |
*
|
|
339 |
* @param aUUID The Bluetooth UUID of attribute
|
|
340 |
*/
|
|
341 |
{
|
|
342 |
if(iNotThisSdpRecord
|
|
343 |
|| iExpectedType==EAnythingUntilEnd) //don't care what we get for current attribute anymore!
|
|
344 |
{
|
|
345 |
// Not interested in this UUID
|
|
346 |
return this;
|
|
347 |
}
|
|
348 |
|
|
349 |
if (iExpectedType==EAnythingUntilNextExpectedValue)
|
|
350 |
{
|
|
351 |
if (iNextExpectedType==EUUID && aUUID==TUUID(iNextExpectedValue))
|
|
352 |
{
|
|
353 |
// Got the "next" value we are looking for so set current expected to "next"
|
|
354 |
// and carry on!
|
|
355 |
NextAttributeComponent();
|
|
356 |
}
|
|
357 |
else
|
|
358 |
{
|
|
359 |
// Not interested in this UUID
|
|
360 |
return this;
|
|
361 |
}
|
|
362 |
}
|
|
363 |
|
|
364 |
iCurrentUUID = aUUID;
|
|
365 |
|
|
366 |
if (iExpectedType!=EUUID)
|
|
367 |
{
|
|
368 |
if (iExpectedType==EUintPossible)
|
|
369 |
{
|
|
370 |
// It was possible to receive a Uint but we got a UUID instead, this is
|
|
371 |
// perfectly valid. Go the the next component and call this method
|
|
372 |
// recursively to ensure next component is processed with this UUID
|
|
373 |
NextAttributeComponent();
|
|
374 |
BuildUUIDL(aUUID);
|
|
375 |
return this; //to prevent us missing an attribute
|
|
376 |
}
|
|
377 |
else
|
|
378 |
{
|
|
379 |
// Shouldn't have received a UUID!
|
|
380 |
iNotThisSdpRecord = ETrue;
|
|
381 |
}
|
|
382 |
}
|
|
383 |
else if (iExpectingSpecific)
|
|
384 |
{
|
|
385 |
if (aUUID != TUUID(iExpectedValue))
|
|
386 |
{
|
|
387 |
// Haven't got what we expected!
|
|
388 |
iNotThisSdpRecord = ETrue;
|
|
389 |
}
|
|
390 |
else if (aUUID==TUUID(KObexObjectPushUUIDValue) && iCurrentAttributeId==KBluetoothProfileDescriptorListAttributeId)
|
|
391 |
{
|
|
392 |
// Remote device complies fully with obex object push profile
|
|
393 |
iFullComplianceWithObexObjectPush = ETrue;;
|
|
394 |
}
|
|
395 |
}
|
|
396 |
else
|
|
397 |
{
|
|
398 |
// When dealing with UUIDs we are ALWAYS expecting a specific UUID.
|
|
399 |
// If we end up here then something has gone wrong
|
|
400 |
iNotThisSdpRecord = ETrue;
|
|
401 |
}
|
|
402 |
|
|
403 |
NextAttributeComponent();
|
|
404 |
return this;
|
|
405 |
}
|
|
406 |
|
|
407 |
|
|
408 |
MSdpElementBuilder* CObexSdpUtils::BuildUintL(const TDesC8& aUint)
|
|
409 |
/**
|
|
410 |
* Got a Uint attribute componet. Check it is what we expected to receive. Get the next attribute component.
|
|
411 |
*
|
|
412 |
* @param aUint Attribute as Uint contained in a descriptor
|
|
413 |
*/
|
|
414 |
{
|
|
415 |
if(iNotThisSdpRecord
|
|
416 |
|| iExpectedType==EAnythingUntilEnd) //don't care what we get for current attribute anymore!
|
|
417 |
{
|
|
418 |
// Not interested in this Uint
|
|
419 |
return this;
|
|
420 |
}
|
|
421 |
|
|
422 |
TUint32 uint = UInt32(aUint);
|
|
423 |
|
|
424 |
if (iExpectedType==EAnythingUntilNextExpectedValue)
|
|
425 |
{
|
|
426 |
if (iNextExpectedType==EUint && uint==iNextExpectedValue)
|
|
427 |
{
|
|
428 |
// Got the "next" value we are looking for so set current expected to "next"
|
|
429 |
// and carry on!
|
|
430 |
NextAttributeComponent();
|
|
431 |
}
|
|
432 |
else
|
|
433 |
{
|
|
434 |
// Not interested in this Uint
|
|
435 |
return this;
|
|
436 |
}
|
|
437 |
}
|
|
438 |
|
|
439 |
if (iExpectedType==ENoComponent || iExpectedType==EUUID)
|
|
440 |
{
|
|
441 |
// We should have not found a Uint
|
|
442 |
iNotThisSdpRecord = ETrue;
|
|
443 |
}
|
|
444 |
else if (iExpectingSpecific)
|
|
445 |
{
|
|
446 |
if (uint != iExpectedValue)
|
|
447 |
{
|
|
448 |
// haven't got what we expected!
|
|
449 |
iNotThisSdpRecord = ETrue;
|
|
450 |
}
|
|
451 |
}
|
|
452 |
else
|
|
453 |
{
|
|
454 |
// Not expecting a specific value so the value we've got is unknown so it's
|
|
455 |
// a piece of info we are trying to discover
|
|
456 |
|
|
457 |
if (iCurrentAttributeId==KProtocolDescriptorListAttributeId && iCurrentUUID==TUUID(K_RFCOMM_UUID_Value))
|
|
458 |
{
|
|
459 |
// Got the port number!
|
|
460 |
iRemoteObexPort = uint;
|
|
461 |
}
|
|
462 |
else if (iCurrentAttributeId==KBluetoothProfileDescriptorListAttributeId && iCurrentUUID==TUUID(KObexObjectPushUUIDValue))
|
|
463 |
{
|
|
464 |
// Got the Obex Object Push Profile Version
|
|
465 |
iObexObjectPushProfileVersion = uint;
|
|
466 |
}
|
|
467 |
else if (iCurrentAttributeId==KSupportedFormatsListAttributeId && iCurrentUUID==TUUID(NULL))
|
|
468 |
{
|
|
469 |
// Got an Obex format supported by the remote device
|
|
470 |
TInt length = iSupportedFormatsList.Length();
|
|
471 |
if (length<KMaxObexSupportedFormats)
|
|
472 |
{
|
|
473 |
iSupportedFormatsList.SetLength(length+1);
|
|
474 |
iSupportedFormatsList[length]=(TUint8)uint;
|
|
475 |
}
|
|
476 |
else
|
|
477 |
{
|
|
478 |
HaltQueryWithError(KErrTooBig);
|
|
479 |
}
|
|
480 |
return this; //don't go to next expected component because a list doesn't
|
|
481 |
//have a defined length
|
|
482 |
}
|
|
483 |
}
|
|
484 |
|
|
485 |
NextAttributeComponent();
|
|
486 |
return this;
|
|
487 |
}
|
|
488 |
|
|
489 |
MSdpElementBuilder* CObexSdpUtils::BuildUnknownL(TUint8 /*aType*/, TUint8 /*aSizeDesc*/, const TDesC8& /*aData*/)
|
|
490 |
/**
|
|
491 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
492 |
*/
|
|
493 |
{
|
|
494 |
return this;
|
|
495 |
}
|
|
496 |
|
|
497 |
MSdpElementBuilder* CObexSdpUtils::BuildNilL()
|
|
498 |
/**
|
|
499 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
500 |
*/
|
|
501 |
{
|
|
502 |
return this;
|
|
503 |
}
|
|
504 |
|
|
505 |
MSdpElementBuilder* CObexSdpUtils::BuildIntL(const TDesC8& /*aInt*/)
|
|
506 |
/**
|
|
507 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
508 |
*/
|
|
509 |
{
|
|
510 |
return this;
|
|
511 |
}
|
|
512 |
|
|
513 |
MSdpElementBuilder* CObexSdpUtils::BuildBooleanL(TBool /*aBool*/)
|
|
514 |
/**
|
|
515 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
516 |
*/
|
|
517 |
{
|
|
518 |
return this;
|
|
519 |
}
|
|
520 |
|
|
521 |
MSdpElementBuilder* CObexSdpUtils::BuildStringL(const TDesC8& /*aString*/)
|
|
522 |
/**
|
|
523 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
524 |
*/
|
|
525 |
{
|
|
526 |
return this;
|
|
527 |
}
|
|
528 |
|
|
529 |
MSdpElementBuilder* CObexSdpUtils::BuildDESL()
|
|
530 |
/**
|
|
531 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
532 |
*/
|
|
533 |
{
|
|
534 |
return this;
|
|
535 |
}
|
|
536 |
|
|
537 |
MSdpElementBuilder* CObexSdpUtils::BuildDEAL()
|
|
538 |
/**
|
|
539 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
540 |
*/
|
|
541 |
{
|
|
542 |
return this;
|
|
543 |
}
|
|
544 |
|
|
545 |
MSdpElementBuilder* CObexSdpUtils::StartListL()
|
|
546 |
/**
|
|
547 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
548 |
*/
|
|
549 |
{
|
|
550 |
return this;
|
|
551 |
}
|
|
552 |
|
|
553 |
MSdpElementBuilder* CObexSdpUtils::EndListL()
|
|
554 |
/**
|
|
555 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
556 |
*/
|
|
557 |
{
|
|
558 |
return this;
|
|
559 |
}
|
|
560 |
|
|
561 |
MSdpElementBuilder* CObexSdpUtils::BuildURLL(const TDesC8& /*aURL*/)
|
|
562 |
/**
|
|
563 |
* Not required for our SDP query, so we provide an empty implementation.
|
|
564 |
*/
|
|
565 |
{
|
|
566 |
return this;
|
|
567 |
}
|
|
568 |
|
|
569 |
TUint32 CObexSdpUtils::UInt32(const TDesC8& aUint)
|
|
570 |
/**
|
|
571 |
* Convert descriptor containing Uint to a numeric Uint.
|
|
572 |
*
|
|
573 |
* The Uints can be 1, 2, 4, 8 or 16 bytes long in theory. It is doubtful
|
|
574 |
* that the 8 or 16 byte variety would actually be used in our Obex Object
|
|
575 |
* Push Service case. The attribute Id will always be a 2 byte Uint but it
|
|
576 |
* is unclear from the spec what size the the port number should be. It is
|
|
577 |
* implied that it should only be 1 byte but in the EPOC implementation, it
|
|
578 |
* is returned as whatever size is it registered as (there is no type/size
|
|
579 |
* checking carried out in the SDP server).
|
|
580 |
*
|
|
581 |
* @param aUint The Uint as a descriptor
|
|
582 |
*/
|
|
583 |
{
|
|
584 |
TUint32 uint=0;
|
|
585 |
|
|
586 |
switch(aUint.Length())
|
|
587 |
{
|
|
588 |
case 1:
|
|
589 |
uint = (TUint32)aUint[0];
|
|
590 |
break;
|
|
591 |
case 2:
|
|
592 |
uint = (TUint32)(BigEndian::Get16(aUint.Ptr()));
|
|
593 |
break;
|
|
594 |
case 4:
|
|
595 |
default:
|
|
596 |
// for our query, if larger Uids are received they may be truncated
|
|
597 |
uint = BigEndian::Get32(aUint.Ptr());
|
|
598 |
break;
|
|
599 |
}
|
|
600 |
|
|
601 |
return uint;
|
|
602 |
}
|
|
603 |
|
|
604 |
void CObexSdpUtils::HaltQuery()
|
|
605 |
/**
|
|
606 |
* Halt the current SDP query by destroying the CSdpAgent.
|
|
607 |
*/
|
|
608 |
{
|
|
609 |
iSdpAgent->Cancel();
|
|
610 |
iIsActiveSDPQuery = EFalse;
|
|
611 |
}
|
|
612 |
|
|
613 |
void CObexSdpUtils::HaltQueryWithError(TInt aError)
|
|
614 |
/**
|
|
615 |
* Halt the current SDP query by destroying the CSdpAgent. Inform MObexSdpUtilsObserver
|
|
616 |
* observer that query has completed with an error.
|
|
617 |
*
|
|
618 |
* @param aError The error code
|
|
619 |
*/
|
|
620 |
{
|
|
621 |
iObserver.RemoteBtObexQueryResult(aError,KErrNotFound,EFalse,KErrNotFound,iSupportedFormatsList);
|
|
622 |
HaltQuery();
|
|
623 |
}
|
|
624 |
|
|
625 |
void CObexSdpUtils::RequestNextAttribute(TSdpServRecordHandle aHandle)
|
|
626 |
/**
|
|
627 |
* Get next attribute if we are expecting another attribute.
|
|
628 |
*
|
|
629 |
* @param aHandle The handle to the service records
|
|
630 |
*/
|
|
631 |
{
|
|
632 |
iAttribute++;
|
|
633 |
if (iAttribute >= iAttributeArray->Count())
|
|
634 |
{
|
|
635 |
// Shouldn't be requesting another attribute as have no expectation
|
|
636 |
// for another attribute
|
|
637 |
HaltQueryWithError(KErrNotFound);
|
|
638 |
}
|
|
639 |
else
|
|
640 |
{
|
|
641 |
iCurrentUUID=TUUID(NULL);
|
|
642 |
|
|
643 |
iAttributeComponent=-1;
|
|
644 |
NextAttributeComponent(); //will increment iAttributeComponent
|
|
645 |
|
|
646 |
iCurrentAttributeId = (*iAttributeArray)[iAttribute]->iAttributeId;
|
|
647 |
TRAPD(err,iSdpAgent->AttributeRequestL(this,aHandle,TSdpAttributeID(iCurrentAttributeId))); //results in multiple calls to BuildUUIDL() & BuildUintL(), ending with 1 call to AttributeRequestComplete()
|
|
648 |
if (err)
|
|
649 |
{
|
|
650 |
HaltQueryWithError(err);
|
|
651 |
}
|
|
652 |
}
|
|
653 |
}
|
|
654 |
|
|
655 |
void CObexSdpUtils::NextAttributeComponent()
|
|
656 |
/**
|
|
657 |
* Get next attribute component if we are expecting another attribute component. Set
|
|
658 |
* internal expectations for the next attribute component we receive.
|
|
659 |
*/
|
|
660 |
{
|
|
661 |
iAttributeComponent++;
|
|
662 |
if (iAttributeComponent >= (*iAttributeArray)[iAttribute]->iAttributeComponentArray->Count())
|
|
663 |
{
|
|
664 |
// Shouldn't be requesting another attribute component as we have no
|
|
665 |
// expectation for another attribute component
|
|
666 |
iNotThisSdpRecord = ETrue;
|
|
667 |
return;
|
|
668 |
}
|
|
669 |
|
|
670 |
// Set expectations for the next attribute component we receive
|
|
671 |
iExpectedType = (*(*iAttributeArray)[iAttribute]->iAttributeComponentArray)[iAttributeComponent].iType;
|
|
672 |
iExpectingSpecific = (*(*iAttributeArray)[iAttribute]->iAttributeComponentArray)[iAttributeComponent].iSpecificValue;
|
|
673 |
iExpectedValue = (*(*iAttributeArray)[iAttribute]->iAttributeComponentArray)[iAttributeComponent].iValue;
|
|
674 |
|
|
675 |
if (iExpectedType==EAnythingUntilNextExpectedValue)
|
|
676 |
{
|
|
677 |
iNextExpectedType = (*(*iAttributeArray)[iAttribute]->iAttributeComponentArray)[iAttributeComponent+1].iType;
|
|
678 |
iNextExpectedValue = (*(*iAttributeArray)[iAttribute]->iAttributeComponentArray)[iAttributeComponent+1].iValue;
|
|
679 |
}
|
|
680 |
}
|
|
681 |
|
|
682 |
|
|
683 |
CObexSdpUtils::CAttribute::CAttribute()
|
|
684 |
/**
|
|
685 |
* Simple constructor
|
|
686 |
*/
|
|
687 |
{
|
|
688 |
}
|
|
689 |
|
|
690 |
CObexSdpUtils::CAttribute::~CAttribute()
|
|
691 |
/**
|
|
692 |
* Destructor deletes array of attributes
|
|
693 |
*/
|
|
694 |
{
|
|
695 |
delete iAttributeComponentArray;
|
|
696 |
}
|