|
reSIProcate/stack
9694
|
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 */
1.7.5.1