Coverage Report

Created: 2023-09-25 06:23

/src/resiprocate/resip/stack/Pidf.cxx
Line
Count
Source (jump to first uncovered line)
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include "resip/stack/Pidf.hxx"
6
#include "resip/stack/SipMessage.hxx"
7
#include "resip/stack/Symbols.hxx"
8
#include "rutil/XMLCursor.hxx"
9
#include "rutil/Logger.hxx"
10
#include "rutil/Inserter.hxx"
11
#include "rutil/WinLeakCheck.hxx"
12
13
using namespace resip;
14
using namespace std;
15
16
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
17
18
bool
19
Pidf::init()
20
4
{
21
4
   static ContentsFactory<Pidf> factory;
22
4
   (void)factory;
23
4
   return true;
24
4
}
25
26
const Pidf Pidf::Empty;
27
28
Pidf::Pidf()
29
   : Contents(getStaticType()),
30
     mNote()
31
2
{
32
2
}
33
34
Pidf::Pidf(const Data& txt)
35
   : Contents(getStaticType()),
36
     mNote(txt)
37
0
{
38
0
}
39
40
Pidf::Pidf(const Mime& contentType)
41
   : Contents(getStaticType()),
42
     mNote()
43
0
{
44
0
}
45
46
Pidf::Pidf(const HeaderFieldValue& hfv, const Mime& contentsType)
47
   : Contents(hfv, contentsType),
48
     mNote()
49
0
{
50
0
}
51
52
Pidf::Pidf(const Data& txt, const Mime& contentType)
53
   : Contents(contentType),
54
     mNote(txt)
55
0
{
56
0
}
57
58
Pidf&
59
Pidf::operator=(const Pidf& rhs)
60
0
{
61
0
   if (this != &rhs)
62
0
   {
63
0
      Contents::operator=(rhs);
64
0
      mNote = rhs.mNote;
65
0
      mEntity = rhs.mEntity;
66
0
      mTuples = rhs.mTuples;
67
0
   }
68
0
   return *this;
69
0
}
70
 
71
Pidf::Pidf(const Pidf& rhs)
72
   : Contents(rhs),
73
     mNote(rhs.mNote),
74
     mEntity(rhs.mEntity),
75
     mTuples(rhs.mTuples)
76
0
{
77
0
}
78
79
Pidf::Pidf(const Uri& entity)
80
   : Contents(getStaticType()),
81
     mEntity(entity)
82
0
{
83
0
}
84
85
Pidf::~Pidf()
86
0
{
87
0
}
88
89
void 
90
Pidf::setEntity(const Uri& entity)
91
0
{
92
0
   checkParsed();
93
0
   mEntity = entity;
94
0
}
95
96
const Uri& 
97
Pidf::getEntity() const
98
0
{ 
99
0
   checkParsed();
100
0
   return mEntity; 
101
0
};
102
103
std::vector<Pidf::Tuple>&
104
Pidf::getTuples()
105
0
{
106
0
   checkParsed();
107
0
   return mTuples;
108
0
}
109
110
const std::vector<Pidf::Tuple>&
111
Pidf::getTuples() const
112
0
{
113
0
   checkParsed();
114
0
   return mTuples;
115
0
}
116
117
int
118
Pidf::getNumTuples() const
119
0
{
120
0
   checkParsed();
121
0
   return (int)mTuples.size();
122
0
}
123
124
Contents* 
125
Pidf::clone() const
126
0
{
127
0
   return new Pidf(*this);
128
0
}
129
130
const Mime& 
131
Pidf::getStaticType() 
132
4
{
133
4
   static Mime type("application","pidf+xml");
134
4
   return type;
135
4
}
136
137
EncodeStream& 
138
Pidf::encodeParsed(EncodeStream& str) const
139
0
{
140
0
   str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << Symbols::CRLF;
141
0
   str << "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"" << Symbols::CRLF;
142
0
   str << "          entity=\"" << mEntity << "\">"  <<  Symbols::CRLF;
143
0
   for (vector<Tuple>::const_iterator i = mTuples.begin(); i != mTuples.end(); ++i)
144
0
   {
145
0
      Data status( (char*)( (i->status) ? "open" : "closed" ) );
146
0
      str << "  <tuple id=\"" << i->id << "\" ";
147
148
0
      XMLCursor::encode(str, i->attributes);
149
0
      str << ">" << Symbols::CRLF;
150
0
      str << "     <status><basic>" << status << "</basic></status>" << Symbols::CRLF;
151
0
      if ( !i->contact.empty() )
152
0
      {
153
0
         str << "     <contact priority=\"" << i->contactPriority << "\">" << i->contact << "</contact>" << Symbols::CRLF;
154
0
      }
155
0
      if ( !i->timeStamp.empty() )
156
0
      {
157
0
         str << "     <timestamp>" << i->timeStamp << "</timestamp>" << Symbols::CRLF;
158
0
      }
159
0
      if ( !i->note.empty() )
160
0
      {
161
0
         str << "     <note>" << i->note << "</note>" << Symbols::CRLF;
162
0
      }
163
0
      str << "  </tuple>" << Symbols::CRLF;
164
0
   }
165
0
   str << "</presence>" << Symbols::CRLF;
166
167
0
   return str;
168
0
}
169
170
void
171
Pidf::parse(ParseBuffer& pb)
172
0
{
173
0
   DebugLog(<< "Pidf::parse(" << Data(pb.start(), int(pb.end()-pb.start())) << ") ");
174
175
0
   std::string pidf_namespace;
176
177
0
   XMLCursor xml(pb);
178
179
0
   XMLCursor::AttributeMap attr = xml.getAttributes();
180
0
   XMLCursor::AttributeMap::const_iterator it =
181
0
         std::find_if(attr.begin(), attr.end(), XMLCursor::AttributeValueEqual("urn:ietf:params:xml:ns:pidf"));
182
183
0
   if ( it != attr.end() ) 
184
0
   {
185
186
0
      std::string key(it->first.data(), it->first.size());
187
188
0
      size_t pos = key.find(':');
189
190
0
      if ( pos != string::npos) 
191
0
      {
192
0
         pidf_namespace.assign(key, pos+1, key.size()-pos-1);
193
0
         pidf_namespace.append(1, ':');
194
0
      }
195
0
   }
196
197
0
   const std::string presence = pidf_namespace + "presence";
198
199
0
   if (xml.getTag() == presence.c_str())
200
0
   {
201
0
      XMLCursor::AttributeMap::const_iterator i = xml.getAttributes().find("entity");
202
0
      if (i != xml.getAttributes().end())
203
0
      {
204
0
         mEntity = Uri(i->second);
205
0
      }
206
0
      else
207
0
      {
208
0
         DebugLog(<< "no entity!");
209
0
      }
210
211
0
      if (xml.firstChild())
212
0
      {
213
0
         do
214
0
         {
215
0
            const std::string tuple = pidf_namespace + "tuple";
216
0
            if (xml.getTag() == tuple.c_str())
217
0
            {
218
0
               Tuple t;
219
0
               t.attributes = xml.getAttributes();
220
0
               XMLCursor::AttributeMap::const_iterator i = xml.getAttributes().find("id");
221
0
               if (i != xml.getAttributes().end())
222
0
               {
223
0
                  t.id = i->second;
224
0
                  t.attributes.erase("id");
225
0
               }
226
227
               // look for status, contacts, notes -- take last of each for now
228
0
               if (xml.firstChild())
229
0
               {
230
0
                  do
231
0
                  {
232
0
                     const std::string status = pidf_namespace + "status";
233
0
                     const std::string contact = pidf_namespace + "contact";
234
0
                     const std::string note = pidf_namespace + "note";
235
0
                     const std::string timestamp = pidf_namespace + "timestamp";
236
0
                     if (xml.getTag() == status.c_str())
237
0
                     {
238
                        // look for basic
239
0
                        if (xml.firstChild())
240
0
                        {
241
0
                           do
242
0
                           {
243
0
                              std::string basic = pidf_namespace + "basic";
244
0
                              if (xml.getTag() == basic.c_str())
245
0
                              {
246
0
                                 if (xml.firstChild())
247
0
                                 {
248
0
                                    t.status = (xml.getValue() == "open");
249
0
                                    xml.parent();
250
0
                                 }
251
0
                              }
252
0
                           } while (xml.nextSibling());
253
0
                           xml.parent();
254
0
                        }
255
0
                     }
256
0
                     else if (xml.getTag() == contact.c_str())
257
0
                     {
258
0
                        XMLCursor::AttributeMap::const_iterator i = xml.getAttributes().find("priority");
259
0
                        if (i != xml.getAttributes().end())
260
0
                        {
261
0
                           t.contactPriority.setValue(i->second);
262
0
                        }
263
0
                        if (xml.firstChild())
264
0
                        {
265
0
                           t.contact = xml.getValue();
266
0
                           xml.parent();
267
0
                        }
268
0
                     }
269
0
                     else if (xml.getTag() == note.c_str())
270
0
                     {
271
0
                        if (xml.firstChild())
272
0
                        {
273
0
                           t.note = xml.getValue();
274
0
                           xml.parent();
275
0
                        }
276
0
                     }
277
0
                     else if (xml.getTag() == timestamp.c_str())
278
0
                     {
279
0
                        if (xml.firstChild())
280
0
                        {
281
0
                           t.timeStamp = xml.getValue();
282
0
                           xml.parent();
283
0
                        }
284
0
                     }
285
0
                  } while (xml.nextSibling());
286
0
                  xml.parent();
287
0
               }
288
               
289
0
               mTuples.push_back(t);
290
0
            }
291
0
         } while (xml.nextSibling());
292
0
         xml.parent();
293
0
      }
294
0
   }
295
0
   else
296
0
   {
297
0
      DebugLog(<< "no presence tag!");
298
0
   }
299
0
}
300
301
void 
302
Pidf::setSimpleId(const Data& id)
303
0
{
304
0
   checkParsed();
305
0
   if (mTuples.empty())
306
0
   {
307
0
      Tuple t;
308
0
      mTuples.push_back(t);
309
0
   }
310
0
   mTuples[0].id = id;
311
0
}
312
313
void 
314
Pidf::setSimpleStatus( bool online, const Data& note, const Data& contact )
315
0
{
316
0
   checkParsed();
317
0
   if (mTuples.empty())
318
0
   {
319
0
      Tuple t;
320
0
      mTuples.push_back(t);
321
0
   }
322
323
0
   mTuples[0].status = online;
324
0
   mTuples[0].contact = contact;
325
0
   mTuples[0].contactPriority = 1000;  // 1.0
326
0
   mTuples[0].note = note;
327
0
   mTuples[0].timeStamp = Data::Empty;
328
0
}
329
330
bool 
331
Pidf::getSimpleStatus(Data* note) const
332
0
{
333
0
   checkParsed();
334
335
0
   if (!mTuples.empty())
336
0
   {
337
0
      if (note)
338
0
      {
339
0
         *note = mTuples[0].note;
340
0
      }
341
   
342
0
      return mTuples[0].status;
343
0
   }
344
0
   return false;
345
0
}
346
347
void 
348
Pidf::merge(const Pidf& other)
349
0
{
350
0
   vector<Tuple>& tuples = getTuples();
351
0
   tuples.reserve(tuples.size() + other.getTuples().size());
352
353
0
   setEntity(other.mEntity);
354
355
0
   for (vector<Tuple>::const_iterator i = other.getTuples().begin();
356
0
        i != other.getTuples().end(); ++i)
357
0
   {
358
0
      bool found = false;
359
0
      for (vector<Tuple>::iterator j = getTuples().begin();
360
0
           j != getTuples().end(); ++j)
361
0
      {
362
         // TODO - only merge over if timestamp is greater
363
0
         if (i->id == j->id)
364
0
         {
365
0
            found = true;
366
0
            *j = *i;
367
0
            break;
368
0
         }
369
0
      }
370
0
      if (!found)
371
0
      {
372
0
         tuples.push_back(*i);
373
0
      }
374
0
   }
375
0
}
376
377
EncodeStream& 
378
resip::operator<<(EncodeStream& strm, const Pidf::Tuple& tuple)
379
0
{
380
0
   strm << "Tuple [" 
381
0
        << " status=" << tuple.status
382
0
        << " id=" << tuple.id
383
0
        << " contact=" << tuple.contact
384
0
        << " attributes=" << Inserter(tuple.attributes);
385
0
   return strm;
386
0
}
387
388
/* ====================================================================
389
 * The Vovida Software License, Version 1.0 
390
 * 
391
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
392
 * 
393
 * Redistribution and use in source and binary forms, with or without
394
 * modification, are permitted provided that the following conditions
395
 * are met:
396
 * 
397
 * 1. Redistributions of source code must retain the above copyright
398
 *    notice, this list of conditions and the following disclaimer.
399
 * 
400
 * 2. Redistributions in binary form must reproduce the above copyright
401
 *    notice, this list of conditions and the following disclaimer in
402
 *    the documentation and/or other materials provided with the
403
 *    distribution.
404
 * 
405
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
406
 *    and "Vovida Open Communication Application Library (VOCAL)" must
407
 *    not be used to endorse or promote products derived from this
408
 *    software without prior written permission. For written
409
 *    permission, please contact vocal@vovida.org.
410
 *
411
 * 4. Products derived from this software may not be called "VOCAL", nor
412
 *    may "VOCAL" appear in their name, without prior written
413
 *    permission of Vovida Networks, Inc.
414
 * 
415
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
416
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
417
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
418
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
419
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
420
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
421
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
422
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
423
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
424
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
425
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
426
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
427
 * DAMAGE.
428
 * 
429
 * ====================================================================
430
 * 
431
 * This software consists of voluntary contributions made by Vovida
432
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
433
 * Inc.  For more information on Vovida Networks, Inc., please see
434
 * <http://www.vovida.org/>.
435
 *
436
 */