reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
NameAddr.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
8#include "rutil/Data.hxx"
9#include "rutil/DnsUtil.hxx"
10#include "rutil/Logger.hxx"
11#include "rutil/ParseBuffer.hxx"
12//#include "rutil/WinLeakCheck.hxx" // not compatible with placement new used below
13
14using namespace resip;
15using namespace std;
16
17#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
18
19//====================
20// NameAddr:
21//====================
24 mAllContacts(false),
25 mDisplayName(),
26 mUnknownUriParametersBuffer(0)
27{}
28
30 Headers::Type type,
31 PoolBase* pool)
32 : ParserCategory(hfv, type, pool),
33 mAllContacts(false),
34 mUri(pool),
35 mDisplayName(),
36 mUnknownUriParametersBuffer(0)
37{}
38
40 PoolBase* pool)
41 : ParserCategory(rhs, pool),
42 mAllContacts(rhs.mAllContacts),
43 mUri(rhs.mUri, pool),
44 mDisplayName(rhs.mDisplayName),
45 mUnknownUriParametersBuffer(0)
46{}
47
48static const Data parseContext("NameAddr constructor");
49NameAddr::NameAddr(const Data& unparsed, bool preCacheAor)
51 mAllContacts(false),
52 mDisplayName(),
53 mUnknownUriParametersBuffer(0)
54{
55 HeaderFieldValue hfv(unparsed.data(), unparsed.size());
56 // must copy because parse creates overlays
57 NameAddr tmp(hfv, Headers::UNKNOWN);
58 tmp.checkParsed();
59 *this = tmp;
60 if(preCacheAor)
61 {
62 mUri.getAor();
63 }
64}
65
68 mAllContacts(false),
69 mUri(uri),
70 mDisplayName(),
71 mUnknownUriParametersBuffer(0)
72{}
73
81
84{
85 if (this != &rhs)
86 {
88
92 mUri = rhs.mUri;
93 }
94 return *this;
95}
96
97bool
98NameAddr::operator==(const NameAddr& other) const
99{
100 return mAllContacts == other.mAllContacts &&
101 uri() == other.uri() &&
102 displayName() == other.displayName();
103}
104
105bool
106NameAddr::operator<(const NameAddr& rhs) const
107{
108 return uri() < rhs.uri();
109}
110
113{
114 return new NameAddr(*this);
115}
116
118NameAddr::clone(void* location) const
119{
120 return new (location) NameAddr(*this);
121}
122
125{
126 return new (pool) NameAddr(*this, pool);
127}
128
129const Uri&
131{
132 checkParsed();
133 return mUri;
134}
135
136Uri&
138{
139 checkParsed();
140 return mUri;
141}
142
143Data&
145{
146 checkParsed();
147 return mDisplayName;
148}
149
150const Data&
152{
153 checkParsed();
154 return mDisplayName;
155}
156
157bool
159{
160 checkParsed();
161 return mAllContacts;
162}
163
164void
169
170void
172{
173 const char* start;
174 start = pb.skipWhitespace();
175 pb.assertNotEof();
176 bool laQuote = false;
177 bool starContact = false;
178
179 if (*pb.position() == Symbols::STAR[0])
180 {
181 pb.skipChar(Symbols::STAR[0]);
182 pb.skipWhitespace();
183 if (pb.eof() || *pb.position() == Symbols::SEMI_COLON[0])
184 {
185 starContact = true;
186 }
187 }
188
189 if (starContact)
190 {
191 mAllContacts = true;
192 // now fall through to parse header parameters
193 }
194 else
195 {
196 pb.reset(start);
197 // Check if we have a double quoted displayname
198 if (*pb.position() == Symbols::DOUBLE_QUOTE[0])
199 {
200 start = pb.skipChar(Symbols::DOUBLE_QUOTE[0]);
201 pb.skipToEndQuote();
202 pb.data(mDisplayName, start);
205 laQuote = true;
207 if (pb.eof())
208 {
209 throw ParseException("Expected '<'",
210 "NameAddr",
211 __FILE__,
212 __LINE__);
213 }
214 else
215 {
217 }
218 }
219 // Check if we have a URI without a displayname surrounded by angle brackets
220 else if (*pb.position() == Symbols::LA_QUOTE[0])
221 {
223 laQuote = true;
224 }
225 // else, we could have a URI with a displayname that is not surrounded by double quotes
226 else
227 {
228 start = pb.position();
229 // Note: An angle bracket can appear in a quoted parameter, we want to avoid matching those,
230 // so if we see a double quote before <, then we ignore the <. If the displayname
231 // itself is double quoted that would have been picked off in the first condition
232 // of this if statement.
234 if (pb.eof() || *pb.position() == Symbols::DOUBLE_QUOTE[0])
235 {
236 // We must have no displayname and a URI that is not surrounded by angle brackets
237 pb.reset(start);
238 }
239 else
240 {
241 // We have a displayname that is not surrounded by double quotes and a URI surround by angle brackets
242 laQuote = true;
244 pb.data(mDisplayName, start);
247 }
248 }
249 pb.skipWhitespace();
250 mUri.setIsBetweenAngleQuotes(laQuote); // Tell Uri parser if the Uri is between angle quotes/brackets or not, so that it can relax embedded header parsing rules if so
251 // Without brackets, header parameters (";tag=...") may follow the
252 // Uri directly with no separator; tell the parser so schemes like
253 // urn: know to stop at ';'/'?'/',' instead of swallowing them.
254 mUri.setIsBareAddrSpec(!laQuote);
255 mUri.parse(pb);
256 if (laQuote)
257 {
259 pb.skipWhitespace();
260 // now fall through to parse header parameters
261 }
262 else
263 {
264 if(mUri.mUnknownParameters.size() > 0)
265 {
268 { // Scope stream
270 // deal with Uri/NameAddr parameter ambiguity
271 // heuristically assign Uri parameters to the Uri
272 for (ParameterList::iterator it = mUri.mUnknownParameters.begin();
273 it != mUri.mUnknownParameters.end(); ++it)
274 {
275 // We're just going to assume all unknown (to Uri) params really
276 // belong on the header. This is not necessarily the case.
277 str << ";";
278 (*it)->encode(str);
279 }
280 }
283 parseParameters(pb2);
284 }
285 }
286 }
287 parseParameters(pb);
288}
289
291NameAddr::encodeParsed(EncodeStream& str) const
292{
293 //bool displayName = !mDisplayName.empty();
294 if (mAllContacts)
295 {
296 str << Symbols::STAR;
297 }
298 else
299 {
300 if (!mDisplayName.empty())
301 {
302#ifdef OMIT_DISPLAY_NAME_QUOTES_IF_NOT_REQUIRED
303 // does nothing if display name is properly quoted
305 {
306#endif
308 for (unsigned int i=0; i < mDisplayName.size(); i++)
309 {
310 char c = mDisplayName[i];
311 switch(c)
312 {
313 case '"':
314 case '\\':
315 str << '\\' << c;
316 break;
317 default:
318 str << c;
319 }
320 }
322#ifdef OMIT_DISPLAY_NAME_QUOTES_IF_NOT_REQUIRED
323 }
324 else
325 {
326 str << mDisplayName;
327 }
328#endif
329 }
330 str << Symbols::LA_QUOTE;
331 mUri.encodeParsed(str);
332 str << Symbols::RA_QUOTE;
333 }
334
335 encodeParameters(str);
336 return str;
337}
338
339
340bool
342{
343 if (mDisplayName.empty())
344 {
345 return false;
346 }
348
349 //shouldn't really be any leading whitespace
350 pb.skipWhitespace();
351 if (pb.eof())
352 {
353 return false;
354 }
355 if ((*pb.position() == '"'))
356 {
357 bool escaped = false;
358 while(!pb.eof())
359 {
360 pb.skipChar();
361 if (escaped)
362 {
363 escaped = false;
364 }
365 else if (*pb.position() == '\\')
366 {
367 escaped = true;
368 }
369 else if (*pb.position() == '"')
370 {
371 break;
372 }
373 }
374 if (*pb.position() == '"')
375 {
376 //should only have whitespace left, and really non of that
377 pb.skipChar();
378 if (pb.eof())
379 {
380 return false;
381 }
382 pb.skipWhitespace();
383 if (pb.eof())
384 {
385 return false; //properly quoted
386 }
387 else
388 {
389 return true;
390 }
391 }
392 else
393 {
394 return true; //imbalanced quotes
395 }
396 }
397 else
398 {
399 while (!pb.eof())
400 {
401 const char* start;
402 start = pb.skipWhitespace();
403 if (pb.eof())
404 {
405 return false;
406 }
408 const char* end = pb.position();
409 for (const char* c = start; c < end; c++)
410 {
411 if ( (*c >= 'a' && *c <= 'z') ||
412 (*c >= 'A' && *c <= 'Z') ||
413 (*c >= '0' && *c <= '9'))
414 {
415 continue;
416 }
417 switch(*c)
418 {
419 case '-':
420 case '.':
421 case '!':
422 case '%':
423 case '*':
424 case '_':
425 case '+':
426 case '`':
427 case '\'':
428 case '~':
429 break;
430 default:
431 return true;
432 }
433 }
434 }
435 }
436 return false;
437}
438
440{
441 if (mDisplayName.find("\\") != Data::npos)
442 {
443 // Double quotes must be encoded as \", so if displayName contains any backslashes, then we remove them
444 Data adjustedDisplayName;
445 {
446 DataStream ds(adjustedDisplayName);
447
448 for (unsigned int i = 0; i < mDisplayName.size(); i++)
449 {
450 if (mDisplayName[i] == '\\')
451 {
452 i++;
453 }
454 if (i < mDisplayName.size())
455 {
456 ds << mDisplayName[i];
457 }
458 }
459 }
460 mDisplayName = adjustedDisplayName;
461 }
462}
463
464ParameterTypes::Factory NameAddr::ParameterFactories[ParameterTypes::MAX_PARAMETER]={0};
465
466Parameter*
467NameAddr::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
468{
469 if(type > ParameterTypes::UNKNOWN && type < ParameterTypes::MAX_PARAMETER && ParameterFactories[type])
470 {
471 return ParameterFactories[type](type, pb, terminators, pool);
472 }
473 return 0;
474}
475
476bool
477NameAddr::exists(const Param<NameAddr>& paramType) const
478{
479 checkParsed();
480 bool ret = getParameterByEnum(paramType.getTypeNum()) != NULL;
481 return ret;
482}
483
484void
486{
487 checkParsed();
489}
490
491#define defineParam(_enum, _name, _type, _RFC_ref_ignored) \
492_enum##_Param::DType& \
493NameAddr::param(const _enum##_Param& paramType) \
494{ \
495 checkParsed(); \
496 _enum##_Param::Type* p = \
497 static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum())); \
498 if (!p) \
499 { \
500 p = new _enum##_Param::Type(paramType.getTypeNum()); \
501 mParameters.push_back(p); \
502 } \
503 return p->value(); \
504} \
505 \
506const _enum##_Param::DType& \
507NameAddr::param(const _enum##_Param& paramType) const \
508{ \
509 checkParsed(); \
510 _enum##_Param::Type* p = \
511 static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum())); \
512 if (!p) \
513 { \
514 InfoLog(<< "Missing parameter " _name " " << ParameterTypes::ParameterNames[paramType.getTypeNum()]); \
515 DebugLog(<< *this); \
516 throw Exception("Missing parameter " _name, __FILE__, __LINE__); \
517 } \
518 return p->value(); \
519}
520
521defineParam(data, "data", ExistsParameter, "RFC 3840");
522defineParam(control, "control", ExistsParameter, "RFC 3840");
523defineParam(mobility, "mobility", QuotedDataParameter, "RFC 3840"); // mobile|fixed
524defineParam(description, "description", QuotedDataParameter, "RFC 3840"); // <> quoted
525defineParam(events, "events", QuotedDataParameter, "RFC 3840"); // list
526defineParam(priority, "priority", QuotedDataParameter, "RFC 3840"); // non-urgent|normal|urgent|emergency
527defineParam(methods, "methods", QuotedDataParameter, "RFC 3840"); // list
528defineParam(schemes, "schemes", QuotedDataParameter, "RFC 3840"); // list
529defineParam(application, "application", ExistsParameter, "RFC 3840");
530defineParam(video, "video", ExistsParameter, "RFC 3840");
531defineParam(language, "language", QuotedDataParameter, "RFC 3840"); // list
532defineParam(type, "type", QuotedDataParameter, "RFC 3840"); // list
533defineParam(isFocus, "isfocus", ExistsParameter, "RFC 3840");
534defineParam(actor, "actor", QuotedDataParameter, "RFC 3840"); // principal|msg-taker|attendant|information
535defineParam(text, "text", ExistsOrDataParameter, "RFC 3840");
536defineParam(extensions, "extensions", QuotedDataParameter, "RFC 3840"); //list
537defineParam(Instance, "+sip.instance", QuotedDataParameter, "RFC 5626"); // <> quoted
538defineParam(regid, "reg-id", UInt32Parameter, "RFC 5626");
539defineParam(pubGruu, "pub-gruu", QuotedDataParameter, "RFC 5627");
540defineParam(tempGruu, "temp-gruu", QuotedDataParameter, "RFC 5627");
541defineParam(expires, "expires", UInt32Parameter, "RFC 3261");
542defineParam(q, "q", QValueParameter, "RFC 3261");
543defineParam(tag, "tag", DataParameter, "RFC 3261");
544defineParam(index, "index", DataParameter, "RFC 4244");
545defineParam(rc, "rc", DataParameter, "RFC 4244-bis");
546defineParam(mp, "mp", DataParameter, "RFC 4244-bis");
547defineParam(np, "np", DataParameter, "RFC 4244-bis");
548defineParam(reason, "reason", DataParameter, "RFC 5806");
549defineParam(counter, "counter", UInt32Parameter, "RFC 5806");
550defineParam(limit, "limit", UInt32Parameter, "RFC 5806");
551defineParam(privacy, "privacy", DataParameter, "RFC 5806");
552defineParam(screen, "screen", DataParameter, "RFC 5806");
553
554
555#undef defineParam
556
557/* ====================================================================
558 * The Vovida Software License, Version 1.0
559 *
560 * Copyright (c) 2024-2026, SIP Spectrum, Inc. http://www.sipspectrum.com
561 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
562 *
563 * Redistribution and use in source and binary forms, with or without
564 * modification, are permitted provided that the following conditions
565 * are met:
566 *
567 * 1. Redistributions of source code must retain the above copyright
568 * notice, this list of conditions and the following disclaimer.
569 *
570 * 2. Redistributions in binary form must reproduce the above copyright
571 * notice, this list of conditions and the following disclaimer in
572 * the documentation and/or other materials provided with the
573 * distribution.
574 *
575 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
576 * and "Vovida Open Communication Application Library (VOCAL)" must
577 * not be used to endorse or promote products derived from this
578 * software without prior written permission. For written
579 * permission, please contact vocal@vovida.org.
580 *
581 * 4. Products derived from this software may not be called "VOCAL", nor
582 * may "VOCAL" appear in their name, without prior written
583 * permission of Vovida Networks, Inc.
584 *
585 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
586 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
587 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
588 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
589 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
590 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
591 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
592 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
593 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
594 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
595 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
596 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
597 * DAMAGE.
598 *
599 * ====================================================================
600 *
601 * This software consists of voluntary contributions made by Vovida
602 * Networks, Inc. and many individuals on behalf of Vovida Networks,
603 * Inc. For more information on Vovida Networks, Inc., please see
604 * <http://www.vovida.org/>.
605 *
606 */
#define defineParam(_enum, _name, _type, _RFC_ref_ignored)
Definition Auth.cxx:239
#define resip_assert(x)
This file needs to work for both C and C++ code.
#define resip_assert_not_null(x)
Generically represents miscellaneous parameter data.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Definition Data.hxx:887
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Represents various parameters that are indicated to be in effect merely by being present,...
void checkParsed() const
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
bool operator<(const NameAddr &other) const
Definition NameAddr.cxx:106
NameAddr & operator=(const NameAddr &)
Definition NameAddr.cxx:83
bool operator==(const NameAddr &other) const
Definition NameAddr.cxx:98
bool mustQuoteDisplayName() const
Definition NameAddr.cxx:341
void remove(const Param< NameAddr > &paramType)
Definition NameAddr.cxx:485
virtual ParserCategory * clone() const
Definition NameAddr.cxx:112
void setAllContacts()
Definition NameAddr.cxx:165
Data & displayName()
Definition NameAddr.cxx:144
virtual ~NameAddr()
Definition NameAddr.cxx:74
virtual EncodeStream & encodeParsed(EncodeStream &str) const
Definition NameAddr.cxx:291
void adjustDisplayNameIfNeeded()
Definition NameAddr.cxx:439
virtual void parse(ParseBuffer &pb)
Definition NameAddr.cxx:171
bool isAllContacts() const
Definition NameAddr.cxx:158
Data * mUnknownUriParametersBuffer
Definition NameAddr.hxx:110
bool exists(const Param< NameAddr > &paramType) const
Definition NameAddr.cxx:477
virtual Parameter * createParam(ParameterTypes::Type type, ParseBuffer &pb, const std::bitset< 256 > &terminators, PoolBase *pool)
Definition NameAddr.cxx:467
virtual ParameterTypes::Type getTypeNum() const =0
Parameter *(* Factory)(ParameterTypes::Type, ParseBuffer &, const std::bitset< 256 > &terminators, PoolBase *pool)
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipNonWhitespace()
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
void reset(const char *pos)
void assertNotEof() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
const char * skipToEndQuote(char quote='"')
const char * skipBackWhitespace()
BaseException used to indicate parse failures.
Base class for all SIP grammar elements that can have parameters.
Parameter * getParameterByEnum(ParameterTypes::Type type) const
ParameterList mUnknownParameters
ParserCategory & operator=(const ParserCategory &rhs)
void removeParameterByEnum(ParameterTypes::Type type)
void parseParameters(ParseBuffer &pb)
EncodeStream & encodeParameters(EncodeStream &str) const
Encodes parameters as they should appear on the wire.
Represents the "q" parameter value of the RFC 3261 grammar.
Generically represents miscellaneous parameter data that is encoded using double quotes.
static const char * SEMI_COLON
Definition Symbols.hxx:30
static const char * LA_QUOTE
Definition Symbols.hxx:27
static const char * RA_QUOTE
Definition Symbols.hxx:28
static const char * STAR
Definition Symbols.hxx:45
static const char * DOUBLE_QUOTE
Definition Symbols.hxx:26
Generically represents unsigned 32-bit integer values conveyed by SIP parameters.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
virtual EncodeStream & encodeParsed(EncodeStream &str) const
Definition Uri.cxx:1496
Data getAor() const
Definition Uri.cxx:1095
virtual void parse(ParseBuffer &pb)
Definition Uri.cxx:1176
void setIsBareAddrSpec(bool value)
Tells the parser this URI is being parsed as a bare (unbracketed) addr-spec inside a header value (e....
Definition Uri.hxx:205
void setIsBetweenAngleQuotes(bool value)
Definition Uri.hxx:189
An ostream that operates on an existing Data.
dcm! – add UnusedChecking(_enum) below;
static const Data parseContext("PrivacyCategory constructor")
#define EncodeStream