|
1 // Copyright (c) 2004-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 "TEquiv.h" |
|
17 #include <uriutils.h> |
|
18 #include <uriutilscommon.h> |
|
19 #include "UriUtilsInternal.h" |
|
20 #include <delimitedpathsegment8.h> |
|
21 #include <delimitedquery8.h> |
|
22 #include <escapeutils.h> |
|
23 |
|
24 _LIT8(KParamUserFull, ";user="); |
|
25 _LIT8(KParamTtlFull, ";ttl="); |
|
26 _LIT8(KParamMethodFull, ";method="); |
|
27 _LIT8(KParamMaddrFull, ";maddr="); |
|
28 _LIT8(KParamMaddr, "maddr"); |
|
29 |
|
30 _LIT8(KHeaderId, "call-id"); |
|
31 _LIT8(KHeaderIdAbbr, "i"); |
|
32 _LIT8(KHeaderContact, "contact"); |
|
33 _LIT8(KHeaderContactAbbr, "m"); |
|
34 _LIT8(KHeaderEncoding, "content-encoding"); |
|
35 _LIT8(KHeaderEncodingAbbr, "e"); |
|
36 _LIT8(KHeaderLength, "content-length"); |
|
37 _LIT8(KHeaderLengthAbbr, "l"); |
|
38 _LIT8(KHeaderType, "content-type"); |
|
39 _LIT8(KHeaderTypeAbbr, "c"); |
|
40 _LIT8(KHeaderFrom, "from"); |
|
41 _LIT8(KHeaderFromAbbr, "f"); |
|
42 _LIT8(KHeaderSubject, "subject"); |
|
43 _LIT8(KHeaderSubjectAbbr, "s"); |
|
44 _LIT8(KHeaderTo, "to"); |
|
45 _LIT8(KHeaderToAbbr, "t"); |
|
46 |
|
47 TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs) |
|
48 : iLhs(aLhs), iRhs(aRhs) |
|
49 { |
|
50 } |
|
51 |
|
52 TBool TEquiv::EquivalentL() const |
|
53 { |
|
54 if (!IsMatchSchemeL()) |
|
55 return KUriUtilsErrDifferentScheme; |
|
56 |
|
57 if (!IsMatchUserInfoL()) |
|
58 return KUriUtilsErrDifferentUserInfo; |
|
59 |
|
60 if (!IsMatchHostL()) |
|
61 return KUriUtilsErrDifferentHost; |
|
62 |
|
63 if (!IsMatchPortL()) |
|
64 return KUriUtilsErrDifferentPort; |
|
65 |
|
66 if (!IsMatchPathL()) |
|
67 return KUriUtilsErrDifferentPath; |
|
68 |
|
69 if (!IsMatchQueryL()) |
|
70 return KUriUtilsErrDifferentQuery; |
|
71 |
|
72 if (!IsMatchFragmentL()) |
|
73 return KUriUtilsErrDifferentFragment; |
|
74 |
|
75 return KErrNone; |
|
76 } |
|
77 |
|
78 TBool TEquiv::IsMatchSchemeL() const |
|
79 { |
|
80 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme); |
|
81 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme); |
|
82 TBool result = IsMatchCaseless(*lhsDes, *rhsDes); |
|
83 CleanupStack::PopAndDestroy(2); |
|
84 return result; |
|
85 } |
|
86 |
|
87 TBool TEquiv::IsMatchUserInfoL() const |
|
88 { |
|
89 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo); |
|
90 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo); |
|
91 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); |
|
92 CleanupStack::PopAndDestroy(2); |
|
93 return result; |
|
94 } |
|
95 |
|
96 TBool TEquiv::IsMatchHostL() const |
|
97 { |
|
98 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); |
|
99 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); |
|
100 TBool result = IsMatchCaseless(*lhsDes, *rhsDes); |
|
101 CleanupStack::PopAndDestroy(2); |
|
102 return result; |
|
103 } |
|
104 |
|
105 TBool TEquiv::IsMatchPortL() const |
|
106 { |
|
107 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort); |
|
108 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort); |
|
109 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); |
|
110 CleanupStack::PopAndDestroy(2); |
|
111 return result; |
|
112 } |
|
113 |
|
114 TBool TEquiv::IsMatchPathL() const |
|
115 { |
|
116 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath); |
|
117 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath); |
|
118 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); |
|
119 CleanupStack::PopAndDestroy(2); |
|
120 return result; |
|
121 } |
|
122 |
|
123 TBool TEquiv::IsMatchQueryL() const |
|
124 { |
|
125 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery); |
|
126 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery); |
|
127 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); |
|
128 CleanupStack::PopAndDestroy(2); |
|
129 return result; |
|
130 } |
|
131 |
|
132 TBool TEquiv::IsMatchFragmentL() const |
|
133 { |
|
134 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment); |
|
135 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment); |
|
136 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); |
|
137 CleanupStack::PopAndDestroy(2); |
|
138 return result; |
|
139 } |
|
140 |
|
141 HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const |
|
142 { |
|
143 HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType)); |
|
144 CleanupStack::PushL(decoded); |
|
145 return decoded; |
|
146 } |
|
147 |
|
148 TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs) |
|
149 : TEquiv(aLhs, aRhs) |
|
150 { |
|
151 } |
|
152 |
|
153 void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const |
|
154 { |
|
155 for (TInt i=0; i < aHost.Length(); i++) |
|
156 { |
|
157 TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9'); |
|
158 if (aHost[i] == '0' && startOfNumber) |
|
159 { |
|
160 // The character is a zero and is either at the start of the string |
|
161 // or the fist number in a sequence. |
|
162 aHost.Delete(i--,1); |
|
163 } |
|
164 } |
|
165 } |
|
166 |
|
167 TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const |
|
168 { |
|
169 UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs); |
|
170 UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs); |
|
171 if (lhsType != rhsType) |
|
172 return EFalse; |
|
173 if (lhsType != UriUtils::ETextHost) |
|
174 { |
|
175 // Host is IPv4 or IPv6 |
|
176 // Create a copy of the hosts and remove any leading '0's |
|
177 HBufC8* lhsCopy = aLhs.AllocLC(); |
|
178 HBufC8* rhsCopy = aRhs.AllocLC(); |
|
179 RemoveLeadingZeros(lhsCopy->Des()); |
|
180 RemoveLeadingZeros(rhsCopy->Des()); |
|
181 TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy); |
|
182 CleanupStack::PopAndDestroy(2); |
|
183 return result; |
|
184 } |
|
185 |
|
186 return IsMatchCaseless(aLhs, aRhs); |
|
187 } |
|
188 |
|
189 TBool TEquivSip::IsMatchHostL() const |
|
190 { |
|
191 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); |
|
192 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); |
|
193 TBool result = IsMatchHostL(*lhsDes, *rhsDes); |
|
194 CleanupStack::PopAndDestroy(2); |
|
195 return result; |
|
196 } |
|
197 |
|
198 TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const |
|
199 { |
|
200 // Were're just checking that if the segments have the same name part |
|
201 // that their values are the same. This method only returns false if the lhs and rhs |
|
202 // have the same name but their values are different. |
|
203 if (!IsMatchCaseless(aLhsName, aRhsName)) |
|
204 { |
|
205 // Names don't match so we're OK |
|
206 return ETrue; |
|
207 } |
|
208 |
|
209 // The maddr parameter needs to be handled differently from the others |
|
210 // The address is checked for equivalence not just a straight string compare. |
|
211 if (IsMatchCaseless(aLhsName, KParamMaddr)) |
|
212 { |
|
213 return IsMatchHostL(aLhsValue, aRhsValue); |
|
214 } |
|
215 else |
|
216 { |
|
217 if (!IsMatchCaseless(aLhsValue, aRhsValue)) |
|
218 { |
|
219 // Names are the same but the values are different |
|
220 // We have a incompatible parameter |
|
221 return EFalse; |
|
222 } |
|
223 } |
|
224 |
|
225 return ETrue; |
|
226 } |
|
227 |
|
228 TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const |
|
229 |
|
230 { |
|
231 TPtrC8 lhsName; |
|
232 TPtrC8 lhsValue; |
|
233 TPtrC8 rhsName; |
|
234 TPtrC8 rhsValue; |
|
235 |
|
236 TPtrC8 lhsSegment; |
|
237 TPtrC8 rhsSegment; |
|
238 |
|
239 // roll back to the start of the lhs segment parser |
|
240 aLhsParser.Reset(); |
|
241 |
|
242 while( aLhsParser.GetNext(lhsSegment) == KErrNone ) |
|
243 { |
|
244 // roll back to the start of the rhs segment parser |
|
245 aRhsParser.Reset(); |
|
246 |
|
247 GetNameValuePair(lhsSegment, lhsName, lhsValue); |
|
248 while( aRhsParser.GetNext(rhsSegment) == KErrNone ) |
|
249 { |
|
250 GetNameValuePair(rhsSegment, rhsName, rhsValue); |
|
251 if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue)) |
|
252 return EFalse; |
|
253 } |
|
254 } |
|
255 |
|
256 return ETrue; |
|
257 } |
|
258 |
|
259 TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const |
|
260 { |
|
261 aParser.Reset(); |
|
262 |
|
263 TInt result = 0; |
|
264 while (!aParser.Eos()) |
|
265 { |
|
266 aParser.Inc(); |
|
267 ++result; |
|
268 } |
|
269 |
|
270 aParser.Reset(); |
|
271 return result; |
|
272 } |
|
273 |
|
274 TBool TEquivSip::IsMatchPathL() const |
|
275 { |
|
276 HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath); |
|
277 HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath); |
|
278 |
|
279 TDelimitedPathSegmentParser8 lhsParser; |
|
280 lhsParser.Parse(*lhs); |
|
281 TDelimitedPathSegmentParser8 rhsParser; |
|
282 rhsParser.Parse(*rhs); |
|
283 |
|
284 // Check each parameter in the lhs parameter list with those in |
|
285 // the rhs parameter list. If at any point a parameter is incompatible |
|
286 // we'll return false. |
|
287 TBool result = ETrue; |
|
288 |
|
289 // Alway check the parameter list with the most parameters against the other |
|
290 // so that we don't miss any |
|
291 TInt lhsLength = ListLength(lhsParser); |
|
292 TInt rhsLength = ListLength(rhsParser); |
|
293 |
|
294 if (lhsLength > rhsLength) |
|
295 { |
|
296 result = IsParamListCompatibleL(lhsParser, rhsParser); |
|
297 } |
|
298 else |
|
299 { |
|
300 result = IsParamListCompatibleL(rhsParser, lhsParser); |
|
301 } |
|
302 |
|
303 // check that the special parameters, if present, are present in both |
|
304 if (result) |
|
305 { |
|
306 if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) || |
|
307 (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) || |
|
308 (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) || |
|
309 (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) ) |
|
310 { |
|
311 result = EFalse; |
|
312 } |
|
313 } |
|
314 |
|
315 CleanupStack::PopAndDestroy(2); |
|
316 return result; |
|
317 } |
|
318 |
|
319 |
|
320 TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const |
|
321 { |
|
322 if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr)) |
|
323 return EHeaderId; |
|
324 if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr)) |
|
325 return EHeaderContact; |
|
326 if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr)) |
|
327 return EHeaderEncoding; |
|
328 if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr)) |
|
329 return EHeaderLength; |
|
330 if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr)) |
|
331 return EHeaderType; |
|
332 if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr)) |
|
333 return EHeaderFrom; |
|
334 if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr)) |
|
335 return EHeaderSubject; |
|
336 if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr)) |
|
337 return EHeaderTo; |
|
338 |
|
339 return EHeaderNormal; |
|
340 } |
|
341 |
|
342 TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const |
|
343 { |
|
344 if (IsMatchCaseless(aLhs, aRhs)) |
|
345 { |
|
346 // identical headers are always OK |
|
347 return ETrue; |
|
348 } |
|
349 |
|
350 // We now need to check for abbreviated headers |
|
351 TPtrC8 lhsName; |
|
352 TPtrC8 lhsValue; |
|
353 TPtrC8 rhsName; |
|
354 TPtrC8 rhsValue; |
|
355 |
|
356 GetNameValuePair(aLhs, lhsName, lhsValue); |
|
357 GetNameValuePair(aRhs, rhsName, rhsValue); |
|
358 |
|
359 if (!IsMatchCaseless(lhsValue, rhsValue)) |
|
360 { |
|
361 // headers with different values can never match |
|
362 return EFalse; |
|
363 } |
|
364 |
|
365 // We now have only those with different header names but with the same value |
|
366 // The last check is to see if the headers are in abbreviated forms |
|
367 THeaderType lhsType = HeaderType(lhsName); |
|
368 THeaderType rhsType = HeaderType(rhsName); |
|
369 if (lhsType != EHeaderNormal && (lhsType == rhsType)) |
|
370 { |
|
371 // They are both special headers of the same type |
|
372 // Everything matches |
|
373 return ETrue; |
|
374 } |
|
375 |
|
376 return EFalse; |
|
377 } |
|
378 |
|
379 TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const |
|
380 |
|
381 { |
|
382 TPtrC8 lhsSegment; |
|
383 TPtrC8 rhsSegment; |
|
384 |
|
385 TBool found = EFalse; |
|
386 // roll back to the start of the lhs segment parser |
|
387 aLhsParser.Reset(); |
|
388 |
|
389 while( aLhsParser.GetNext(lhsSegment) == KErrNone ) |
|
390 { |
|
391 // roll back to the start of the rhs segment parser |
|
392 aRhsParser.Reset(); |
|
393 |
|
394 found = EFalse; |
|
395 |
|
396 while( aRhsParser.GetNext(rhsSegment) == KErrNone ) |
|
397 { |
|
398 if (IsMatchHeader(lhsSegment, rhsSegment)) |
|
399 { |
|
400 // a match has been found for this header so move to the next |
|
401 // header in the lhs list |
|
402 found = ETrue; |
|
403 break; |
|
404 } |
|
405 } |
|
406 if (!found) |
|
407 { |
|
408 // no match has been found so the headers are not equvalent |
|
409 return EFalse; |
|
410 } |
|
411 } |
|
412 |
|
413 return ETrue; |
|
414 } |
|
415 |
|
416 TBool TEquivSip::IsMatchQueryL() const |
|
417 { |
|
418 HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery); |
|
419 HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery); |
|
420 |
|
421 TDelimitedQueryParser8 lhsParser; |
|
422 lhsParser.Parse(*lhs); |
|
423 TDelimitedQueryParser8 rhsParser; |
|
424 rhsParser.Parse(*rhs); |
|
425 |
|
426 TBool result = EFalse; |
|
427 |
|
428 // first check that the number of headers are the same in both lists. |
|
429 TInt lhsLength = ListLength(lhsParser); |
|
430 TInt rhsLength = ListLength(rhsParser); |
|
431 if (lhsLength == rhsLength) |
|
432 { |
|
433 // Check each parameter in the lhs parameter list with those in |
|
434 // the rhs parameter list. If at any point a parameter is incompatible |
|
435 // we'll return false. |
|
436 result = IsQueryListCompatible(lhsParser, rhsParser); |
|
437 } |
|
438 |
|
439 CleanupStack::PopAndDestroy(2); |
|
440 return result; |
|
441 } |
|
442 |
|
443 TBool TEquivSip::IsMatchFragmentL() const |
|
444 { |
|
445 // We don't care about the fragment for SIP URIs |
|
446 return ETrue; |
|
447 } |