1#if defined(HAVE_CONFIG_H)
19#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
34 :
Contents(getStaticType()), mSimplePresenceExtracted(false)
39 :
Contents(getStaticType()), mSimplePresenceExtracted(false)
44 :
Contents(hfv, contentsType), mSimplePresenceExtracted(false)
57 mergeNoCheckParse(rhs);
63 :
Contents(rhs), mSimplePresenceExtracted(false)
66 mergeNoCheckParse(rhs);
75GenericPidfContents::reset()
78 cleanupNodeMemory(mRootNodes);
83 mRootPidfNamespacePrefix.
clear();
87 clearSimplePresenceInfo();
90void GenericPidfContents::clearSimplePresenceInfo()
92 SimplePresenceInfoList::iterator itSPList = mSimplePresenceInfoList.begin();
93 for (; itSPList != mSimplePresenceInfoList.end(); itSPList++)
97 mSimplePresenceInfoList.clear();
98 mSimplePresenceExtracted =
false;
102GenericPidfContents::cleanupNodeMemory(NodeList& nodeList)
105 NodeList::iterator itNode = nodeList.begin();
106 for (; itNode != nodeList.end(); itNode++)
108 cleanupNodeMemory((*itNode)->mChildren);
123 static Mime type(
"application",
"pidf+xml");
130 str <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <<
Symbols::CRLF;
131 str <<
"<" << mRootPidfNamespacePrefix <<
"presence ";
134 for (; itNs != mNamespaces.
end(); itNs++)
145 if (!itNs->second.empty())
147 str <<
":" << itNs->second.substr(0, itNs->second.size() - 1);
152 NodeList::const_iterator itNode = mRootNodes.begin();
154 for (; itNode != mRootNodes.end(); itNode++)
156 (*itNode)->encode(str, indent);
158 str <<
"</" << mRootPidfNamespacePrefix <<
"presence>" <<
Symbols::CRLF;
166 mSimplePresenceExtracted =
false;
171 for (; itAttr != attr.
end(); itAttr++)
173 if (itAttr->first.prefix(
"xmlns"))
183 pb.
data(prefix, anchor);
188 mRootPidfNamespacePrefix = prefix;
191 mNamespaces[itAttr->second] = prefix;
193 else if (itAttr->first ==
"entity")
195 mEntity =
Uri(itAttr->second);
199 DebugLog(<<
"Unknown root attribute: " << itAttr->first <<
"=" << itAttr->second);
210 parseChildren(xml, mRootNodes);
223GenericPidfContents::parseChildren(
XMLCursor& xml, NodeList& nodeList)
225 Node* node =
new Node();
227 node->mValue.duplicate(xml.
getValue());
229 const char* anchor = pb.position();
234 pb.data(node->mNamespacePrefix, anchor);
235 anchor = pb.position();
237 pb.data(node->mTag, anchor);
242 node->mTag.duplicate(xml.
getTag());
251 node->mValue.duplicate(xml.
getValue());
255 parseChildren(xml, node->mChildren);
260 nodeList.push_back(node);
269 str <<
" " << itAttrib->first <<
"=\"" << itAttrib->second <<
"\"";
279 if (mChildren.size() == 0)
283 str << indent <<
"<" << mNamespacePrefix << mTag;
284 encodeAttributes(str);
289 str << indent <<
"<" << mNamespacePrefix << mTag;
290 encodeAttributes(str);
291 str <<
">" << mValue <<
"</" << mNamespacePrefix << mTag <<
">" <<
Symbols::CRLF;
296 else if (mChildren.size() == 1 && mAttributes.empty() &&
297 mChildren.front()->mValue.empty() && mChildren.front()->mAttributes.empty() && mChildren.front()->mChildren.size() == 0)
299 str << indent <<
"<" << mNamespacePrefix << mTag <<
"><" << mChildren.front()->mNamespacePrefix;
300 str << mChildren.front()->mTag <<
"/></" << mNamespacePrefix << mTag <<
">" <<
Symbols::CRLF;
304 str << indent <<
"<" << mNamespacePrefix << mTag;
305 encodeAttributes(str);
307 NodeList::const_iterator itNode = mChildren.begin();
308 for (; itNode != mChildren.end(); itNode++)
310 (*itNode)->encode(str, indent +
" ");
312 str << indent <<
"</" << mNamespacePrefix << mTag <<
">" <<
Symbols::CRLF;
321 if (namespacePrefixCorrections)
324 HashMap<Data, Data, KeyedDataHash>::iterator itNsCorr = namespacePrefixCorrections->
find(rhs.
mNamespacePrefix);
325 if (itNsCorr != namespacePrefixCorrections->end())
327 mNamespacePrefix = itNsCorr->second;
341 NodeList::const_iterator itNode = rhs.
mChildren.begin();
342 for (; itNode != rhs.
mChildren.end(); itNode++)
345 node->
copy(*(*itNode), namespacePrefixCorrections);
346 mChildren.push_back(node);
356 return mergeNoCheckParse(other);
363 mRootNodes = nodeList;
369 NodeList::iterator it = node->
mChildren.begin();
370 for (; it != node->
mChildren.end(); it++)
372 if ((*it)->mTag == tag)
374 return (*it)->mValue;
383 mSimplePresenceExtracted =
false;
388 mEntity = other.mEntity;
390 else if(mEntity.
user() != other.mEntity.
user() ||
391 mEntity.
host() != other.mEntity.
host())
393 DebugLog(<<
"Merge failed, entities do not match: " << mEntity <<
", other=" << other.mEntity);
397 HashMap<Data, Data, KeyedDataHash> namespacePrefixCorrections;
400 bool checkNamespaceMismatches = mNamespaces.
size() > 0;
402 for(; itOtherNs != other.mNamespaces.
end(); itOtherNs++)
406 if (checkNamespaceMismatches)
409 if (itNs != mNamespaces.
end())
411 if (itNs->second != itOtherNs->second)
414 namespacePrefixCorrections[itOtherNs->second] = itNs->second;
421 mNamespaces[itOtherNs->first] = itOtherNs->second;
426 if (!checkNamespaceMismatches)
428 mRootPidfNamespacePrefix = other.mRootPidfNamespacePrefix;
432 bool checkMatches = mRootNodes.size() > 0;
433 NodeList::const_iterator itOtherNode = other.mRootNodes.begin();
434 for(; itOtherNode != other.mRootNodes.end(); itOtherNode++)
437 bool matchFound =
false;
441 if (itOtherAttrib != (*itOtherNode)->mAttributes.end())
443 NodeList::iterator itNode = mRootNodes.begin();
444 for (; itNode != mRootNodes.end(); itNode++)
446 if ((*itNode)->mTag == (*itOtherNode)->mTag)
450 if (itAttrib != (*itNode)->mAttributes.end())
452 if (itOtherAttrib->second == itAttrib->second)
461 cleanupNodeMemory((*itNode)->mChildren);
462 (*itNode)->copy(*(*itOtherNode), &namespacePrefixCorrections);
474 Node* node =
new Node();
475 node->copy(*(*itOtherNode), namespacePrefixCorrections.size() > 0 ? &namespacePrefixCorrections : 0);
476 mRootNodes.push_back(node);
500 Data adjustedPrefix(prefix);
508 mRootPidfNamespacePrefix = adjustedPrefix;
510 mNamespaces[uri] = adjustedPrefix;
516 const Data& timestamp,
519 const Data& contactPriority)
522 extractSimplePresenceInfo();
524 if (mNamespaces.
empty())
531 bool foundExisting =
false;
532 NodeList::iterator it = mRootNodes.begin();
533 for(; it != mRootNodes.end(); it++)
535 if((*it)->mTag ==
"tuple")
538 if(itAttrib != (*it)->mAttributes.end())
540 if(itAttrib->second ==
id)
542 foundExisting =
true;
553 cleanupNodeMemory((*it)->mChildren);
558 tupleNode =
new Node();
560 tupleNode->
mTag =
"tuple";
567 statusNode->
mTag =
"status";
570 basicNode->
mTag =
"basic";
571 basicNode->
mValue = online ?
"open" :
"closed";
572 statusNode->
mChildren.push_back(basicNode);
573 tupleNode->
mChildren.push_back(statusNode);
576 if (!contact.
empty())
580 contactNode->
mTag =
"contact";
581 contactNode->
mValue = contact;
582 if (!contactPriority.
empty())
584 contactNode->
mAttributes[
"priority"] = contactPriority;
586 tupleNode->
mChildren.push_back(contactNode);
594 noteNode->
mTag =
"note";
596 tupleNode->
mChildren.push_back(noteNode);
600 if (!timestamp.
empty())
604 timestampNode->
mTag =
"timestamp";
605 timestampNode->
mValue = timestamp;
606 tupleNode->
mChildren.push_back(timestampNode);
611 mRootNodes.push_back(tupleNode);
615 foundExisting =
false;
616 SimplePresenceInfoList::iterator itSPList = mSimplePresenceInfoList.begin();
617 for (; itSPList != mSimplePresenceInfoList.end(); itSPList++)
619 if ((*itSPList)->mTupleId ==
id)
621 (*itSPList)->mOnline = online;
622 (*itSPList)->mTimestamp = timestamp;
623 (*itSPList)->mNote = note;
624 (*itSPList)->mContact = contact;
625 (*itSPList)->mContactPriority = contactPriority;
626 foundExisting =
true;
638 mSimplePresenceInfoList.push_back(info);
640 mSimplePresenceExtracted =
true;
647 extractSimplePresenceInfo();
648 if (mSimplePresenceInfoList.empty())
654 return mSimplePresenceInfoList.front()->mTupleId;
662 extractSimplePresenceInfo();
663 if (mSimplePresenceInfoList.empty())
669 return mSimplePresenceInfoList.front()->mOnline;
677 extractSimplePresenceInfo();
678 if (mSimplePresenceInfoList.empty())
684 return mSimplePresenceInfoList.front()->mTimestamp;
692 extractSimplePresenceInfo();
693 if (mSimplePresenceInfoList.empty())
699 return mSimplePresenceInfoList.front()->mNote;
707 extractSimplePresenceInfo();
708 if (mSimplePresenceInfoList.empty())
714 return mSimplePresenceInfoList.front()->mContact;
722 extractSimplePresenceInfo();
723 if (mSimplePresenceInfoList.empty())
729 return mSimplePresenceInfoList.front()->mContactPriority;
734GenericPidfContents::extractSimplePresenceInfo()
736 if (!mSimplePresenceExtracted)
738 clearSimplePresenceInfo();
741 NodeList::const_iterator itNode = mRootNodes.begin();
742 for (; itNode != mRootNodes.end(); itNode++)
744 if ((*itNode)->mTag ==
"tuple")
747 if (itAttrib != (*itNode)->mAttributes.end())
749 SimplePresenceInfo* info =
new SimplePresenceInfo;
750 info->mTupleId = itAttrib->second;
752 NodeList::const_iterator itTupleChild = (*itNode)->mChildren.begin();
753 for (; itTupleChild != (*itNode)->mChildren.end(); itTupleChild++)
755 if ((*itTupleChild)->mTag ==
"status")
758 NodeList::const_iterator itStatusChild = (*itTupleChild)->mChildren.begin();
759 for (; itStatusChild != (*itTupleChild)->mChildren.end(); itStatusChild++)
761 if ((*itStatusChild)->mTag ==
"basic")
763 info->mOnline = (*itStatusChild)->mValue ==
"open";
768 else if (info->mContact.empty() && (*itTupleChild)->mTag ==
"contact")
770 info->mContact = (*itTupleChild)->mValue;
772 if (itAttrib != (*itTupleChild)->mAttributes.end())
774 info->mContactPriority = itAttrib->second;
777 else if (info->mNote.empty() && (*itTupleChild)->mTag ==
"note")
779 info->mNote = (*itTupleChild)->mValue;
781 else if (info->mTimestamp.empty() && (*itTupleChild)->mTag ==
"timestamp")
783 info->mTimestamp = (*itTupleChild)->mValue;
788 mSimplePresenceInfoList.push_back(info);
792 mSimplePresenceExtracted =
true;
818 if (gmtime_s(&gmt, &datetime) != 0)
826 if (gmtime_r(&datetime, &gmt) == 0)
837 ds << gmt.tm_year + 1900 <<
"-";
838 pad2(gmt.tm_mon + 1, ds);
840 pad2(gmt.tm_mday, ds);
842 pad2(gmt.tm_hour, ds);
844 pad2(gmt.tm_min, ds);
846 pad2(gmt.tm_sec, ds);
858 <<
" note=" << tuple.
mNote
static void pad2(const int x, EncodeStream &str)
static const Data BasePidfNamespaceUri("urn:ietf:params:xml:ns:pidf")
Base class for all SIP body types.
Contents & operator=(const Contents &rhs)
Assignment operator.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
bool postfix(const Data &post) const noexcept
Returns true if this Data ends with the bytes indicated by the passed-in Data.
Data & clear()
Clears the contents of this Data.
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()
std::list< Node * > NodeList
const Data & getSimplePresenceContact()
const Data & getSimplePresenceContactPriority()
void setSimplePresenceTupleNode(const Data &id, bool online, const Data ×tamp=Data::Empty, const Data ¬e=Data::Empty, const Data &contact=Data::Empty, const Data &contactPriority=Data::Empty)
const Data & getSimplePresenceTupleId()
virtual Contents * clone() const
duplicate an GenericPidfContents object
virtual void parse(ParseBuffer &pb)
static const GenericPidfContents Empty
virtual EncodeStream & encodeParsed(EncodeStream &str) const
const Data & getSimplePresenceTimestamp()
static Data generateTimestampData(time_t datetime)
const bool getSimplePresenceOnline()
const Data & getSimplePresenceNote()
static Data generateNowTimestampData()
void addNamespace(const Data &uri, const Data &prefix)
static const Data & getSubNodeValue(Node *node, const Data &tag)
const Uri & getEntity() const
void setEntity(const Uri &entity)
bool merge(const GenericPidfContents &other)
virtual ~GenericPidfContents()
iterator find(const Key &key)
List::const_iterator const_iterator
Represents the "media-type" element in the RFC 3261 grammar.
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 * COLON
static const char * Presence
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
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)
std::string strError(int err)
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)