reSIProcate/stack  9694
MessageWaitingContents.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include "resip/stack/MessageWaitingContents.hxx"
00006 #include "rutil/Logger.hxx"
00007 #include "rutil/ParseBuffer.hxx"
00008 #include "rutil/WinLeakCheck.hxx"
00009 
00010 
00011 using namespace resip;
00012 using namespace std;
00013 
00014 #define RESIPROCATE_SUBSYSTEM Subsystem::CONTENTS
00015 
00016 bool
00017 MessageWaitingContents::init()
00018 {
00019    static ContentsFactory<MessageWaitingContents> factory;
00020    (void)factory;
00021    return true;
00022 }
00023 
00024 resip::MessageWaitingContents::AccountHeader resip::mw_account;
00025 const char* MessageHeaders[MW_MAX] = {"voice-message", 
00026                                       "fax-message", 
00027                                       "pager-message", 
00028                                       "multimedia-message", 
00029                                       "text-message",
00030                                       "none"};
00031 
00032 MessageWaitingContents::MessageWaitingContents()
00033    : Contents(getStaticType()),
00034      mHasMessages(false),
00035      mAccountUri(0)
00036 {
00037    for(int i = 0; i < (int)MW_MAX; i++)
00038    {
00039       mHeaders[i] = 0;
00040    }
00041 }
00042 
00043 MessageWaitingContents::MessageWaitingContents(const HeaderFieldValue& hfv, const Mime& contentType)
00044    : Contents(hfv, contentType),
00045      mHasMessages(false),
00046      mAccountUri(0)
00047 {
00048    for(int i = 0; i < (int)MW_MAX; i++)
00049    {
00050       mHeaders[i] = 0;
00051    }
00052 }
00053 
00054 MessageWaitingContents::MessageWaitingContents(const Data& data, const Mime& contentType)
00055    : Contents(contentType),
00056      mHasMessages(false),
00057      mAccountUri(0)
00058 {
00059    for(int i = 0; i < (int)MW_MAX; i++)
00060    {
00061       mHeaders[i] = 0;
00062    }
00063    assert(0);
00064 }
00065 
00066 MessageWaitingContents::MessageWaitingContents(const MessageWaitingContents& rhs)
00067    : Contents(rhs),
00068      mHasMessages(rhs.mHasMessages),
00069      mAccountUri(rhs.mAccountUri ? new Uri(*rhs.mAccountUri) : 0),
00070      mExtensions(rhs.mExtensions)
00071 {
00072    for(int i = 0; i < (int)MW_MAX; i++)
00073    {
00074       if (rhs.mHeaders[i] != 0)
00075       {
00076          mHeaders[i] = new Header(*rhs.mHeaders[i]);
00077       }
00078       else
00079       {
00080          mHeaders[i] = 0;
00081       }
00082    }
00083 }   
00084 
00085 MessageWaitingContents::~MessageWaitingContents()
00086 {
00087    clear();
00088 }
00089 
00090 void
00091 MessageWaitingContents::clear()
00092 {
00093    mHasMessages = false;
00094 
00095    delete mAccountUri;
00096    mAccountUri = 0;
00097    
00098    for (int i = 0; i < (int)MW_MAX; i++)
00099    {
00100       delete mHeaders[i];
00101    }
00102 }
00103 
00104 MessageWaitingContents&
00105 MessageWaitingContents::operator=(const MessageWaitingContents& rhs)
00106 {
00107    if (this != &rhs)
00108    {
00109       Contents::operator=(rhs);
00110       clear();
00111 
00112       mHasMessages = rhs.mHasMessages;
00113       mAccountUri = rhs.mAccountUri ? new Uri(*rhs.mAccountUri) : 0;
00114       mExtensions = rhs.mExtensions;
00115 
00116       for(int i = 0; i < (int)MW_MAX; i++)
00117       {
00118          if (rhs.mHeaders[i] != 0)
00119          {
00120             mHeaders[i] = new Header(*rhs.mHeaders[i]);
00121          }
00122          else
00123          {
00124             mHeaders[i] = 0;
00125          }
00126       }
00127    }
00128    return *this;
00129 }
00130 
00131 const Mime& 
00132 MessageWaitingContents::getStaticType() 
00133 {
00134    static Mime type("application", "simple-message-summary");
00135    //static Mime type("text", "data");
00136    return type;
00137 }
00138 
00139 Contents*
00140 MessageWaitingContents::clone() const
00141 {
00142    return new MessageWaitingContents(*this);
00143 }
00144 
00145 EncodeStream& 
00146 MessageWaitingContents::encodeParsed(EncodeStream& s) const
00147 {
00148    s << "Messages-Waiting" << Symbols::COLON[0] << Symbols::SPACE[0]
00149      << (mHasMessages ? "yes" : "no") << Symbols::CRLF;
00150 
00151    if (exists(mw_account))
00152    {
00153       s << "Message-Account" << Symbols::COLON[0] << Symbols::SPACE[0];
00154       header(mw_account).encode(s);
00155       s << Symbols::CRLF;
00156    }
00157 
00158    for(int i = 0; i < (int)MW_MAX; i++)
00159    {
00160       if (mHeaders[i] != 0)
00161       {
00162          s << MessageHeaders[i] << Symbols::COLON[0] << Symbols::SPACE[0]
00163            << mHeaders[i]->mNew << Symbols::SLASH[0] 
00164            << mHeaders[i]->mOld;
00165 
00166          if (mHeaders[i]->mHasUrgent)
00167          {
00168             s << Symbols::SPACE[0] << Symbols::LPAREN[0]    
00169               << mHeaders[i]->mUrgentNew << Symbols::SLASH[0] 
00170               << mHeaders[i]->mUrgentOld << Symbols::RPAREN[0]; 
00171          }
00172 
00173          s << Symbols::CRLF;
00174       }
00175    }
00176 
00177    if (!mExtensions.empty())
00178    {
00179       s << Symbols::CRLF;
00180       for (map<Data, Data>::const_iterator i = mExtensions.begin();
00181            i != mExtensions.end(); i++)
00182       {
00183          s << i->first << Symbols::COLON[0] << Symbols::SPACE[0]
00184            << i->second << Symbols::CRLF;
00185       }
00186    }
00187 
00188    return s;
00189 }
00190 
00191 inline
00192 bool
00193 isWhite(char c)
00194 {
00195    switch (c)
00196    {
00197       case ' ' :
00198       case '\t' : 
00199       case '\r' : 
00200       case '\n' : 
00201          return true;
00202       default:
00203          return false;
00204    }
00205 }
00206 
00207 const char*
00208 resip::skipSipLWS(ParseBuffer& pb)
00209 {
00210    enum {WS, CR, LF, CR1};
00211 
00212    int state = WS;
00213 
00214    while (!pb.eof())
00215    {
00216       if (!isWhite(*pb.position()))
00217       {
00218          if (state == LF)
00219          {
00220             pb.reset(pb.position() - 2);
00221          }
00222          return pb.position();
00223       }
00224       if (!pb.eof())
00225       {
00226          switch (state)
00227          {
00228             case WS:
00229                if (*pb.position() == Symbols::CR[0])
00230                {
00231                   state = CR;
00232                }
00233                break;
00234             case CR:
00235                if (*pb.position() == Symbols::CR[0])
00236                {
00237                   state = CR;
00238                }
00239                else if (*pb.position() == Symbols::LF[0])
00240                {
00241                   state = LF;
00242                }
00243                else
00244                {
00245                   state = WS;
00246                }
00247                break;
00248             case LF:
00249                if (*pb.position() == Symbols::CR[0])
00250                {
00251                   state = CR1;
00252                }
00253                else if (!pb.eof() && *pb.position() == Symbols::LF[0])
00254                {
00255                   state = WS;
00256                }
00257                break;
00258             case CR1:
00259                if (*pb.position() == Symbols::CR[0])
00260                {
00261                   state = CR;
00262                }
00263                else if (*pb.position() == Symbols::LF[0])
00264                {
00265                   pb.reset(pb.position() - 3);
00266                   return pb.position();
00267                }
00268                else
00269                {
00270                   state = WS;
00271                }
00272                break;
00273             default:
00274                assert(false);
00275          }
00276       }
00277       pb.skipChar();
00278    }
00279 
00280    if (state == LF)
00281    {
00282       pb.reset(pb.position() - 2);
00283    }
00284    return pb.position();
00285 }
00286 
00287 void
00288 MessageWaitingContents::parse(ParseBuffer& pb)
00289 {
00290    pb.skipChars("Messages-Waiting");
00291    pb.skipWhitespace();
00292    pb.skipChar(Symbols::COLON[0]);
00293    const char* anchor = pb.skipWhitespace();
00294    pb.skipNonWhitespace();
00295    
00296    Data has;
00297    pb.data(has, anchor);
00298    if (isEqualNoCase(has, "yes"))
00299    {
00300       mHasMessages = true;
00301    }
00302    else if (isEqualNoCase(has, "no"))
00303    {
00304       mHasMessages = false;
00305    }
00306    else
00307    {
00308       pb.fail(__FILE__, __LINE__);
00309    }
00310 
00311    anchor = pb.skipWhitespace();
00312    if (pb.eof())
00313    {
00314       return;
00315    }
00316 
00317    Data accountHeader;
00318    pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::COLON);
00319    pb.data(accountHeader, anchor);
00320    static const Data AccountMessage("message-account");
00321    if (isEqualNoCase(accountHeader, AccountMessage))
00322    {
00323       pb.skipWhitespace();
00324       pb.skipChar(Symbols::COLON[0]);
00325       pb.skipWhitespace();
00326       
00327       mAccountUri = new Uri();
00328       mAccountUri->parse(pb);
00329       pb.skipChars(Symbols::CRLF);
00330    }
00331    else
00332    {
00333       pb.reset(anchor);
00334    }
00335 
00336    while (!pb.eof() && *pb.position() != Symbols::CR[0])
00337    {
00338       int ht = -1;
00339       switch (tolower(*pb.position()))
00340       {
00341          case 'v' :
00342             ht = mw_voice;
00343             break;
00344          case 'f' :
00345             ht = mw_fax;
00346             break;
00347          case 'p' :
00348             ht = mw_pager;
00349             break;
00350          case 'm' :
00351             ht = mw_multimedia;
00352             break;
00353          case 't' :
00354             ht = mw_text;
00355             break;
00356          case 'n' :
00357             ht = mw_none;
00358             break;
00359          default :
00360             pb.fail(__FILE__, __LINE__);
00361       }
00362       assert(ht != -1);
00363 
00364       pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::COLON);
00365       pb.skipWhitespace();
00366       pb.skipChar(Symbols::COLON[0]);
00367       pb.skipWhitespace();
00368 
00369       unsigned int numNew = pb.integer();
00370       pb.skipWhitespace();
00371       pb.skipChar(Symbols::SLASH[0]);
00372       pb.skipWhitespace();
00373 
00374       unsigned int numOld = pb.integer();
00375       skipSipLWS(pb);
00376 
00377       if (!pb.eof() && *pb.position() != Symbols::LPAREN[0])
00378       {
00379          if (mHeaders[ht] != 0)
00380          {
00381             pb.fail(__FILE__, __LINE__);
00382          }
00383          mHeaders[ht] = new Header(numNew, numOld);
00384       }
00385       else
00386       {
00387          pb.skipChar();
00388          pb.skipWhitespace();
00389 
00390          unsigned int numUrgentNew = pb.integer();
00391          pb.skipWhitespace();
00392          pb.skipChar(Symbols::SLASH[0]);
00393          pb.skipWhitespace();
00394 
00395          unsigned int numUrgentOld = pb.integer();
00396          pb.skipWhitespace();
00397          pb.skipChar(Symbols::RPAREN[0]);
00398          // skip LWS as specified in rfc3261
00399          skipSipLWS(pb);
00400 
00401          if (mHeaders[ht] != 0)
00402          {
00403             pb.fail(__FILE__, __LINE__);
00404          }
00405          mHeaders[ht] = new Header(numNew, numOld, numUrgentNew, numUrgentOld);
00406       }
00407       
00408       pb.skipChars(Symbols::CRLF);
00409    }
00410 
00411    if (!pb.eof() && *pb.position() == Symbols::CR[0])
00412    {
00413       pb.skipChars(Symbols::CRLF);
00414       
00415       while (!pb.eof())
00416       {
00417          anchor = pb.position();
00418          Data header;
00419          pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::COLON);
00420          pb.data(header, anchor);
00421 
00422          pb.skipWhitespace();
00423          pb.skipChar(Symbols::COLON[0]);
00424          anchor = pb.skipWhitespace();
00425 
00426          while (true)
00427          {
00428             // CodeWarrior isn't helpful enough to pick the "obvious" operator definition
00429             // so we add volatile here so CW is completely unconfused what to do.
00430             const volatile char* pos = pb.skipToChar(Symbols::CR[0]);
00431             skipSipLWS(pb);
00432             if (pb.position() == pos)
00433             {
00434                Data content;
00435                pb.data(content, anchor);
00436                mExtensions[header] = content;
00437 
00438                pb.skipChars(Symbols::CRLF);
00439                break;
00440             }
00441          }
00442       }
00443    }
00444 }
00445 
00446 MessageWaitingContents::Header::Header(unsigned int numNew,
00447                                        unsigned int numOld)
00448    : mNew(numNew),
00449      mOld(numOld),
00450      mHasUrgent(false),
00451      mUrgentNew(0),
00452      mUrgentOld(0)
00453 {}
00454 
00455 MessageWaitingContents::Header::Header(unsigned int numNew,
00456                                        unsigned int numOld,
00457                                        unsigned int numUrgentNew,
00458                                        unsigned int numUrgentOld)
00459    : mNew(numNew),
00460      mOld(numOld),
00461      mHasUrgent(true),
00462      mUrgentNew(numUrgentNew),
00463      mUrgentOld(numUrgentOld)
00464 {}
00465 
00466 MessageWaitingContents::Header& 
00467 MessageWaitingContents::header(HeaderType ht)
00468 {
00469    checkParsed();
00470 
00471    /* this is a trick to allow a const method to update "this" with an empty
00472       Header in case there wasn't a corresponding header line in the MessageWaiting doc
00473     */
00474    if (mHeaders[ht] == 0)
00475    {
00476       mHeaders[ht] = new Header(0, 0);
00477    }
00478    return *mHeaders[ht];
00479 }
00480 
00481 const MessageWaitingContents::Header& 
00482 MessageWaitingContents::header(HeaderType ht) const
00483 {
00484    checkParsed();
00485 
00486    /* this is a trick to allow a const method to update "this" with an empty
00487       Header in case there wasn't a corresponding header line in the MessageWaiting doc
00488     */
00489    if (mHeaders[ht] == 0)
00490    {
00491       ErrLog(<< "You called "
00492             "MessageWaitingContents::header(HeaderType ht) _const_ "
00493             "without first calling exists(), and the header does not exist. Our"
00494             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00495             "this is probably not what you want, but it is either this or "
00496             "assert/throw an exception. Since this has been the behavior for "
00497             "so long, we are not throwing here, _yet_. You need to fix your "
00498             "code, before we _do_ start throwing. This is why const-correctness"
00499             " should never be made a TODO item </rant>");
00500       MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
00501       ncthis->mHeaders[ht] = new Header(0, 0);
00502    }
00503    return *mHeaders[ht];
00504 }
00505 
00506 bool 
00507 MessageWaitingContents::exists(HeaderType ht) const
00508 {
00509    checkParsed();
00510    return mHeaders[ht] != 0;
00511 }
00512 
00513 void
00514 MessageWaitingContents::remove(HeaderType ht)
00515 {
00516    checkParsed();
00517    delete mHeaders[ht];
00518    mHeaders[ht] = 0;
00519 }
00520 
00521 Uri& 
00522 MessageWaitingContents::header(const AccountHeader& ht)
00523 {
00524    checkParsed();
00525 
00526    /* this is a trick to allow a const method to update "this" with an empty
00527       Uri in case there wasn't a Message-Account line in the MessageWaiting doc
00528     */
00529    if (mAccountUri == 0)
00530    {
00531       mAccountUri = new Uri();
00532    }
00533    return *mAccountUri;
00534 }
00535 
00536 const Uri& 
00537 MessageWaitingContents::header(const AccountHeader& ht) const
00538 {
00539    checkParsed();
00540 
00541    /* this is a trick to allow a const method to update "this" with an empty
00542       Uri in case there wasn't a Message-Account line in the MessageWaiting doc
00543     */
00544    if (mAccountUri == 0)
00545    {
00546       ErrLog(<< "You called "
00547             "MessageWaitingContents::header(const AccountHeader& ht) _const_ "
00548             "without first calling exists(), and the header does not exist. Our"
00549             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00550             "this is probably not what you want, but it is either this or "
00551             "assert/throw an exception. Since this has been the behavior for "
00552             "so long, we are not throwing here, _yet_. You need to fix your "
00553             "code, before we _do_ start throwing. This is why const-correctness"
00554             " should never be made a TODO item </rant>");
00555       MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
00556       ncthis->mAccountUri = new Uri();
00557    }
00558    return *mAccountUri;
00559 }
00560 
00561 bool 
00562 MessageWaitingContents::exists(const AccountHeader& ht) const
00563 {
00564    checkParsed();
00565    return mAccountUri != 0;
00566 }
00567 
00568 void
00569 MessageWaitingContents::remove(const AccountHeader& ht)
00570 {
00571    checkParsed();
00572    delete mAccountUri;
00573    mAccountUri = 0;
00574 }
00575 
00576 Data&
00577 MessageWaitingContents::header(const Data& hn)
00578 {
00579    checkParsed();
00580    return mExtensions[hn];
00581 }
00582 
00583 const Data&
00584 MessageWaitingContents::header(const Data& hn) const
00585 {
00586    checkParsed();
00587    std::map<Data, Data>::const_iterator h=mExtensions.find(hn);
00588    if(h==mExtensions.end())
00589    {
00590       ErrLog(<< "You called "
00591             "MessageWaitingContents::header(const Data& hn) _const_ "
00592             "without first calling exists(), and the header does not exist. Our"
00593             " behavior in this scenario is to implicitly create the header(using const_cast!); "
00594             "this is probably not what you want, but it is either this or "
00595             "assert/throw an exception. Since this has been the behavior for "
00596             "so long, we are not throwing here, _yet_. You need to fix your "
00597             "code, before we _do_ start throwing. This is why const-correctness"
00598             " should never be made a TODO item </rant>");
00599       MessageWaitingContents* ncthis = const_cast<MessageWaitingContents*>(this);
00600       h=ncthis->mExtensions.insert(std::make_pair<Data, Data>(hn,Data::Empty)).first;
00601    }
00602    return h->second;
00603 }
00604 
00605 bool
00606 MessageWaitingContents::exists(const Data& hn) const
00607 {
00608    checkParsed();
00609    return mExtensions.find(hn) != mExtensions.end();
00610 }
00611 
00612 void
00613 MessageWaitingContents::remove(const Data& hn)
00614 {
00615    checkParsed();
00616    mExtensions.erase(hn);
00617 }
00618 
00619 /* ====================================================================
00620  * The Vovida Software License, Version 1.0 
00621  * 
00622  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00623  * 
00624  * Redistribution and use in source and binary forms, with or without
00625  * modification, are permitted provided that the following conditions
00626  * are met:
00627  * 
00628  * 1. Redistributions of source code must retain the above copyright
00629  *    notice, this list of conditions and the following disclaimer.
00630  * 
00631  * 2. Redistributions in binary form must reproduce the above copyright
00632  *    notice, this list of conditions and the following disclaimer in
00633  *    the documentation and/or other materials provided with the
00634  *    distribution.
00635  * 
00636  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00637  *    and "Vovida Open Communication Application Library (VOCAL)" must
00638  *    not be used to endorse or promote products derived from this
00639  *    software without prior written permission. For written
00640  *    permission, please contact vocal@vovida.org.
00641  *
00642  * 4. Products derived from this software may not be called "VOCAL", nor
00643  *    may "VOCAL" appear in their name, without prior written
00644  *    permission of Vovida Networks, Inc.
00645  * 
00646  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00647  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00648  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00649  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00650  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00651  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00652  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00653  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00654  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00655  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00656  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00657  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00658  * DAMAGE.
00659  * 
00660  * ====================================================================
00661  * 
00662  * This software consists of voluntary contributions made by Vovida
00663  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00664  * Inc.  For more information on Vovida Networks, Inc., please see
00665  * <http://www.vovida.org/>.
00666  *
00667  */