|
1 // Copyright (c) 2005-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 // Name : CSIPClientDataParser.cpp |
|
15 // Part of : SIP Client Resolver |
|
16 // Version : 1.0 |
|
17 // |
|
18 |
|
19 |
|
20 |
|
21 #include "CSIPClientDataParser.h" |
|
22 #include "CSIPClientData.h" |
|
23 #include "SIPHeaderLookup.h" |
|
24 #include "sipacceptcontactheader.h" |
|
25 #include "CSIPFeatureSet.h" |
|
26 #include "sdpdocument.h" |
|
27 #include "sdpmediafield.h" |
|
28 #include "sdpfmtattributefield.h" |
|
29 #include "sdpattributefield.h" |
|
30 #include "sipstrings.h" |
|
31 #include "sipstrconsts.h" |
|
32 |
|
33 |
|
34 // Constants for our XML DTD |
|
35 _LIT8( KTagSIPClient, "SIP_CLIENT" ); |
|
36 _LIT8( KTagSIPHeaders, "SIP_HEADERS" ); |
|
37 _LIT8( KTagSDPLines, "SDP_LINES" ); |
|
38 _LIT8( KTagLine, "LINE" ); |
|
39 _LIT8( KTagLineM, "m" ); |
|
40 _LIT8( KTagRtpmap, "RTPMAP" ); |
|
41 _LIT8( KTagMediaAttribute, "MEDIA_ATTRIBUTE" ); |
|
42 _LIT8( KTagAccept, "ACCEPT" ); |
|
43 _LIT8( KTagAllowStarting, "ALLOW_STARTING" ); |
|
44 _LIT8( KTagAcceptContact, "ACCEPT_CONTACT" ); |
|
45 _LIT8( KTagAllowEvents, "ALLOW_EVENTS" ); |
|
46 _LIT8( KTagYes, "YES" ); |
|
47 |
|
48 _LIT8( KMimeTypeXml, "text/xml" ); |
|
49 _LIT8( KSdpMediaFieldStart, "m=" ); |
|
50 _LIT8( KSdpAttributeFieldStart, "a=" ); |
|
51 _LIT8( KRtpmapName, "rtpmap" ); |
|
52 _LIT8( KCrLf, "\r\n" ); |
|
53 |
|
54 const TInt KSdpLineAttrCount( 2 ); |
|
55 |
|
56 // ----------------------------------------------------------------------------- |
|
57 // CSIPClientDataParser::NewL |
|
58 // ----------------------------------------------------------------------------- |
|
59 // |
|
60 CSIPClientDataParser* CSIPClientDataParser::NewL() |
|
61 { |
|
62 CSIPClientDataParser* self = new( ELeave ) CSIPClientDataParser; |
|
63 CleanupStack::PushL( self ); |
|
64 self->ConstructL(); |
|
65 CleanupStack::Pop( self ); |
|
66 return self; |
|
67 } |
|
68 |
|
69 // ----------------------------------------------------------------------------- |
|
70 // CSIPClientDataParser::CSIPClientDataParser |
|
71 // ----------------------------------------------------------------------------- |
|
72 // |
|
73 CSIPClientDataParser::CSIPClientDataParser() |
|
74 : iSIPHeaderLookupOpened (EFalse) |
|
75 { |
|
76 } |
|
77 |
|
78 // ----------------------------------------------------------------------------- |
|
79 // CSIPClientDataParser::ConstructL |
|
80 // ----------------------------------------------------------------------------- |
|
81 // |
|
82 void CSIPClientDataParser::ConstructL() |
|
83 { |
|
84 iParser = Xml::CParser::NewL( KMimeTypeXml, *this ); |
|
85 SIPHeaderLookup::OpenL(); |
|
86 iSIPHeaderLookupOpened = ETrue; |
|
87 |
|
88 // Initialize XML strings |
|
89 RStringPool& stringPool = iParser->StringPool(); |
|
90 iTagSIPClient = stringPool.OpenStringL(KTagSIPClient); |
|
91 iTagSIPHeaders = stringPool.OpenStringL(KTagSIPHeaders); |
|
92 iTagSDPLines = stringPool.OpenStringL(KTagSDPLines); |
|
93 iTagLine = stringPool.OpenStringL(KTagLine); |
|
94 iTagLineM = stringPool.OpenStringL(KTagLineM); |
|
95 iTagRtpmap = stringPool.OpenStringL(KTagRtpmap); |
|
96 iTagMediaAttribute = stringPool.OpenStringL(KTagMediaAttribute); |
|
97 iTagAccept = stringPool.OpenStringL(KTagAccept); |
|
98 iTagAllowStarting = stringPool.OpenStringL(KTagAllowStarting); |
|
99 iTagAcceptContact = stringPool.OpenStringL(KTagAcceptContact); |
|
100 iTagAllowEvents = stringPool.OpenStringL(KTagAllowEvents); |
|
101 iTagYes = stringPool.OpenStringL(KTagYes); |
|
102 |
|
103 // Initialize parser states |
|
104 iStateTransitions.AppendL( |
|
105 TStateTransition(iTagSIPClient,EInit,ESIPClient)); |
|
106 |
|
107 iStateTransitions.AppendL( |
|
108 TStateTransition(iTagSIPClient,ESIPClient,EInit,EFalse)); |
|
109 |
|
110 iStateTransitions.AppendL( |
|
111 TStateTransition(iTagSIPHeaders,ESIPClient,ESIPHeaders)); |
|
112 |
|
113 iStateTransitions.AppendL( |
|
114 TStateTransition(iTagSIPHeaders,ESIPHeaders,ESIPClient,EFalse)); |
|
115 |
|
116 iStateTransitions.AppendL( |
|
117 TStateTransition(iTagAccept,ESIPHeaders,EAccept)); |
|
118 |
|
119 iStateTransitions.AppendL( |
|
120 TStateTransition(iTagAccept,EAccept,ESIPHeaders,EFalse)); |
|
121 |
|
122 iStateTransitions.AppendL( |
|
123 TStateTransition(iTagAcceptContact,ESIPHeaders,EAcceptContact)); |
|
124 |
|
125 iStateTransitions.AppendL( |
|
126 TStateTransition(iTagAcceptContact,EAcceptContact,ESIPHeaders,EFalse)); |
|
127 |
|
128 iStateTransitions.AppendL( |
|
129 TStateTransition(iTagAllowEvents,ESIPHeaders,EAllowEvents)); |
|
130 |
|
131 iStateTransitions.AppendL( |
|
132 TStateTransition(iTagAllowEvents,EAllowEvents,ESIPHeaders,EFalse)); |
|
133 |
|
134 iStateTransitions.AppendL( |
|
135 TStateTransition(iTagSDPLines,ESIPClient,ESDPLines)); |
|
136 |
|
137 iStateTransitions.AppendL( |
|
138 TStateTransition(iTagSDPLines,ESDPLines,ESIPClient,EFalse)); |
|
139 |
|
140 iStateTransitions.AppendL( |
|
141 TStateTransition(iTagLine,ESDPLines,ELine)); |
|
142 |
|
143 iStateTransitions.AppendL( |
|
144 TStateTransition(iTagLine,ELine,ESDPLines,EFalse)); |
|
145 |
|
146 iStateTransitions.AppendL( |
|
147 TStateTransition(iTagRtpmap,ELine,ERtpmap)); |
|
148 |
|
149 iStateTransitions.AppendL( |
|
150 TStateTransition(iTagRtpmap,ERtpmap,ELine,EFalse)); |
|
151 |
|
152 iStateTransitions.AppendL( |
|
153 TStateTransition(iTagMediaAttribute,ELine,EMediaAttribute)); |
|
154 |
|
155 iStateTransitions.AppendL( |
|
156 TStateTransition(iTagMediaAttribute,EMediaAttribute,ELine,EFalse)); |
|
157 } |
|
158 |
|
159 // ----------------------------------------------------------------------------- |
|
160 // CSIPClientDataParser::~CSIPClientDataParser |
|
161 // ----------------------------------------------------------------------------- |
|
162 // |
|
163 CSIPClientDataParser::~CSIPClientDataParser() |
|
164 { |
|
165 iStateTransitions.Close(); |
|
166 iTagYes.Close(); |
|
167 iTagAllowEvents.Close(); |
|
168 iTagAcceptContact.Close(); |
|
169 iTagAllowStarting.Close(); |
|
170 iTagAccept.Close(); |
|
171 iTagMediaAttribute.Close(); |
|
172 iTagLineM.Close(); |
|
173 iTagRtpmap.Close(); |
|
174 iTagLine.Close(); |
|
175 iTagSDPLines.Close(); |
|
176 iTagSIPHeaders.Close(); |
|
177 iTagSIPClient.Close(); |
|
178 if( iSIPHeaderLookupOpened ) |
|
179 { |
|
180 SIPHeaderLookup::Close(); |
|
181 } |
|
182 delete iParser; |
|
183 } |
|
184 |
|
185 // ----------------------------------------------------------------------------- |
|
186 // CSIPClientDataParser::ParseL |
|
187 // ----------------------------------------------------------------------------- |
|
188 // |
|
189 void CSIPClientDataParser::ParseL ( CSIPClientData* aClientData, |
|
190 const TDesC8& aXmlDocument ) |
|
191 { |
|
192 iState = EInit; |
|
193 iClientData = aClientData; |
|
194 |
|
195 // Parse the specified document into iClientData |
|
196 Xml::ParseL( *iParser, aXmlDocument ); |
|
197 |
|
198 iClientData = NULL; |
|
199 } |
|
200 |
|
201 // ----------------------------------------------------------------------------- |
|
202 // CSIPClientDataParser::OnStartElementL |
|
203 // ----------------------------------------------------------------------------- |
|
204 // |
|
205 void CSIPClientDataParser::OnStartElementL( |
|
206 const Xml::RTagInfo& aElement, |
|
207 const Xml::RAttributeArray& aAttributes, |
|
208 TInt /*aErrorCode*/ ) |
|
209 { |
|
210 // Get element name (e.g. "SIP_CLIENT") and change state (Enter) |
|
211 ChangeStateL( aElement.LocalName(), ETrue ); |
|
212 |
|
213 switch( iState ) |
|
214 { |
|
215 case ESIPClient: |
|
216 { |
|
217 HandleSIPClientL( aAttributes ); |
|
218 break; |
|
219 } |
|
220 case EAccept: |
|
221 { |
|
222 HandleSIPHeaderL( |
|
223 SIPStrings::StringF(SipStrConsts::EAcceptHeader), |
|
224 aAttributes ); |
|
225 break; |
|
226 } |
|
227 case EAcceptContact: |
|
228 { |
|
229 HandleSIPHeaderL( |
|
230 SIPStrings::StringF(SipStrConsts::EAcceptContactHeader), |
|
231 aAttributes ); |
|
232 break; |
|
233 } |
|
234 case EAllowEvents: |
|
235 { |
|
236 HandleSIPHeaderL( |
|
237 SIPStrings::StringF(SipStrConsts::EAllowEventsHeader), |
|
238 aAttributes ); |
|
239 break; |
|
240 } |
|
241 case ELine: |
|
242 { |
|
243 HandleSdpLineL( aAttributes ); |
|
244 break; |
|
245 } |
|
246 case ERtpmap: |
|
247 { |
|
248 HandleRtpmapL( aAttributes ); |
|
249 break; |
|
250 } |
|
251 case EMediaAttribute: |
|
252 { |
|
253 HandleMediaAttributeL( aAttributes ); |
|
254 break; |
|
255 } |
|
256 default: |
|
257 { |
|
258 // do nothing; |
|
259 break; |
|
260 } |
|
261 } |
|
262 } |
|
263 |
|
264 // ----------------------------------------------------------------------------- |
|
265 // CSIPClientDataParser::OnEndElementL |
|
266 // ----------------------------------------------------------------------------- |
|
267 // |
|
268 void CSIPClientDataParser::OnEndElementL( |
|
269 const Xml::RTagInfo& aElement, |
|
270 TInt /*aErrorCode*/ ) |
|
271 { |
|
272 // Get element name (e.g. "SIP_CLIENT") and change state (Exit) |
|
273 ChangeStateL( aElement.LocalName(), EFalse ); |
|
274 } |
|
275 |
|
276 // ----------------------------------------------------------------------------- |
|
277 // CSIPClientDataParser::ChangeStateL |
|
278 // ----------------------------------------------------------------------------- |
|
279 // |
|
280 void CSIPClientDataParser::ChangeStateL( const RString& aElementName, |
|
281 TBool aEnter ) |
|
282 { |
|
283 // Try to find a matching entry from the transitions table |
|
284 TInt count = iStateTransitions.Count(); |
|
285 for( TInt i = 0; i < count; i++ ) |
|
286 { |
|
287 const TStateTransition& transition = iStateTransitions[ i ]; |
|
288 if( ( iState == transition.iState ) && |
|
289 ( aElementName == transition.iTag ) && |
|
290 ( aEnter == transition.iEnter ) ) |
|
291 { |
|
292 // Match found, do transition |
|
293 iState = transition.iNextState; |
|
294 return; |
|
295 } |
|
296 } |
|
297 |
|
298 // No match was found, report error |
|
299 User::Leave( KErrCorrupt ); |
|
300 } |
|
301 |
|
302 // ----------------------------------------------------------------------------- |
|
303 // CSIPClientDataParser::HandleSIPClientL |
|
304 // ----------------------------------------------------------------------------- |
|
305 // |
|
306 void CSIPClientDataParser::HandleSIPClientL( |
|
307 const Xml::RAttributeArray& aAttributes ) |
|
308 { |
|
309 // Verify that we have correct number of attributes |
|
310 __ASSERT_ALWAYS( aAttributes.Count() == 1, User::Leave( KErrCorrupt ) ); |
|
311 |
|
312 // Verify that we have the correct attributes |
|
313 const RString& allowName = aAttributes[ 0 ].Attribute().LocalName(); |
|
314 const RString& allowValue = aAttributes[ 0 ].Value(); |
|
315 if( allowName != iTagAllowStarting ) |
|
316 { |
|
317 User::Leave( KErrCorrupt ); |
|
318 } |
|
319 iClientData->SetAllowStarting( ( allowValue == iTagYes ) ); |
|
320 } |
|
321 |
|
322 // ----------------------------------------------------------------------------- |
|
323 // CSIPClientDataParser::HandleSIPHeaderL |
|
324 // ----------------------------------------------------------------------------- |
|
325 // |
|
326 void CSIPClientDataParser::HandleSIPHeaderL( |
|
327 RStringF aHeaderName, |
|
328 const Xml::RAttributeArray& aAttributes ) |
|
329 { |
|
330 // Verify that we have correct number of attributes |
|
331 if( aAttributes.Count() != 1 ) |
|
332 { |
|
333 User::Leave( KErrCorrupt ); |
|
334 } |
|
335 |
|
336 // Read header value |
|
337 const RString& value = aAttributes[ 0 ].Value(); |
|
338 |
|
339 // Create SIP header object |
|
340 RPointerArray< CSIPHeaderBase > headers = |
|
341 SIPHeaderLookup::CreateHeaderL( aHeaderName, value.DesC() ); |
|
342 // Add created headers to ClientData |
|
343 CSIPHeaderBase::PushLC( &headers ); |
|
344 while( headers.Count() > 0 ) |
|
345 { |
|
346 CSIPHeaderBase* header = headers[ 0 ]; |
|
347 if ( header->Name() == |
|
348 SIPStrings::StringF(SipStrConsts::EAcceptContactHeader) ) |
|
349 { |
|
350 CSIPAcceptContactHeader* acceptContact = |
|
351 static_cast< CSIPAcceptContactHeader* >( header ); |
|
352 iClientData->SIPFeatureSet().AddFeaturesL( *acceptContact ); |
|
353 delete header; |
|
354 } |
|
355 else |
|
356 { |
|
357 iClientData->SIPHeaders().AppendL( header ); |
|
358 } |
|
359 headers.Remove( 0 ); |
|
360 } |
|
361 CleanupStack::PopAndDestroy(); // headers |
|
362 } |
|
363 |
|
364 // ----------------------------------------------------------------------------- |
|
365 // CSIPClientDataParser::HandleSdpLineL |
|
366 // ----------------------------------------------------------------------------- |
|
367 // |
|
368 void CSIPClientDataParser::HandleSdpLineL( |
|
369 const Xml::RAttributeArray& aAttributes ) |
|
370 { |
|
371 // Verify that we have correct number of attributes |
|
372 if( aAttributes.Count() != KSdpLineAttrCount ) |
|
373 { |
|
374 User::Leave( KErrCorrupt ); |
|
375 } |
|
376 |
|
377 // Verify that we have the correct attribute(s) |
|
378 if( aAttributes[ 0 ].Value() != iTagLineM ) |
|
379 { |
|
380 User::Leave( KErrCorrupt ); |
|
381 } |
|
382 |
|
383 // Get attribute and convert to a form compatible with CSdpMediaField |
|
384 // (basically just surround the string with "m=" and "\r\n") |
|
385 TPtrC8 value( aAttributes[ 1 ].Value().DesC() ); |
|
386 HBufC8* mediaFieldBuf = CreateSdpFieldBufLC( KSdpMediaFieldStart, value ); |
|
387 |
|
388 // Read and decode SDP media field to ClientData |
|
389 CSdpMediaField* mediaField = CSdpMediaField::DecodeLC( *mediaFieldBuf ); |
|
390 iClientData->AddMediaFieldL( mediaField ); |
|
391 CleanupStack::Pop( mediaField ); |
|
392 |
|
393 CleanupStack::PopAndDestroy( mediaFieldBuf ); |
|
394 } |
|
395 |
|
396 // ----------------------------------------------------------------------------- |
|
397 // CSIPClientDataParser::HandleRtpmapL |
|
398 // ----------------------------------------------------------------------------- |
|
399 // |
|
400 void CSIPClientDataParser::HandleRtpmapL( |
|
401 const Xml::RAttributeArray& aAttributes ) |
|
402 { |
|
403 CSdpDocument& sdp = iClientData->SdpDocument(); |
|
404 if( aAttributes.Count() != 1 || sdp.MediaFields().Count() == 0 ) |
|
405 { |
|
406 User::Leave( KErrCorrupt ); |
|
407 } |
|
408 |
|
409 // Get attribute and convert to a form compatible |
|
410 // with CSdpfmtAttributeField |
|
411 // (basically just surround the string with "a=" and "\r\n") |
|
412 TPtrC8 value( aAttributes[ 0 ].Value().DesC() ); |
|
413 HBufC8* fieldBuf = CreateSdpFieldBufLC( KSdpAttributeFieldStart, value ); |
|
414 |
|
415 // Decode and add rtpmap attribute field |
|
416 CSdpFmtAttributeField* attributeField = |
|
417 CSdpFmtAttributeField::DecodeL( *fieldBuf ); |
|
418 CleanupStack::PopAndDestroy( fieldBuf ); |
|
419 CleanupStack::PushL( attributeField ); |
|
420 |
|
421 if( attributeField->Attribute().DesC().Compare( KRtpmapName ) != 0 ) |
|
422 { |
|
423 User::Leave( KErrCorrupt ); |
|
424 } |
|
425 |
|
426 // Add the rtpmap-attribute to the last added media field |
|
427 const TInt lastIndex = sdp.MediaFields().Count()-1; |
|
428 CSdpMediaField* lastMediaField = sdp.MediaFields()[ lastIndex ]; |
|
429 lastMediaField->FormatAttributeFields().AppendL( attributeField ); |
|
430 |
|
431 CleanupStack::Pop( attributeField ); |
|
432 } |
|
433 |
|
434 // ----------------------------------------------------------------------------- |
|
435 // CSIPClientDataParser::HandleMediaAttributeL |
|
436 // ----------------------------------------------------------------------------- |
|
437 // |
|
438 void CSIPClientDataParser::HandleMediaAttributeL( |
|
439 const Xml::RAttributeArray& aAttributes ) |
|
440 { |
|
441 CSdpDocument& sdp = iClientData->SdpDocument(); |
|
442 if( aAttributes.Count() != 1 || sdp.MediaFields().Count() == 0 ) |
|
443 { |
|
444 User::Leave( KErrCorrupt ); |
|
445 } |
|
446 |
|
447 // Get attribute and convert to a form compatible with CSdpAttributeField |
|
448 // (basically just surround the string with "a=" and "\r\n") |
|
449 TPtrC8 value( aAttributes[ 0 ].Value().DesC() ); |
|
450 HBufC8* fieldBuf = CreateSdpFieldBufLC( KSdpAttributeFieldStart, value ); |
|
451 |
|
452 // Decode and add attribute field |
|
453 CSdpAttributeField* attributeField = |
|
454 CSdpAttributeField::DecodeL( *fieldBuf ); |
|
455 CleanupStack::PopAndDestroy( fieldBuf ); |
|
456 CleanupStack::PushL( attributeField ); |
|
457 |
|
458 // Add the attribute to the last added media field |
|
459 const TInt lastIndex = sdp.MediaFields().Count()-1; |
|
460 CSdpMediaField* lastMediaField = sdp.MediaFields()[ lastIndex ]; |
|
461 lastMediaField->AttributeFields().AppendL( attributeField ); |
|
462 |
|
463 CleanupStack::Pop( attributeField ); |
|
464 } |
|
465 |
|
466 // ----------------------------------------------------------------------------- |
|
467 // CSIPClientDataParser::CreateSdpFieldBufLC |
|
468 // ----------------------------------------------------------------------------- |
|
469 // |
|
470 HBufC8* CSIPClientDataParser::CreateSdpFieldBufLC( |
|
471 const TDesC8& aFieldStart, |
|
472 const TDesC8& aValue ) |
|
473 { |
|
474 TInt bufLength = aFieldStart.Length() + aValue.Length() + KCrLf().Length(); |
|
475 HBufC8* buf = HBufC8::NewLC( bufLength ); |
|
476 TPtr8 bufPtr = buf->Des(); |
|
477 bufPtr.Copy( aFieldStart ); |
|
478 bufPtr.Append( aValue ); |
|
479 bufPtr.Append( KCrLf ); |
|
480 return buf; |
|
481 } |