/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 | | */ |