Coverage Report

Created: 2024-07-23 06:39

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