reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
GenericPidfContents.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 BasePidfNamespaceUri("urn:ietf:params:xml:ns:pidf");
22
23bool
25{
27 (void)factory;
28 return true;
29}
30
32
34 : Contents(getStaticType()), mSimplePresenceExtracted(false)
35{
36}
37
39 : Contents(getStaticType()), mSimplePresenceExtracted(false)
40{
41}
42
44 : Contents(hfv, contentsType), mSimplePresenceExtracted(false)
45{
46}
47
50{
51 if (this != &rhs)
52 {
54
55 // clear any data then merge in new stuff
56 reset();
57 mergeNoCheckParse(rhs);
58 }
59 return *this;
60}
61
63 : Contents(rhs), mSimplePresenceExtracted(false)
64{
65 // merge in new stuff
66 mergeNoCheckParse(rhs);
67}
68
73
74void
75GenericPidfContents::reset()
76{
77 // Cleanup Node Memory recursively
78 cleanupNodeMemory(mRootNodes);
79
80 // Clear namespace map
81 mNamespaces.clear();
82
83 mRootPidfNamespacePrefix.clear();
84 mEntity.host().clear();
85 mEntity.user().clear();
86
87 clearSimplePresenceInfo();
88}
89
90void GenericPidfContents::clearSimplePresenceInfo()
91{
92 SimplePresenceInfoList::iterator itSPList = mSimplePresenceInfoList.begin();
93 for (; itSPList != mSimplePresenceInfoList.end(); itSPList++)
94 {
95 delete *itSPList;
96 }
97 mSimplePresenceInfoList.clear();
98 mSimplePresenceExtracted = false;
99}
100
101void
102GenericPidfContents::cleanupNodeMemory(NodeList& nodeList)
103{
104 // Cleanup Node Memory recursively
105 NodeList::iterator itNode = nodeList.begin();
106 for (; itNode != nodeList.end(); itNode++)
107 {
108 cleanupNodeMemory((*itNode)->mChildren);
109 delete *itNode;
110 }
111 nodeList.clear();
112}
113
114Contents*
116{
117 return new GenericPidfContents(*this);
118}
119
120const Mime&
122{
123 static Mime type("application","pidf+xml");
124 return type;
125}
126
128GenericPidfContents::encodeParsed(EncodeStream& str) const
129{
130 str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << Symbols::CRLF;
131 str << "<" << mRootPidfNamespacePrefix << "presence ";
132 NamespaceMap::const_iterator itNs = mNamespaces.begin();
133 bool first = true;
134 for (; itNs != mNamespaces.end(); itNs++)
135 {
136 if (first)
137 {
138 first = false;
139 str << "xmlns";
140 }
141 else
142 {
143 str << " xmlns";
144 }
145 if (!itNs->second.empty()) // Check if prefix is not-empty
146 {
147 str << ":" << itNs->second.substr(0, itNs->second.size() - 1); // remove trailing ":"
148 }
149 str << "=\"" << itNs->first << "\"" << Symbols::CRLF;
150 }
151 str << " entity=\"" << mEntity << "\">" << Symbols::CRLF;
152 NodeList::const_iterator itNode = mRootNodes.begin();
153 Data indent(" ");
154 for (; itNode != mRootNodes.end(); itNode++)
155 {
156 (*itNode)->encode(str, indent);
157 }
158 str << "</" << mRootPidfNamespacePrefix << "presence>" << Symbols::CRLF;
159
160 return str;
161}
162
163void
165{
166 mSimplePresenceExtracted = false;
167
168 XMLCursor xml(pb);
169 const XMLCursor::AttributeMap& attr = xml.getAttributes();
171 for (; itAttr != attr.end(); itAttr++)
172 {
173 if (itAttr->first.prefix("xmlns"))
174 {
175 Data prefix;
176 ParseBuffer pb(itAttr->first);
178 if (!pb.eof())
179 {
180 pb.skipChar();
181 const char* anchor = pb.position();
182 pb.skipToEnd();
183 pb.data(prefix, anchor);
184 prefix += Symbols::COLON;
185 }
186 if (isEqualNoCase(itAttr->second, BasePidfNamespaceUri))
187 {
188 mRootPidfNamespacePrefix = prefix;
189 }
190
191 mNamespaces[itAttr->second] = prefix;
192 }
193 else if (itAttr->first == "entity")
194 {
195 mEntity = Uri(itAttr->second); // can throw!
196 }
197 else
198 {
199 DebugLog(<< "Unknown root attribute: " << itAttr->first << "=" << itAttr->second);
200 }
201 }
202
203 // Ensure root presence node is present
204 if (xml.getTag() == mRootPidfNamespacePrefix + Symbols::Presence)
205 {
206 if (xml.firstChild())
207 {
208 do
209 {
210 parseChildren(xml, mRootNodes);
211 } while (xml.nextSibling());
212 xml.parent();
213 }
214 }
215 else
216 {
217 // TODO Throw?
218 DebugLog(<< "Aborting parse, root presence node missing: " << mRootPidfNamespacePrefix + Symbols::Presence);
219 }
220}
221
222void
223GenericPidfContents::parseChildren(XMLCursor& xml, NodeList& nodeList)
224{
225 Node* node = new Node();
226 node->mAttributes = xml.getAttributes(); // !slg! yuck - yes we are copying memory for attributes
227 node->mValue.duplicate(xml.getValue()); // use Data::duplicate to avoid copying memory
228 ParseBuffer pb(xml.getTag());
229 const char* anchor = pb.position();
230 pb.skipToChar(Symbols::COLON[0]);
231 if (!pb.eof())
232 {
233 pb.skipChar();
234 pb.data(node->mNamespacePrefix, anchor);
235 anchor = pb.position();
236 pb.skipToEnd();
237 pb.data(node->mTag, anchor);
238 }
239 else
240 {
241 // No namespace prefix
242 node->mTag.duplicate(xml.getTag()); // use Data::duplicate to avoid copying memory
243 }
244
245 if (node->mValue.empty() && xml.firstChild())
246 {
247 do
248 {
249 if (!xml.getValue().empty())
250 {
251 node->mValue.duplicate(xml.getValue()); // use Data::duplicate to avoid copying memory
252 }
253 else
254 {
255 parseChildren(xml, node->mChildren);
256 }
257 } while (xml.nextSibling());
258 xml.parent();
259 }
260 nodeList.push_back(node);
261}
262
265{
267 for (; itAttrib != mAttributes.end(); itAttrib++)
268 {
269 str << " " << itAttrib->first << "=\"" << itAttrib->second << "\"";
270 }
271 return str;
272}
273
275GenericPidfContents::Node::encode(EncodeStream& str, Data indent) const
276{
277 if (!mTag.empty())
278 {
279 if (mChildren.size() == 0)
280 {
281 if (mValue.empty())
282 {
283 str << indent << "<" << mNamespacePrefix << mTag;
284 encodeAttributes(str);
285 str << "/>" << Symbols::CRLF;
286 }
287 else
288 {
289 str << indent << "<" << mNamespacePrefix << mTag;
290 encodeAttributes(str);
291 str << ">" << mValue << "</" << mNamespacePrefix << mTag << ">" << Symbols::CRLF;
292 }
293 }
294 // The following else collapses simple single nodes (no attributes or values) to one line: ie:
295 // <outernode></innernode></outernode>
296 else if (mChildren.size() == 1 && mAttributes.empty() &&
297 mChildren.front()->mValue.empty() && mChildren.front()->mAttributes.empty() && mChildren.front()->mChildren.size() == 0)
298 {
299 str << indent << "<" << mNamespacePrefix << mTag << "><" << mChildren.front()->mNamespacePrefix;
300 str << mChildren.front()->mTag << "/></" << mNamespacePrefix << mTag << ">" << Symbols::CRLF;
301 }
302 else
303 {
304 str << indent << "<" << mNamespacePrefix << mTag;
305 encodeAttributes(str);
306 str << ">" << Symbols::CRLF;
307 NodeList::const_iterator itNode = mChildren.begin();
308 for (; itNode != mChildren.end(); itNode++)
309 {
310 (*itNode)->encode(str, indent + " ");
311 }
312 str << indent << "</" << mNamespacePrefix << mTag << ">" << Symbols::CRLF;
313 }
314 }
315 return str;
316}
317
318void
319GenericPidfContents::Node::copy(const Node& rhs, HashMap<Data, Data, KeyedDataHash>* namespacePrefixCorrections)
320{
321 if (namespacePrefixCorrections)
322 {
323 // Check if namespace should be corrected
324 HashMap<Data, Data, KeyedDataHash>::iterator itNsCorr = namespacePrefixCorrections->find(rhs.mNamespacePrefix);
325 if (itNsCorr != namespacePrefixCorrections->end())
326 {
327 mNamespacePrefix = itNsCorr->second;
328 }
329 else
330 {
331 mNamespacePrefix = rhs.mNamespacePrefix;
332 }
333 }
334 else
335 {
336 mNamespacePrefix = rhs.mNamespacePrefix;
337 }
338 mTag = rhs.mTag;
339 mAttributes = rhs.mAttributes;
340 mValue = rhs.mValue;
341 NodeList::const_iterator itNode = rhs.mChildren.begin();
342 for (; itNode != rhs.mChildren.end(); itNode++)
343 {
344 Node* node = new Node();
345 node->copy(*(*itNode), namespacePrefixCorrections);
346 mChildren.push_back(node);
347 }
348}
349
350bool
352{
353 // Ensure both sides are parsed if not already
354 checkParsed();
355 other.checkParsed();
356 return mergeNoCheckParse(other);
357}
358
359void
361{
362 mRootNodes.clear();
363 mRootNodes = nodeList;
364}
365
366const Data&
368{
369 NodeList::iterator it = node->mChildren.begin();
370 for (; it != node->mChildren.end(); it++)
371 {
372 if ((*it)->mTag == tag)
373 {
374 return (*it)->mValue;
375 }
376 }
377 return Data::Empty;
378}
379
380bool
381GenericPidfContents::mergeNoCheckParse(const GenericPidfContents& other)
382{
383 mSimplePresenceExtracted = false;
384
385 // Validate entity user and host - we allow mismatched schemes
386 if (mEntity.host().empty())
387 {
388 mEntity = other.mEntity;
389 }
390 else if(mEntity.user() != other.mEntity.user() ||
391 mEntity.host() != other.mEntity.host())
392 {
393 DebugLog(<< "Merge failed, entities do not match: " << mEntity << ", other=" << other.mEntity);
394 return false;
395 }
396
397 HashMap<Data, Data, KeyedDataHash> namespacePrefixCorrections; // other/old prefix name, new/dest prefix name
398
399 // Copy over namespaces - looking for mismatched prefixes
400 bool checkNamespaceMismatches = mNamespaces.size() > 0;
401 NamespaceMap::const_iterator itOtherNs = other.mNamespaces.begin();
402 for(; itOtherNs != other.mNamespaces.end(); itOtherNs++)
403 {
404 // Check if namespace is already in list and if so - verify prefix will match
405 bool found = false;
406 if (checkNamespaceMismatches)
407 {
408 NamespaceMap::iterator itNs = mNamespaces.find(itOtherNs->first);
409 if (itNs != mNamespaces.end())
410 {
411 if (itNs->second != itOtherNs->second)
412 {
413 // Prefix used for same namespace does not match
414 namespacePrefixCorrections[itOtherNs->second] = itNs->second;
415 }
416 found = true;
417 }
418 }
419 if(!found)
420 {
421 mNamespaces[itOtherNs->first] = itOtherNs->second; // Copy over
422 }
423 }
424 // If we didn't check for namespace mismatches then we didn't have any namespaces
425 // to start with, which means we didn't have a root namespace - set it now
426 if (!checkNamespaceMismatches)
427 {
428 mRootPidfNamespacePrefix = other.mRootPidfNamespacePrefix;
429 }
430
431 // Merge root presence nodes
432 bool checkMatches = mRootNodes.size() > 0;
433 NodeList::const_iterator itOtherNode = other.mRootNodes.begin();
434 for(; itOtherNode != other.mRootNodes.end(); itOtherNode++)
435 {
436 // If there is an ID attribute then see if tag/id combo lives already in local list
437 bool matchFound = false;
438 if (checkMatches)
439 {
440 Node::AttributeMap::iterator itOtherAttrib = (*itOtherNode)->mAttributes.find("id");
441 if (itOtherAttrib != (*itOtherNode)->mAttributes.end())
442 {
443 NodeList::iterator itNode = mRootNodes.begin();
444 for (; itNode != mRootNodes.end(); itNode++)
445 {
446 if ((*itNode)->mTag == (*itOtherNode)->mTag)
447 {
448 // Node found - check for id match
449 Node::AttributeMap::iterator itAttrib = (*itNode)->mAttributes.find("id");
450 if (itAttrib != (*itNode)->mAttributes.end())
451 {
452 if (itOtherAttrib->second == itAttrib->second) // Check if Id's match
453 {
454 // compare timestamps
455 const Data& ts1 = getSubNodeValue((*itNode), "timestamp");
456 const Data& ts2 = getSubNodeValue((*itOtherNode), "timestamp");
457 // Note: to compare timestamps we use a string compare and rely on properties from RFC3339 (section 5.1) with
458 // the assumption that same id items will generate timestamps in the same timezone and timezone format
459 if (ts1.empty() || ts2.empty() || ts2 >= ts1)
460 {
461 cleanupNodeMemory((*itNode)->mChildren);
462 (*itNode)->copy(*(*itOtherNode), &namespacePrefixCorrections);
463 }
464 matchFound = true;
465 break;
466 }
467 }
468 }
469 }
470 }
471 }
472 if (!matchFound)
473 {
474 Node* node = new Node();
475 node->copy(*(*itOtherNode), namespacePrefixCorrections.size() > 0 ? &namespacePrefixCorrections : 0);
476 mRootNodes.push_back(node);
477 }
478 }
479 return true;
480}
481
482void
484{
485 checkParsed();
486 mEntity = entity;
487}
488
489const Uri&
491{
492 checkParsed();
493 return mEntity;
494}
495
496void
498{
499 checkParsed();
500 Data adjustedPrefix(prefix);
501 // Add colon to end if missing if prefix was provided
502 if (!prefix.empty() && !prefix.postfix(Symbols::COLON))
503 {
504 adjustedPrefix += Symbols::COLON;
505 }
507 {
508 mRootPidfNamespacePrefix = adjustedPrefix;
509 }
510 mNamespaces[uri] = adjustedPrefix;
511}
512
513void
515 bool online,
516 const Data& timestamp,
517 const Data& note,
518 const Data& contact,
519 const Data& contactPriority)
520{
521 // Make sure we have extract any existing simple presence info
522 extractSimplePresenceInfo();
523
524 if (mNamespaces.empty())
525 {
526 // Add default namespace
527 addNamespace(BasePidfNamespaceUri, Data::Empty); // no custom prefix
528 }
529
530 // See if node exists and if so delete it - otherwise add new
531 bool foundExisting = false;
532 NodeList::iterator it = mRootNodes.begin();
533 for(; it != mRootNodes.end(); it++)
534 {
535 if((*it)->mTag == "tuple")
536 {
537 Node::AttributeMap::iterator itAttrib = (*it)->mAttributes.find("id");
538 if(itAttrib != (*it)->mAttributes.end())
539 {
540 if(itAttrib->second == id)
541 {
542 foundExisting = true;
543 break;
544 }
545 }
546 }
547 }
548
549 Node* tupleNode;
550 if(foundExisting)
551 {
552 // Remove all children and add back, below
553 cleanupNodeMemory((*it)->mChildren);
554 tupleNode = (*it);
555 }
556 else
557 {
558 tupleNode = new Node();
559 tupleNode->mNamespacePrefix = mRootPidfNamespacePrefix;
560 tupleNode->mTag = "tuple";
561 tupleNode->mAttributes["id"] = id;
562 }
563
564 // Add Status Node with Basic subnode
565 Node* statusNode = new Node();
566 statusNode->mNamespacePrefix = mRootPidfNamespacePrefix;
567 statusNode->mTag = "status";
568 Node* basicNode = new Node();
569 basicNode->mNamespacePrefix = mRootPidfNamespacePrefix;
570 basicNode->mTag = "basic";
571 basicNode->mValue = online ? "open" : "closed";
572 statusNode->mChildren.push_back(basicNode);
573 tupleNode->mChildren.push_back(statusNode);
574
575 // Add Contact node if required
576 if (!contact.empty())
577 {
578 Node* contactNode = new Node();
579 contactNode->mNamespacePrefix = mRootPidfNamespacePrefix;
580 contactNode->mTag = "contact";
581 contactNode->mValue = contact;
582 if (!contactPriority.empty())
583 {
584 contactNode->mAttributes["priority"] = contactPriority;
585 }
586 tupleNode->mChildren.push_back(contactNode);
587 }
588
589 // Add Note node if required
590 if (!note.empty())
591 {
592 Node* noteNode = new Node();
593 noteNode->mNamespacePrefix = mRootPidfNamespacePrefix;
594 noteNode->mTag = "note";
595 noteNode->mValue = note;
596 tupleNode->mChildren.push_back(noteNode);
597 }
598
599 // Add Timestamp node if required
600 if (!timestamp.empty())
601 {
602 Node* timestampNode = new Node();
603 timestampNode->mNamespacePrefix = mRootPidfNamespacePrefix;
604 timestampNode->mTag = "timestamp";
605 timestampNode->mValue = timestamp;
606 tupleNode->mChildren.push_back(timestampNode);
607 }
608
609 if (!foundExisting)
610 {
611 mRootNodes.push_back(tupleNode);
612 }
613
614 // store info in list - if TupleId exists already then update it, otherwise add new
615 foundExisting = false; // reuse flag from above
616 SimplePresenceInfoList::iterator itSPList = mSimplePresenceInfoList.begin();
617 for (; itSPList != mSimplePresenceInfoList.end(); itSPList++)
618 {
619 if ((*itSPList)->mTupleId == id)
620 {
621 (*itSPList)->mOnline = online;
622 (*itSPList)->mTimestamp = timestamp;
623 (*itSPList)->mNote = note;
624 (*itSPList)->mContact = contact;
625 (*itSPList)->mContactPriority = contactPriority;
626 foundExisting = true;
627 }
628 }
629 if (!foundExisting)
630 {
632 info->mTupleId = id;
633 info->mOnline = online;
634 info->mTimestamp = timestamp;
635 info->mNote = note;
636 info->mContact = contact;
637 info->mContactPriority = contactPriority;
638 mSimplePresenceInfoList.push_back(info);
639 }
640 mSimplePresenceExtracted = true;
641}
642
643const Data&
645{
646 checkParsed();
647 extractSimplePresenceInfo();
648 if (mSimplePresenceInfoList.empty())
649 {
650 return Data::Empty;
651 }
652 else
653 {
654 return mSimplePresenceInfoList.front()->mTupleId;
655 }
656}
657
658const bool
660{
661 checkParsed();
662 extractSimplePresenceInfo();
663 if (mSimplePresenceInfoList.empty())
664 {
665 return false;
666 }
667 else
668 {
669 return mSimplePresenceInfoList.front()->mOnline;
670 }
671}
672
673const Data&
675{
676 checkParsed();
677 extractSimplePresenceInfo();
678 if (mSimplePresenceInfoList.empty())
679 {
680 return Data::Empty;
681 }
682 else
683 {
684 return mSimplePresenceInfoList.front()->mTimestamp;
685 }
686}
687
688const Data&
690{
691 checkParsed();
692 extractSimplePresenceInfo();
693 if (mSimplePresenceInfoList.empty())
694 {
695 return Data::Empty;
696 }
697 else
698 {
699 return mSimplePresenceInfoList.front()->mNote;
700 }
701}
702
703const Data&
705{
706 checkParsed();
707 extractSimplePresenceInfo();
708 if (mSimplePresenceInfoList.empty())
709 {
710 return Data::Empty;
711 }
712 else
713 {
714 return mSimplePresenceInfoList.front()->mContact;
715 }
716}
717
718const Data&
720{
721 checkParsed();
722 extractSimplePresenceInfo();
723 if (mSimplePresenceInfoList.empty())
724 {
725 return Data::Empty;
726 }
727 else
728 {
729 return mSimplePresenceInfoList.front()->mContactPriority;
730 }
731}
732
733void
734GenericPidfContents::extractSimplePresenceInfo()
735{
736 if (!mSimplePresenceExtracted)
737 {
738 clearSimplePresenceInfo();
739
740 // Iterate through root nodes and find first tuple
741 NodeList::const_iterator itNode = mRootNodes.begin();
742 for (; itNode != mRootNodes.end(); itNode++)
743 {
744 if ((*itNode)->mTag == "tuple")
745 {
746 Node::AttributeMap::iterator itAttrib = (*itNode)->mAttributes.find("id");
747 if (itAttrib != (*itNode)->mAttributes.end())
748 {
749 SimplePresenceInfo* info = new SimplePresenceInfo;
750 info->mTupleId = itAttrib->second;
751 // iterate through children looking for nodes we want
752 NodeList::const_iterator itTupleChild = (*itNode)->mChildren.begin();
753 for (; itTupleChild != (*itNode)->mChildren.end(); itTupleChild++)
754 {
755 if ((*itTupleChild)->mTag == "status")
756 {
757 // iterate through children looking for basic node
758 NodeList::const_iterator itStatusChild = (*itTupleChild)->mChildren.begin();
759 for (; itStatusChild != (*itTupleChild)->mChildren.end(); itStatusChild++)
760 {
761 if ((*itStatusChild)->mTag == "basic")
762 {
763 info->mOnline = (*itStatusChild)->mValue == "open";
764 break;
765 }
766 }
767 }
768 else if (info->mContact.empty() && (*itTupleChild)->mTag == "contact")
769 {
770 info->mContact = (*itTupleChild)->mValue;
771 Node::AttributeMap::iterator itAttrib = (*itTupleChild)->mAttributes.find("priority");
772 if (itAttrib != (*itTupleChild)->mAttributes.end())
773 {
774 info->mContactPriority = itAttrib->second;
775 }
776 }
777 else if (info->mNote.empty() && (*itTupleChild)->mTag == "note")
778 {
779 info->mNote = (*itTupleChild)->mValue;
780 }
781 else if (info->mTimestamp.empty() && (*itTupleChild)->mTag == "timestamp")
782 {
783 info->mTimestamp = (*itTupleChild)->mValue;
784 }
785 }
786 // Just push on the back, we could consider checking if the TupleId already exists before
787 // adding, but we are assuming unique tupleid entries in the document for now.
788 mSimplePresenceInfoList.push_back(info);
789 }
790 }
791 }
792 mSimplePresenceExtracted = true;
793 }
794}
795
796Data
798{
799 time_t now;
800 time(&now);
801 return generateTimestampData(now);
802}
803
804static void pad2(const int x, DataStream& str)
805{
806 if (x < 10)
807 {
808 str << Symbols::ZERO[0];
809 }
810 str << x;
811}
812
813Data
815{
816 struct tm gmt;
817#if defined(WIN32)
818 if (gmtime_s(&gmt, &datetime) != 0)
819 {
820 int e = getErrno();
821 DebugLog(<< "Failed to convert to gmt: " << strError(e));
822 return Data::Empty;
823 }
824#else
825 // gmtime_r is available on Linux, Solaris, and other POSIX platforms
826 if (gmtime_r(&datetime, &gmt) == 0)
827 {
828 int e = getErrno();
829 DebugLog(<< "Failed to convert to gmt: " << strError(e));
830 return Data::Empty;
831 }
832#endif
833
834 Data timestamp;
835 {
836 DataStream ds(timestamp);
837 ds << gmt.tm_year + 1900 << "-";
838 pad2(gmt.tm_mon + 1, ds);
839 ds << "-";
840 pad2(gmt.tm_mday, ds);
841 ds << "T";
842 pad2(gmt.tm_hour, ds);
843 ds << ":";
844 pad2(gmt.tm_min, ds);
845 ds << ":";
846 pad2(gmt.tm_sec, ds);
847 ds << "Z";
848 }
849 return timestamp;
850}
851
854{
855 strm << "Tuple ["
856 << " id=" << tuple.mTupleId
857 << " status=" << tuple.mOnline
858 << " note=" << tuple.mNote
859 << " contact=" << tuple.mContact
860 << " contactPriority=" << tuple.mContactPriority << "]";
861 return strm;
862}
863
864/* ====================================================================
865*
866* Copyright (c) 2015-2026 SIP Spectrum, Inc. All rights reserved.
867*
868* Redistribution and use in source and binary forms, with or without
869* modification, are permitted provided that the following conditions
870* are met:
871*
872* 1. Redistributions of source code must retain the above copyright
873* notice, this list of conditions and the following disclaimer.
874*
875* 2. Redistributions in binary form must reproduce the above copyright
876* notice, this list of conditions and the following disclaimer in
877* the documentation and/or other materials provided with the
878* distribution.
879*
880* 3. Neither the name of the author(s) nor the names of any contributors
881* may be used to endorse or promote products derived from this software
882* without specific prior written permission.
883*
884* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
885* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
886* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
887* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
888* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
889* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
890* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
891* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
892* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
893* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
894* SUCH DAMAGE.
895*
896* ====================================================================
897*
898*/
899/*
900* vi: set shiftwidth=3 expandtab:
901*/
static void pad2(const int x, EncodeStream &str)
static const Data BasePidfNamespaceUri("urn:ietf:params:xml:ns:pidf")
#define DebugLog(args_)
Definition Logger.hxx:128
Base class for all SIP body types.
Definition Contents.hxx:51
Contents & operator=(const Contents &rhs)
Assignment operator.
Definition Contents.cxx:71
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
bool postfix(const Data &post) const noexcept
Returns true if this Data ends with the bytes indicated by the passed-in Data.
Definition Data.cxx:1910
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
EncodeStream & encode(EncodeStream &str, Data indent) const
EncodeStream & encodeAttributes(EncodeStream &str) const
void copy(const Node &rhs, HashMap< Data, Data, KeyedDataHash > *namespacePrefixCorrections)
SIP body type for holding PIDF contents (MIME content-type application/pidf+xml).
void setRootNodes(const NodeList &nodeList)
virtual GenericPidfContents & operator=(const GenericPidfContents &rhs)
static const Mime & getStaticType()
const Data & getSimplePresenceContactPriority()
void setSimplePresenceTupleNode(const Data &id, bool online, const Data &timestamp=Data::Empty, const Data &note=Data::Empty, const Data &contact=Data::Empty, const Data &contactPriority=Data::Empty)
virtual Contents * clone() const
duplicate an GenericPidfContents object
virtual void parse(ParseBuffer &pb)
static const GenericPidfContents Empty
virtual EncodeStream & encodeParsed(EncodeStream &str) const
static Data generateTimestampData(time_t datetime)
void addNamespace(const Data &uri, const Data &prefix)
static const Data & getSubNodeValue(Node *node, const Data &tag)
void setEntity(const Uri &entity)
bool merge(const GenericPidfContents &other)
void checkParsed() const
iterator find(const Key &key)
size_type size() const
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipToEnd()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
static const char * ZERO
Definition Symbols.hxx:36
static const char * COLON
Definition Symbols.hxx:15
static const char * Presence
Definition Symbols.hxx:103
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
Data & user()
Definition Uri.hxx:42
Data & host()
Definition Uri.hxx:40
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
int getErrno()
Definition Socket.hxx:97
std::string strError(int err)
Definition compat.hxx:274
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
#define EncodeStream