reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
MessageWaitingContents.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <ctype.h>
6
8#include "rutil/Logger.hxx"
11
12
13using namespace resip;
14using namespace std;
15
16#define RESIPROCATE_SUBSYSTEM Subsystem::CONTENTS
17
18bool
20{
22 (void)factory;
23 return true;
24}
25
27const char* MessageHeaders[MW_MAX] = {"voice-message",
28 "fax-message",
29 "pager-message",
30 "multimedia-message",
31 "text-message",
32 "none"};
33
35 : Contents(getStaticType()),
36 mHasMessages(false),
37 mAccountUri(0)
38{
39 for(int i = 0; i < (int)MW_MAX; i++)
40 {
41 mHeaders[i] = 0;
42 }
43}
44
46 : Contents(hfv, contentType),
47 mHasMessages(false),
48 mAccountUri(0)
49{
50 for(int i = 0; i < (int)MW_MAX; i++)
51 {
52 mHeaders[i] = 0;
53 }
54}
55
57 : Contents(contentType),
58 mHasMessages(false),
59 mAccountUri(0)
60{
61 for(int i = 0; i < (int)MW_MAX; i++)
62 {
63 mHeaders[i] = 0;
64 }
65 resip_assert(0);
66}
67
69 : Contents(rhs),
70 mHasMessages(rhs.mHasMessages),
71 mAccountUri(rhs.mAccountUri ? new Uri(*rhs.mAccountUri) : 0),
72 mExtensions(rhs.mExtensions)
73{
74 for(int i = 0; i < (int)MW_MAX; i++)
75 {
76 if (rhs.mHeaders[i] != 0)
77 {
78 mHeaders[i] = new Header(*rhs.mHeaders[i]);
79 }
80 else
81 {
82 mHeaders[i] = 0;
83 }
84 }
85}
86
91
92void
93MessageWaitingContents::clear()
94{
95 mHasMessages = false;
96
97 delete mAccountUri;
98 mAccountUri = 0;
99
100 for (int i = 0; i < (int)MW_MAX; i++)
101 {
102 delete mHeaders[i];
103 }
104}
105
108{
109 if (this != &rhs)
110 {
112 clear();
113
114 mHasMessages = rhs.mHasMessages;
115 mAccountUri = rhs.mAccountUri ? new Uri(*rhs.mAccountUri) : 0;
116 mExtensions = rhs.mExtensions;
117
118 for(int i = 0; i < (int)MW_MAX; i++)
119 {
120 if (rhs.mHeaders[i] != 0)
121 {
122 mHeaders[i] = new Header(*rhs.mHeaders[i]);
123 }
124 else
125 {
126 mHeaders[i] = 0;
127 }
128 }
129 }
130 return *this;
131}
132
133const Mime&
135{
136 static Mime type("application", "simple-message-summary");
137 //static Mime type("text", "data");
138 return type;
139}
140
143{
144 return new MessageWaitingContents(*this);
145}
146
149{
150 s << "Messages-Waiting" << Symbols::COLON[0] << Symbols::SPACE[0]
151 << (mHasMessages ? "yes" : "no") << Symbols::CRLF;
152
153 if (exists(mw_account))
154 {
155 s << "Message-Account" << Symbols::COLON[0] << Symbols::SPACE[0];
156 header(mw_account).encode(s);
157 s << Symbols::CRLF;
158 }
159
160 for(int i = 0; i < (int)MW_MAX; i++)
161 {
162 if (mHeaders[i] != 0)
163 {
165 << mHeaders[i]->mNew << Symbols::SLASH[0]
166 << mHeaders[i]->mOld;
167
168 if (mHeaders[i]->mHasUrgent)
169 {
170 s << Symbols::SPACE[0] << Symbols::LPAREN[0]
171 << mHeaders[i]->mUrgentNew << Symbols::SLASH[0]
172 << mHeaders[i]->mUrgentOld << Symbols::RPAREN[0];
173 }
174
175 s << Symbols::CRLF;
176 }
177 }
178
179 if (!mExtensions.empty())
180 {
181 s << Symbols::CRLF;
182 for (map<Data, Data>::const_iterator i = mExtensions.begin();
183 i != mExtensions.end(); i++)
184 {
185 s << i->first << Symbols::COLON[0] << Symbols::SPACE[0]
186 << i->second << Symbols::CRLF;
187 }
188 }
189
190 return s;
191}
192
193inline
194bool
195isWhite(char c)
196{
197 switch (c)
198 {
199 case ' ' :
200 case '\t' :
201 case '\r' :
202 case '\n' :
203 return true;
204 default:
205 return false;
206 }
207}
208
209const char*
211{
212 enum {WS, CR, LF, CR1};
213
214 int state = WS;
215
216 while (!pb.eof())
217 {
218 if (!isWhite(*pb.position()))
219 {
220 if (state == LF)
221 {
222 pb.reset(pb.position() - 2);
223 }
224 return pb.position();
225 }
226 if (!pb.eof())
227 {
228 switch (state)
229 {
230 case WS:
231 if (*pb.position() == Symbols::CR[0])
232 {
233 state = CR;
234 }
235 break;
236 case CR:
237 if (*pb.position() == Symbols::CR[0])
238 {
239 state = CR;
240 }
241 else if (*pb.position() == Symbols::LF[0])
242 {
243 state = LF;
244 }
245 else
246 {
247 state = WS;
248 }
249 break;
250 case LF:
251 if (*pb.position() == Symbols::CR[0])
252 {
253 state = CR1;
254 }
255 else if (!pb.eof() && *pb.position() == Symbols::LF[0])
256 {
257 state = WS;
258 }
259 break;
260 case CR1:
261 if (*pb.position() == Symbols::CR[0])
262 {
263 state = CR;
264 }
265 else if (*pb.position() == Symbols::LF[0])
266 {
267 pb.reset(pb.position() - 3);
268 return pb.position();
269 }
270 else
271 {
272 state = WS;
273 }
274 break;
275 default:
276 resip_assert(false);
277 }
278 }
279 pb.skipChar();
280 }
281
282 if (state == LF)
283 {
284 pb.reset(pb.position() - 2);
285 }
286 return pb.position();
287}
288
289void
291{
292 pb.skipChars("Messages-Waiting");
293 pb.skipWhitespace();
295 const char* anchor = pb.skipWhitespace();
297
298 Data has;
299 pb.data(has, anchor);
300 if (isEqualNoCase(has, "yes"))
301 {
302 mHasMessages = true;
303 }
304 else if (isEqualNoCase(has, "no"))
305 {
306 mHasMessages = false;
307 }
308 else
309 {
310 pb.fail(__FILE__, __LINE__);
311 }
312
313 anchor = pb.skipWhitespace();
314 if (pb.eof())
315 {
316 return;
317 }
318
319 Data accountHeader;
321 pb.data(accountHeader, anchor);
322 static const Data AccountMessage("message-account");
323 if (isEqualNoCase(accountHeader, AccountMessage))
324 {
325 pb.skipWhitespace();
327 pb.skipWhitespace();
328
329 mAccountUri = new Uri();
330 mAccountUri->parse(pb);
332 }
333 else
334 {
335 pb.reset(anchor);
336 }
337
338 while (!pb.eof() && *pb.position() != Symbols::CR[0])
339 {
340 int ht = -1;
341 switch (tolower(static_cast< unsigned char >(*pb.position())))
342 {
343 case 'v' :
344 ht = mw_voice;
345 break;
346 case 'f' :
347 ht = mw_fax;
348 break;
349 case 'p' :
350 ht = mw_pager;
351 break;
352 case 'm' :
353 ht = mw_multimedia;
354 break;
355 case 't' :
356 ht = mw_text;
357 break;
358 case 'n' :
359 ht = mw_none;
360 break;
361 default :
362 pb.fail(__FILE__, __LINE__);
363 }
364 resip_assert(ht != -1);
365
367 pb.skipWhitespace();
369 pb.skipWhitespace();
370
371 unsigned int numNew = pb.integer();
372 pb.skipWhitespace();
374 pb.skipWhitespace();
375
376 unsigned int numOld = pb.integer();
377 skipSipLWS(pb);
378
379 if (!pb.eof() && *pb.position() != Symbols::LPAREN[0])
380 {
381 if (mHeaders[ht] != 0)
382 {
383 pb.fail(__FILE__, __LINE__);
384 }
385 mHeaders[ht] = new Header(numNew, numOld);
386 }
387 else
388 {
389 pb.skipChar();
390 pb.skipWhitespace();
391
392 unsigned int numUrgentNew = pb.integer();
393 pb.skipWhitespace();
395 pb.skipWhitespace();
396
397 unsigned int numUrgentOld = pb.integer();
398 pb.skipWhitespace();
400 // skip LWS as specified in rfc3261
401 skipSipLWS(pb);
402
403 if (mHeaders[ht] != 0)
404 {
405 pb.fail(__FILE__, __LINE__);
406 }
407 mHeaders[ht] = new Header(numNew, numOld, numUrgentNew, numUrgentOld);
408 }
409
411 }
412
413 if (!pb.eof() && *pb.position() == Symbols::CR[0])
414 {
416
417 while (!pb.eof())
418 {
419 anchor = pb.position();
420 Data header;
422 pb.data(header, anchor);
423
424 pb.skipWhitespace();
426 anchor = pb.skipWhitespace();
427
428 while (true)
429 {
430 // CodeWarrior isn't helpful enough to pick the "obvious" operator definition
431 // so we add volatile here so CW is completely unconfused what to do.
432 const volatile char* pos = pb.skipToChar(Symbols::CR[0]);
433 skipSipLWS(pb);
434 if (pb.position() == pos)
435 {
436 Data content;
437 pb.data(content, anchor);
438 mExtensions[header] = content;
439
441 break;
442 }
443 }
444 }
445 }
446}
447
449 unsigned int numOld)
450 : mNew(numNew),
451 mOld(numOld),
452 mHasUrgent(false),
453 mUrgentNew(0),
454 mUrgentOld(0)
455{}
456
458 unsigned int numOld,
459 unsigned int numUrgentNew,
460 unsigned int numUrgentOld)
461 : mNew(numNew),
462 mOld(numOld),
463 mHasUrgent(true),
464 mUrgentNew(numUrgentNew),
465 mUrgentOld(numUrgentOld)
466{}
467
470{
471 checkParsed();
472
473 /* this is a trick to allow a const method to update "this" with an empty
474 Header in case there wasn't a corresponding header line in the MessageWaiting doc
475 */
476 if (mHeaders[ht] == 0)
477 {
478 mHeaders[ht] = new Header(0, 0);
479 }
480 return *mHeaders[ht];
481}
482
485{
486 checkParsed();
487
488 /* this is a trick to allow a const method to update "this" with an empty
489 Header in case there wasn't a corresponding header line in the MessageWaiting doc
490 */
491 if (mHeaders[ht] == 0)
492 {
493 ErrLog(<< "You called "
494 "MessageWaitingContents::header(HeaderType ht) _const_ "
495 "without first calling exists(), and the header does not exist. Our"
496 " behavior in this scenario is to implicitly create the header(using const_cast!); "
497 "this is probably not what you want, but it is either this or "
498 "assert/throw an exception. Since this has been the behavior for "
499 "so long, we are not throwing here, _yet_. You need to fix your "
500 "code, before we _do_ start throwing. This is why const-correctness"
501 " should never be made a TODO item </rant>");
502 MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
503 ncthis->mHeaders[ht] = new Header(0, 0);
504 }
505 return *mHeaders[ht];
506}
507
508bool
510{
511 checkParsed();
512 return mHeaders[ht] != 0;
513}
514
515void
517{
518 checkParsed();
519 delete mHeaders[ht];
520 mHeaders[ht] = 0;
521}
522
523Uri&
525{
526 checkParsed();
527
528 /* this is a trick to allow a const method to update "this" with an empty
529 Uri in case there wasn't a Message-Account line in the MessageWaiting doc
530 */
531 if (mAccountUri == 0)
532 {
533 mAccountUri = new Uri();
534 }
535 return *mAccountUri;
536}
537
538const Uri&
540{
541 checkParsed();
542
543 /* this is a trick to allow a const method to update "this" with an empty
544 Uri in case there wasn't a Message-Account line in the MessageWaiting doc
545 */
546 if (mAccountUri == 0)
547 {
548 ErrLog(<< "You called "
549 "MessageWaitingContents::header(const AccountHeader& ht) _const_ "
550 "without first calling exists(), and the header does not exist. Our"
551 " behavior in this scenario is to implicitly create the header(using const_cast!); "
552 "this is probably not what you want, but it is either this or "
553 "assert/throw an exception. Since this has been the behavior for "
554 "so long, we are not throwing here, _yet_. You need to fix your "
555 "code, before we _do_ start throwing. This is why const-correctness"
556 " should never be made a TODO item </rant>");
557 MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
558 ncthis->mAccountUri = new Uri();
559 }
560 return *mAccountUri;
561}
562
563bool
565{
566 checkParsed();
567 return mAccountUri != 0;
568}
569
570void
572{
573 checkParsed();
574 delete mAccountUri;
575 mAccountUri = 0;
576}
577
578Data&
580{
581 checkParsed();
582 return mExtensions[hn];
583}
584
585const Data&
587{
588 checkParsed();
589 std::map<Data, Data>::const_iterator h=mExtensions.find(hn);
590 if(h==mExtensions.end())
591 {
592 ErrLog(<< "You called "
593 "MessageWaitingContents::header(const Data& hn) _const_ "
594 "without first calling exists(), and the header does not exist. Our"
595 " behavior in this scenario is to implicitly create the header(using const_cast!); "
596 "this is probably not what you want, but it is either this or "
597 "assert/throw an exception. Since this has been the behavior for "
598 "so long, we are not throwing here, _yet_. You need to fix your "
599 "code, before we _do_ start throwing. This is why const-correctness"
600 " should never be made a TODO item </rant>");
601 MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
602 h=ncthis->mExtensions.insert(std::make_pair(hn,Data::Empty)).first;
603 }
604 return h->second;
605}
606
607bool
609{
610 checkParsed();
611 return mExtensions.find(hn) != mExtensions.end();
612}
613
614void
616{
617 checkParsed();
618 mExtensions.erase(hn);
619}
620
621/* ====================================================================
622 * The Vovida Software License, Version 1.0
623 *
624 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
625 *
626 * Redistribution and use in source and binary forms, with or without
627 * modification, are permitted provided that the following conditions
628 * are met:
629 *
630 * 1. Redistributions of source code must retain the above copyright
631 * notice, this list of conditions and the following disclaimer.
632 *
633 * 2. Redistributions in binary form must reproduce the above copyright
634 * notice, this list of conditions and the following disclaimer in
635 * the documentation and/or other materials provided with the
636 * distribution.
637 *
638 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
639 * and "Vovida Open Communication Application Library (VOCAL)" must
640 * not be used to endorse or promote products derived from this
641 * software without prior written permission. For written
642 * permission, please contact vocal@vovida.org.
643 *
644 * 4. Products derived from this software may not be called "VOCAL", nor
645 * may "VOCAL" appear in their name, without prior written
646 * permission of Vovida Networks, Inc.
647 *
648 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
649 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
650 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
651 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
652 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
653 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
654 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
655 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
656 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
657 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
658 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
659 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
660 * DAMAGE.
661 *
662 * ====================================================================
663 *
664 * This software consists of voluntary contributions made by Vovida
665 * Networks, Inc. and many individuals on behalf of Vovida Networks,
666 * Inc. For more information on Vovida Networks, Inc., please see
667 * <http://www.vovida.org/>.
668 *
669 */
#define ErrLog(args_)
Definition Logger.hxx:137
const char * MessageHeaders[MW_MAX]
bool isWhite(char c)
#define resip_assert(x)
This file needs to work for both C and C++ code.
Base class for all SIP body types.
Definition Contents.hxx:51
Contents & operator=(const Contents &rhs)
Assignment operator.
Definition Contents.cxx:71
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
void checkParsed() const
makes accessing the MessageAccount Uri operate like accessing the other MessageWaiting headers.
Provides an interface for reading and modifying MessageWaiting bodies.
Header(unsigned int numNew, unsigned int numOld)
Header constructor.
SIP body type for holding MWI contents (MIME content-type application/simple-message-summary).
virtual EncodeStream & encodeParsed(EncodeStream &str) const
bool exists(HeaderType ht) const
Check if HeaderType is present.
virtual Contents * clone() const
duplicate an MessageWaitingContents object
Header & header(HeaderType ht)
Get the header correspoding to ht.
void remove(HeaderType ht)
Remove the header correspoding to ht.
virtual void parse(ParseBuffer &pb)
MessageWaitingContents & operator=(const MessageWaitingContents &rhs)
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
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)
CurrentPosition skipChars(const char *cs)
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void fail(const char *file, unsigned int line, const Data &errmsg=Data::Empty) const
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
static const char * Whitespace
static const char * LF
Definition Symbols.hxx:24
static const char * RPAREN
Definition Symbols.hxx:38
static const char * LPAREN
Definition Symbols.hxx:37
static const char * SPACE
Definition Symbols.hxx:34
static const char * COLON
Definition Symbols.hxx:15
static const char * CR
Definition Symbols.hxx:23
static const char * SLASH
Definition Symbols.hxx:32
static const char * CRLF
Definition Symbols.hxx:21
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
virtual void parse(ParseBuffer &pb)
Definition Uri.cxx:1176
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
MessageWaitingContents::AccountHeader mw_account
Used to access the Message-Account header in MessageWaiting docs.
const char * skipSipLWS(ParseBuffer &pb)
HeaderType
An enumeration of MessageWaiting header types for use with resip::MessageWaitingContents.
#define EncodeStream