reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
DialogInfoContents.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <time.h>
6#include <iomanip>
7
11#include "rutil/XMLCursor.hxx"
12#include "rutil/Logger.hxx"
13#include "rutil/Inserter.hxx"
15
16using namespace resip;
17using namespace std;
18
19#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
20
21const static Data BaseDialogInfoNamespaceUri("urn:ietf:params:xml:ns:dialog-info");
22const static Data SharedAppearanceDialogInfoNamespaceUri("urn:ietf:params:xml:ns:sa-dialog-info");
24
25const static Data DefaultEncodeIndent(" ");
26
27bool
29{
31 (void)factory;
32 return true;
33}
34
35static const char* DialogInfoStateStrings[] =
36{
37 "full",
38 "partial"
39};
40
41const char*
43{
44 return DialogInfoStateStrings[dialogInfoState];
45}
46
49{
50 for (int i = 0; i < MaxDialogInfoState; i++)
51 {
52 if (isEqualNoCase(DialogInfoStateStrings[i], dialogInfoStateString))
53 {
54 return (DialogInfoState)i;
55 }
56 }
57 return MaxDialogInfoState;
58}
59
60static const char* DialogStateStrings[] =
61{
62 "trying",
63 "proceeding",
64 "early",
65 "confirmed",
66 "terminated"
67};
68
69const char*
71{
72 return DialogStateStrings[dialogState];
73}
74
77{
78 for (int i = 0; i < MaxDialogState; i++)
79 {
80 if (isEqualNoCase(DialogStateStrings[i], dialogStateString))
81 {
82 return (DialogState)i;
83 }
84 }
85 return MaxDialogState;
86}
87
88static const char* DialogStateEventStrings[] =
89{
90 "cancelled",
91 "rejected",
92 "replaced",
93 "local-bye",
94 "remote-bye",
95 "error",
96 "timeout"
97};
98
99const char*
101{
102 return DialogStateEventStrings[dialogStateEvent];
103}
104
107{
108 for (int i = 0; i < MaxOrUnsetDialogStateEvent; i++)
109 {
110 if (isEqualNoCase(DialogStateEventStrings[i], dialogStateEventString))
111 {
112 return (DialogStateEvent)i;
113 }
114 }
116}
117
118static const char* DirectionStrings[] =
119{
120 "initiator",
121 "recipient"
122};
123
124const char*
126{
127 return DirectionStrings[direction];
128}
129
132{
133 for (int i = 0; i < MaxOrUnsetDirection; i++)
134 {
135 if (isEqualNoCase(DirectionStrings[i], directionString))
136 {
137 return (Direction)i;
138 }
139 }
140 return MaxOrUnsetDirection;
141}
142
143bool
144DialogInfoContents::compareTag(const Data& tagName, const Data& compareToTagNoPrefix, const Data& namespacePrefix)
145{
146 if (namespacePrefix.empty())
147 {
148 return tagName == compareToTagNoPrefix;
149 }
150 Data compareToTagWithPrefix(namespacePrefix);
151 compareToTagWithPrefix += compareToTagNoPrefix;
152 return tagName == compareToTagWithPrefix;
153}
154
156
158 : Contents(getStaticType()), mIndent(DefaultEncodeIndent), mVersion(0), mDialogInfoState(Partial)
159{
160}
161
163 : Contents(getStaticType()), mIndent(DefaultEncodeIndent), mVersion(0), mDialogInfoState(Partial)
164{
165}
166
168 : Contents(hfv, contentsType), mIndent(DefaultEncodeIndent), mVersion(0), mDialogInfoState(Partial)
169{
170}
171
175
176Contents*
178{
179 return new DialogInfoContents(*this);
180}
181
182const Mime&
184{
185 static Mime type("application","dialog-info+xml");
186 return type;
187}
188
190DialogInfoContents::encodeParsed(EncodeStream& str) const
191{
192 bool hasSharedAppearanceElements = false;
193
194 // Check if any dialogs have shared appearance elements, if so, we need to add the namespace
195 for (DialogList::const_iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
196 {
197 if (it->hasExclusive() || it->hasAppearance() || !it->getReplacedDialogs().empty() || !it->getJoinedDialogs().empty())
198 {
199 hasSharedAppearanceElements = true;
200 break; // no need to continue, we found at least one
201 }
202 }
203
204 str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << Symbols::CRLF;
205 str << "<dialog-info xmlns=\"" << BaseDialogInfoNamespaceUri << "\"" << Symbols::CRLF;
206 if (hasSharedAppearanceElements)
207 {
209 }
210 str << " version=\"" << mVersion << "\" state=\"" << dialogInfoStateToString(mDialogInfoState) << "\"" << Symbols::CRLF;
211 str << " entity=\"" << Data::from(mEntity).xmlCharDataEncode() << "\">" << Symbols::CRLF;
212
213 for (DialogList::const_iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
214 {
215 it->encodeParsed(str, mIndent);
216 }
217
218 str << "</dialog-info>" << Symbols::CRLF;
219
220 return str;
221}
222
223bool
224DialogInfoContents::Dialog::getDialogElement(const Data& childElementName, Data& elementValue, int instance) const
225{
226 bool found = false;
227 elementValue = "";
228 std::pair <std::multimap<Data, Data>::const_iterator, std::multimap<Data, Data>::const_iterator> filteredList;
229 filteredList = mExtraDialogElements.equal_range(childElementName);
230 int matchCount = 0;
231 for (std::multimap<Data, Data>::const_iterator matchListIterator = filteredList.first; matchListIterator != filteredList.second; ++matchListIterator)
232 {
233 if(instance == matchCount)
234 {
235 elementValue = matchListIterator->second;
236 found = true;
237 break;
238 }
239 matchCount++;
240 }
241
242 return(found);
243}
244
246DialogInfoContents::Dialog::encodeParsed(EncodeStream& str, const Data& indent) const
247{
248 // Encode dialog attributes
249 str << indent << "<dialog id=\"" << mId.xmlCharDataEncode() << "\"";
250 if (!mCallId.empty())
251 {
252 str << " call-id=\"" << mCallId.xmlCharDataEncode() << "\"";
253 }
254 if (!mLocalTag.empty())
255 {
256 str << Symbols::CRLF << indent << " local-tag=\"" << mLocalTag.xmlCharDataEncode() << "\"";
257 }
258 if (!mRemoteTag.empty())
259 {
260 str << Symbols::CRLF << indent << " remote-tag=\"" << mRemoteTag.xmlCharDataEncode() << "\"";
261 }
262 if (mDirection != MaxOrUnsetDirection)
263 {
264 str << " direction=\"" << directionToString(mDirection) << "\"";
265 }
266 str << ">" << Symbols::CRLF;
267
268 // Encode state element
269 str << indent << indent << "<state";
270 if (mStateEvent != MaxOrUnsetDialogStateEvent)
271 {
272 str << " event=\"" << dialogStateEventToString(mStateEvent) << "\"";
273 }
274 if (mStateCode != 0)
275 {
276 str << " code=\"" << mStateCode << "\"";
277 }
278 str << ">" << dialogStateToString(mState) << "</state>" << Symbols::CRLF;
279
280 // Encode duration element
281 if (mHasDuration)
282 {
283 str << indent << indent << "<duration>" << mDuration << "</duration>" << Symbols::CRLF;
284 }
285
286 // Encode replaces element
287 if (!mReplaces.mCallId.empty())
288 {
289 str << indent << indent << "<replaces call-id=\"" << mReplaces.mCallId.xmlCharDataEncode() << "\"" << Symbols::CRLF;
290 str << indent << indent << " local-tag=\"" << mReplaces.mLocalTag.xmlCharDataEncode() << "\" remote-tag=\"" << mReplaces.mRemoteTag.xmlCharDataEncode() << "\"/>" << Symbols::CRLF;
291 }
292
293 // Encode referred by element
294 if (!mReferredBy.uri().host().empty())
295 {
296 str << indent << indent;
297 encodeNameAddrElement(str, "referred-by", mReferredBy);
298 str << Symbols::CRLF;
299 }
300
301 // Encode route set
302 if (!mRouteSet.empty())
303 {
304 str << indent << indent << "<route-set>" << Symbols::CRLF;
305 for (NameAddrs::const_iterator itNA = mRouteSet.begin(); itNA != mRouteSet.end(); itNA++)
306 {
307 str << indent << indent << indent << "<hop>" << Data::from(itNA->uri()).xmlCharDataEncode() << "</hop>" << Symbols::CRLF;
308 }
309 str << indent << indent << "</route-set>" << Symbols::CRLF;
310 }
311
312 // Encode local participant (if set)
313 mLocalParticipant.encode(str, "local", indent);
314
315 // Encode remote participant (if set)
316 mRemoteParticipant.encode(str, "remote", indent);
317
318
320 // Encode RFC7463 Specific Elements
322
323 // Encode shared appearance number
324 if (mHasAppearance)
325 {
326 str << indent << indent << "<" << SharedAppearanceDialogInfoNamespacePrefix << "appearance>" << mAppearance << "</" << SharedAppearanceDialogInfoNamespacePrefix << "appearance>" << Symbols::CRLF;
327 }
328
329 // Encode exclusive flag
330 if (mHasExclusive)
331 {
332 str << indent << indent << "<" << SharedAppearanceDialogInfoNamespacePrefix << "exclusive>" << (mExclusive ? "true" : "false") << "</" << SharedAppearanceDialogInfoNamespacePrefix << "exclusive>" << Symbols::CRLF;
333 }
334
335 // Encode replaced-dialog's
336 for (auto replacedDialogsIterator = mReplacedDialogs.begin(); replacedDialogsIterator != mReplacedDialogs.end(); replacedDialogsIterator++)
337 {
338 str << indent << indent << "<" << SharedAppearanceDialogInfoNamespacePrefix << "replaced-dialog" << Symbols::CRLF
339 << indent << indent << indent << "call-id=\"" << replacedDialogsIterator->mCallId.xmlCharDataEncode() << "\"" << Symbols::CRLF
340 << indent << indent << indent << "local-tag=\"" << replacedDialogsIterator->mLocalTag.xmlCharDataEncode() << "\"" << Symbols::CRLF
341 << indent << indent << indent << "remote-tag=\"" << replacedDialogsIterator->mRemoteTag.xmlCharDataEncode() << "\"/>" << Symbols::CRLF;
342 }
343
344 // Encode joined-dialog's
345 for (auto joinedDialogsIterator = mJoinedDialogs.begin(); joinedDialogsIterator != mJoinedDialogs.end(); joinedDialogsIterator++)
346 {
347 str << indent << indent << "<" << SharedAppearanceDialogInfoNamespacePrefix << "joined-dialog" << Symbols::CRLF
348 << indent << indent << indent << "call-id=\"" << joinedDialogsIterator->mCallId.xmlCharDataEncode() << "\"" << Symbols::CRLF
349 << indent << indent << indent << "local-tag=\"" << joinedDialogsIterator->mLocalTag.xmlCharDataEncode() << "\"" << Symbols::CRLF
350 << indent << indent << indent << "remote-tag=\"" << joinedDialogsIterator->mRemoteTag.xmlCharDataEncode() << "\"/>" << Symbols::CRLF;
351 }
352
353
354 // User specific/non-standard Dialog elements
355 for(std::multimap<Data, Data>::const_iterator elementIterator = mExtraDialogElements.begin();
356 elementIterator != mExtraDialogElements.end();
357 elementIterator++)
358 {
359 DebugLog(<< "Dialog child element Name: \"" << elementIterator->first << "\" Value: \"" << elementIterator->second << "\"");
360 str << indent << indent << '<' << elementIterator->first << '>'
361 << elementIterator->second.xmlCharDataEncode()
362 << "</" << elementIterator->first << '>' << Symbols::CRLF;
363 }
364
365 str << indent << "</dialog>" << Symbols::CRLF;
366
367 return str;
368}
369
371DialogInfoContents::encodeNameAddrElement(EncodeStream& str, const char* elementName, const NameAddr& nameAddr)
372{
373 str << "<" << elementName;
374 if (!nameAddr.displayName().empty())
375 {
376 str << " display=\"" << nameAddr.displayName().xmlCharDataEncode() << "\"";
377 }
378 str << ">" << Data::from(nameAddr.uri()).xmlCharDataEncode() << "</" << elementName << ">";
379 return str;
380}
381
382void
384{
385 mTarget = targetWithContactParams.uri();
386 Data paramsData;
387 { // scope so that stream flushs
388 DataStream dstr(paramsData);
389 targetWithContactParams.encodeParameters(dstr);
390 }
391 // If there are parameters present - parse them
392 if (!paramsData.empty())
393 {
394 ParseBuffer pb(paramsData);
395 pb.skipChar(); // Skip first ; that is always present
396 pb.skipWhitespace();
397
398 do
399 {
400 const char* anchor = pb.position();
401 pb.skipToOneOf("=;");
402 if (*pb.position() == '=')
403 {
404 Data name;
405 Data value;
406 pb.data(name, anchor);
407 pb.skipChar();
408 pb.skipWhitespace();
409 if (*pb.position() == '"')
410 {
411 // Quoted Value
412 pb.skipChar();
413 anchor = pb.position();
414 pb.skipToChar('"');
415 value = pb.data(anchor);
416 pb.skipChar();
417 pb.skipToChar(';');
418 }
419 else
420 {
421 // Unquoted value
422 anchor = pb.position();
423 pb.skipToChar(';');
424 value = pb.data(anchor);
425 }
426 mTargetParams[name] = value;
427 }
428 else // ';' or eof
429 {
430 // No equals operator - this is a boolean param
431 mTargetParams[pb.data(anchor)] = "true";
432 pb.skipToChar(';');
433 }
434 if (!pb.eof())
435 {
436 // Skip ;
437 pb.skipChar();
438 }
439 } while (!pb.eof());
440 }
441}
442
443bool
445{
446 TargetParams::const_iterator it = mTargetParams.find(name);
447 if (it != mTargetParams.end())
448 {
449 value = it->second;
450 return true;
451 }
452 return false;
453}
454
456DialogInfoContents::Dialog::Participant::encode(EncodeStream& str, const char* baseElementName, const Data& indent) const
457{
458 // Only encode if any of the optional sub elements are actually set
459 if (!mIdentity.uri().host().empty() || !mTarget.host().empty() || !mSessionDescription.empty() || mHasCSeq)
460 {
461 str << indent << indent << "<" << baseElementName << ">" << Symbols::CRLF;
462 if (!mIdentity.uri().host().empty())
463 {
464 str << indent << indent << indent;
465 encodeNameAddrElement(str, "identity", mIdentity);
466 str << Symbols::CRLF;
467 }
468 if (!mTarget.host().empty())
469 {
470 str << indent << indent << indent << "<target uri=\"" << Data::from(mTarget).xmlCharDataEncode() << "\"";
471 if (mTargetParams.empty())
472 {
473 // no params - just close tag
474 str << "/>" << Symbols::CRLF;
475 }
476 else
477 {
478 str << ">" << Symbols::CRLF;
479 for (TargetParams::const_iterator itParm = mTargetParams.begin(); itParm != mTargetParams.end(); itParm++)
480 {
481 str << indent << indent << indent << indent << "<param pname=\"" << itParm->first.xmlCharDataEncode() << "\" pval=\"" << itParm->second.xmlCharDataEncode() << "\"/>" << Symbols::CRLF;
482 }
483 str << indent << indent << indent << "</target>" << Symbols::CRLF;
484 }
485 }
486 if (!mSessionDescription.empty())
487 {
488 // SDP is multiline, so whitespace is important - don't format for "pretty" output
489 str << indent << indent << indent << "<session-description type=\"" << mSessionDescriptionType << "\">" << mSessionDescription.xmlCharDataEncode() << "</session-description>" << Symbols::CRLF;
490 }
491 if (mHasCSeq)
492 {
493 str << indent << indent << indent << "<cseq>" << mCSeq << "</cseq>" << Symbols::CRLF;
494 }
495 str << indent << indent << "</" << baseElementName << ">" << Symbols::CRLF;
496 }
497 return str;
498}
499
500void
502{
503 XMLCursor xml(pb);
504 const XMLCursor::AttributeMap& attr = xml.getAttributes();
506 bool baseDialogInfoNamespaceUriFound = false;
507 for (; itAttr != attr.end(); itAttr++)
508 {
509 if (itAttr->first.prefix("xmlns"))
510 {
511 Data prefix;
512 ParseBuffer pb(itAttr->first);
514 if (!pb.eof())
515 {
516 pb.skipChar();
517 const char* anchor = pb.position();
518 pb.skipToEnd();
519 pb.data(prefix, anchor);
520 }
521 if (isEqualNoCase(itAttr->second, BaseDialogInfoNamespaceUri))
522 {
523 baseDialogInfoNamespaceUriFound = true;
524 mBaseDialogInfoNamespacePrefix = prefix;
525 }
527 {
528 mSharedAppearanceDialogInfoNamespacePrefix = prefix;
529 }
530 }
531 else if (itAttr->first == "version")
532 {
533 mVersion = itAttr->second.convertUnsignedLong();
534 }
535 else if (itAttr->first == "state")
536 {
537 mDialogInfoState = dialogInfoStateStringToEnum(itAttr->second);
538 }
539 else if (itAttr->first == "entity")
540 {
541 mEntity = Uri(itAttr->second.xmlCharDataDecode()); // can throw!
542 }
543 else
544 {
545 DebugLog(<< "Unknown root attribute: " << itAttr->first << "=" << itAttr->second);
546 }
547 }
548
549 if (!baseDialogInfoNamespaceUriFound)
550 {
551 WarningLog(<< "Base xmlns from RFC4235 was not found, expected: " << BaseDialogInfoNamespaceUri);
552 // ?slg? - throw or be tolerant?
553 }
554
555 if (xml.firstChild())
556 {
557 do
558 {
559 if (compareTag(xml.getTag(), "dialog", mBaseDialogInfoNamespacePrefix))
560 {
561 parseDialog(xml);
562 }
563 else
564 {
565 DebugLog(<< "Unknown root element: " << xml.getTag());
566 }
567 } while (xml.nextSibling());
568 xml.parent();
569 }
570}
571
572void
573DialogInfoContents::parseDialog(XMLCursor& xml)
574{
575 const XMLCursor::AttributeMap& attr = xml.getAttributes();
577 Dialog dialog;
578 for (; itAttr != attr.end(); itAttr++)
579 {
580 if (itAttr->first == "id")
581 {
582 dialog.mId = itAttr->second.xmlCharDataDecode();
583 }
584 else if (itAttr->first == "call-id")
585 {
586 dialog.mCallId = itAttr->second.xmlCharDataDecode();
587 }
588 else if (itAttr->first == "local-tag")
589 {
590 dialog.mLocalTag = itAttr->second.xmlCharDataDecode();
591 }
592 else if (itAttr->first == "remote-tag")
593 {
594 dialog.mRemoteTag = itAttr->second.xmlCharDataDecode();
595 }
596 else if (itAttr->first == "direction")
597 {
598 dialog.mDirection = directionStringToEnum(itAttr->second);
599 }
600 else
601 {
602 DebugLog(<< "Unknown dialog attribute: " << itAttr->first << "=" << itAttr->second);
603 }
604 }
605
606 if (dialog.mId.empty())
607 {
608 WarningLog(<< "Dialog Id was not found for dialog element");
609 // ?slg? - throw or be tolerant?
610 }
611
612 if (xml.firstChild())
613 {
614 do
615 {
616 if (compareTag(xml.getTag(), "state", mBaseDialogInfoNamespacePrefix))
617 {
618 const XMLCursor::AttributeMap& attr = xml.getAttributes();
619 for (itAttr = attr.begin(); itAttr != attr.end(); itAttr++)
620 {
621 if (itAttr->first == "event")
622 {
623 dialog.mStateEvent = dialogStateEventStringToEnum(itAttr->second);
624 }
625 else if (itAttr->first == "code")
626 {
627 dialog.mStateCode = itAttr->second.convertInt();
628 }
629 else
630 {
631 DebugLog(<< "Unknown state attribute: " << itAttr->first << "=" << itAttr->second);
632 }
633 }
634 if (xml.firstChild())
635 {
636 dialog.mState = dialogStateStringToEnum(xml.getValue());
637 xml.parent();
638 }
639 }
640 else if (compareTag(xml.getTag(), "duration", mBaseDialogInfoNamespacePrefix))
641 {
642 if (xml.firstChild())
643 {
644 dialog.mDuration = xml.getValue().convertUnsignedLong();
645 dialog.mHasDuration = true;
646 xml.parent();
647 }
648 }
649 else if (compareTag(xml.getTag(), "replaces", mBaseDialogInfoNamespacePrefix))
650 {
651 parseDialogIdInfo(xml, dialog.mReplaces);
652 }
653 else if (compareTag(xml.getTag(), "referred-by", mBaseDialogInfoNamespacePrefix))
654 {
655 parseNameAddrElement(xml, dialog.mReferredBy);
656 }
657 else if (compareTag(xml.getTag(), "route-set", mBaseDialogInfoNamespacePrefix))
658 {
659 if (xml.firstChild())
660 {
661 do
662 {
663 if (compareTag(xml.getTag(), "hop", mBaseDialogInfoNamespacePrefix))
664 {
665 NameAddr nameAddr;
666 if (parseUriValue(xml, nameAddr.uri()))
667 {
668 dialog.mRouteSet.push_back(nameAddr);
669 }
670 }
671 else
672 {
673 DebugLog(<< "Unknown dialog/route-set element: " << xml.getTag());
674 }
675 } while (xml.nextSibling());
676 xml.parent();
677 }
678 }
679 else if (compareTag(xml.getTag(), "local", mBaseDialogInfoNamespacePrefix))
680 {
681 dialog.mLocalParticipant.parse(xml, mBaseDialogInfoNamespacePrefix);
682 }
683 else if (compareTag(xml.getTag(), "remote", mBaseDialogInfoNamespacePrefix))
684 {
685 dialog.mRemoteParticipant.parse(xml, mBaseDialogInfoNamespacePrefix);
686 }
687 // Now Look for RFC7463 tags
688 else if (compareTag(xml.getTag(), "appearance", mSharedAppearanceDialogInfoNamespacePrefix))
689 {
690 if (xml.firstChild())
691 {
692 dialog.mAppearance = xml.getValue().convertUnsignedLong();
693 dialog.mHasAppearance = true;
694 xml.parent();
695 }
696 }
697 else if (compareTag(xml.getTag(), "exclusive", mSharedAppearanceDialogInfoNamespacePrefix))
698 {
699 if (xml.firstChild())
700 {
701 dialog.mExclusive = isEqualNoCase(xml.getValue(), "true");
702 dialog.mHasExclusive = true;
703 xml.parent();
704 }
705 }
706 else if (compareTag(xml.getTag(), "replaced-dialog", mSharedAppearanceDialogInfoNamespacePrefix))
707 {
708 Dialog::DialogIdInfo dialogIdInfo;
709 if (parseDialogIdInfo(xml, dialogIdInfo))
710 {
711 dialog.mReplacedDialogs.push_back(dialogIdInfo);
712 }
713 }
714 else if (compareTag(xml.getTag(), "joined-dialog", mSharedAppearanceDialogInfoNamespacePrefix))
715 {
716 Dialog::DialogIdInfo dialogIdInfo;
717 if (parseDialogIdInfo(xml, dialogIdInfo))
718 {
719 dialog.mJoinedDialogs.push_back(dialogIdInfo);
720 }
721 }
722 else
723 {
724 Data elementName = xml.getTag();
725 if (xml.firstChild())
726 {
727 DebugLog(<< "Unknown dialog element: " << elementName << " value: " << xml.getValue().xmlCharDataDecode());
728 dialog.addDialogElement(elementName, xml.getValue().xmlCharDataDecode());
729 xml.parent();
730 }
731 else
732 {
733 DebugLog(<< "Unknown dialog element: " << elementName);
734 }
735 }
736 } while (xml.nextSibling());
737 xml.parent();
738 }
739
740 //DebugLog(<< "Pushing " << mDialogs.size() << "'th dialog " << dialog.mId << " parsed into DialogInfoCOntents::mDialogs");
741 mDialogs.push_back(dialog);
742}
743
744bool
745DialogInfoContents::parseDialogIdInfo(XMLCursor& xml, Dialog::DialogIdInfo& dialogIdInfo)
746{
747 const XMLCursor::AttributeMap& attr = xml.getAttributes();
748 for (XMLCursor::AttributeMap::const_iterator itAttr = attr.begin(); itAttr != attr.end(); itAttr++)
749 {
750 if (itAttr->first == "call-id")
751 {
752 dialogIdInfo.mCallId = itAttr->second.xmlCharDataDecode();
753 }
754 else if (itAttr->first == "local-tag")
755 {
756 dialogIdInfo.mLocalTag = itAttr->second.xmlCharDataDecode();
757 }
758 else if (itAttr->first == "remote-tag")
759 {
760 dialogIdInfo.mRemoteTag = itAttr->second.xmlCharDataDecode();
761 }
762 else
763 {
764 DebugLog(<< "Unknown dialog/replaces attribute: " << itAttr->first << "=" << itAttr->second);
765 }
766 }
767 return !dialogIdInfo.mCallId.empty() && !dialogIdInfo.mLocalTag.empty() && !dialogIdInfo.mRemoteTag.empty();
768}
769
770bool
771DialogInfoContents::parseUriValue(XMLCursor& xml, Uri& uri)
772{
773 bool parseGood = false;
774 if (xml.firstChild())
775 {
776 try
777 {
778 uri = Uri(xml.getValue().xmlCharDataDecode());
779 parseGood = true;
780 }
781 catch (BaseException& ex) // ?slg? - catch here or not - let exception bubble up? or rethrow?
782 {
783 DebugLog(<< "Could not parse NameAddr value: " << xml.getValue().xmlCharDataDecode() << ": " << ex);
784 }
785 xml.parent();
786 }
787 return parseGood;
788}
789
790bool
791DialogInfoContents::parseNameAddrElement(XMLCursor& xml, NameAddr& nameAddr)
792{
793 const XMLCursor::AttributeMap& attr = xml.getAttributes();
795 for (; itAttr != attr.end(); itAttr++)
796 {
797 if (itAttr->first == "display")
798 {
799 nameAddr.displayName() = itAttr->second.xmlCharDataDecode();
800 }
801 else
802 {
803 DebugLog(<< "Unknown NameAddr attribute: " << itAttr->first << "=" << itAttr->second);
804 }
805 }
806 return parseUriValue(xml, nameAddr.uri());
807}
808
809void
810DialogInfoContents::Dialog::Participant::parse(XMLCursor& xml, const Data& namespacePrefix)
811{
812 if (xml.firstChild())
813 {
814 do
815 {
816 if (compareTag(xml.getTag(), "identity", namespacePrefix))
817 {
818 parseNameAddrElement(xml, mIdentity);
819 }
820 else if (compareTag(xml.getTag(), "target", namespacePrefix))
821 {
822 try
823 {
824 const XMLCursor::AttributeMap& attr = xml.getAttributes();
826 for (; itAttr != attr.end(); itAttr++)
827 {
828 if (itAttr->first == "uri")
829 {
830 mTarget = Uri(itAttr->second.xmlCharDataDecode());
831 }
832 else
833 {
834 DebugLog(<< "Unknown dialog/participant/target attribute: " << itAttr->first << "=" << itAttr->second);
835 }
836 }
837
838 if (xml.firstChild())
839 {
840 do
841 {
842 if (compareTag(xml.getTag(), "param", namespacePrefix))
843 {
844 parseParam(xml);
845 }
846 else
847 {
848 DebugLog(<< "Unknown dialog/particpant/target element: " << xml.getTag());
849 }
850 } while (xml.nextSibling());
851 xml.parent();
852 }
853 }
854 catch (BaseException& ex) // ?slg? - catch here or not - let exception bubble up? or rethrow?
855 {
856 DebugLog(<< "Could not parse dialog/participatn/target uri value: " << xml.getValue().xmlCharDataDecode() << ": " << ex);
857 }
858 }
859 else if (compareTag(xml.getTag(), "session-description", namespacePrefix))
860 {
861 const XMLCursor::AttributeMap& attr = xml.getAttributes();
863 for (; itAttr != attr.end(); itAttr++)
864 {
865 if (itAttr->first == "type")
866 {
867 mSessionDescriptionType = itAttr->second.xmlCharDataDecode();
868 }
869 else
870 {
871 DebugLog(<< "Unknown dialog/participant/session-description attribute: " << itAttr->first << "=" << itAttr->second);
872 }
873 }
874 if (xml.firstChild())
875 {
876 mSessionDescription = xml.getValue().xmlCharDataDecode();
877 xml.parent();
878 }
879 }
880 else if (compareTag(xml.getTag(), "cseq", namespacePrefix))
881 {
882 if (xml.firstChild())
883 {
884 mCSeq = xml.getValue().convertUnsignedLong();
885 mHasCSeq = true;
886 xml.parent();
887 }
888 }
889 else
890 {
891 DebugLog(<< "Unknown dialog participant element: " << xml.getTag());
892 }
893 } while (xml.nextSibling());
894 xml.parent();
895 }
896}
897
898void
899DialogInfoContents::Dialog::Participant::parseParam(XMLCursor& xml)
900{
901 const XMLCursor::AttributeMap& attr = xml.getAttributes();
903 Data name;
904 Data value;
905 for (; itAttr != attr.end(); itAttr++)
906 {
907 if (itAttr->first == "pname")
908 {
909 name = itAttr->second.xmlCharDataDecode();
910 }
911 else if (itAttr->first == "pval")
912 {
913 value = itAttr->second.xmlCharDataDecode();
914 }
915 else
916 {
917 DebugLog(<< "Unknown dialog/participant/target/param attribute: " << itAttr->first << "=" << itAttr->second);
918 }
919 }
920 if (!name.empty())
921 {
922 mTargetParams[name] = value;
923 }
924}
925
926void
928{
929 checkParsed();
930 // Ensure id doesn't already exist
931 removeDialog(dialog.mId);
932 mDialogs.push_back(dialog);
933}
934
935bool
937{
938 checkParsed();
939 for (DialogList::iterator it = mDialogs.begin(); it != mDialogs.end(); it++)
940 {
941 if (it->mId == id)
942 {
943 mDialogs.erase(it);
944 return true;
945 }
946 }
947 return false;
948}
949
950
951/* ====================================================================
952*
953* Copyright (c) 2016 SIP Spectrum, Inc. All rights reserved.
954*
955* Redistribution and use in source and binary forms, with or without
956* modification, are permitted provided that the following conditions
957* are met:
958*
959* 1. Redistributions of source code must retain the above copyright
960* notice, this list of conditions and the following disclaimer.
961*
962* 2. Redistributions in binary form must reproduce the above copyright
963* notice, this list of conditions and the following disclaimer in
964* the documentation and/or other materials provided with the
965* distribution.
966*
967* 3. Neither the name of the author(s) nor the names of any contributors
968* may be used to endorse or promote products derived from this software
969* without specific prior written permission.
970*
971* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
972* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
973* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
974* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
975* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
976* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
977* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
978* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
979* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
980* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
981* SUCH DAMAGE.
982*
983* ====================================================================
984*
985*/
986/*
987* vi: set shiftwidth=3 expandtab:
988*/
static const Data BaseDialogInfoNamespaceUri("urn:ietf:params:xml:ns:dialog-info")
static const char * DirectionStrings[]
static const char * DialogStateEventStrings[]
static const char * DialogInfoStateStrings[]
static const Data SharedAppearanceDialogInfoNamespacePrefix("sa:")
static const Data SharedAppearanceDialogInfoNamespaceUri("urn:ietf:params:xml:ns:sa-dialog-info")
static const Data DefaultEncodeIndent(" ")
static const char * DialogStateStrings[]
#define DebugLog(args_)
Definition Logger.hxx:128
#define WarningLog(args_)
Definition Logger.hxx:134
The abstract base-class for all exceptions thrown by resip code.
Base class for all SIP body types.
Definition Contents.hxx:51
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
Data xmlCharDataDecode() const
Performs in-place XML Character Data un-escaping of a Data.
Definition Data.cxx:1464
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
Data xmlCharDataEncode() const
Performs in-place XML Character Data escaping of a Data.
Definition Data.cxx:1454
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
bool getTargetParam(const Data &name, Data &value) const
bool getDialogElement(const Data &childElementName, Data &elementValue, int instance=0) const
SIP body type for holding DialogInfo contents (MIME content-type application/dialog-info+xml).
virtual void parse(ParseBuffer &pb)
void addDialog(const Dialog &dialog)
static const char * dialogInfoStateToString(const DialogInfoState &dialogInfoState)
virtual Contents * clone() const
duplicate an DialogInfoContents object
static const char * dialogStateEventToString(const DialogStateEvent &dialogStateEvent)
static DialogState dialogStateStringToEnum(const Data &dialogStateString)
static bool compareTag(const Data &tagName, const Data &compareToTagNoPrefix, const Data &namespacePrefix)
static const char * directionToString(const Direction &direction)
static Direction directionStringToEnum(const Data &directionString)
bool removeDialog(const Data &id)
static const char * dialogStateToString(const DialogState &dialogState)
static const DialogInfoContents Empty
virtual EncodeStream & encodeParsed(EncodeStream &str) const
static const Mime & getStaticType()
static DialogInfoState dialogInfoStateStringToEnum(const Data &dialogInfoStateString)
static DialogStateEvent dialogStateEventStringToEnum(const Data &dialogStateEventString)
dcm! – kill typedef std::list<DialogId> DialogIdSet;
Definition Dialog.hxx:29
void checkParsed() const
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
Data & displayName()
Definition NameAddr.cxx:144
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipToEnd()
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
EncodeStream & encodeParameters(EncodeStream &str) const
Encodes parameters as they should appear on the wire.
void push_back(const T &t)
Inserts a header field value at the back of this container.
static const char * COLON
Definition Symbols.hxx:15
static const char * CRLF
Definition Symbols.hxx:21
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
const Data & getValue() const
const Data & getTag() const
const AttributeMap & getAttributes() const
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
#define EncodeStream