/[resiprocate]/main/sip/resiprocate/SipMessage.cxx
ViewVC logotype

Contents of /main/sip/resiprocate/SipMessage.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4601 - (show annotations) (download)
Thu May 12 01:10:49 2005 UTC (14 years, 6 months ago) by derek
File size: 44490 byte(s)
merged identity branch(4598) into main--removing identity branch after this
1 #if defined(HAVE_CONFIG_H)
2 #include "resiprocate/config.hxx"
3 #endif
4
5 #include "resiprocate/Contents.hxx"
6 #include "resiprocate/OctetContents.hxx"
7 #include "resiprocate/HeaderFieldValueList.hxx"
8 #include "resiprocate/SipMessage.hxx"
9 #include "resiprocate/ExtensionHeader.hxx"
10 #include "resiprocate/os/Coders.hxx"
11 #include "resiprocate/os/CountStream.hxx"
12 #include "resiprocate/os/Logger.hxx"
13 #include "resiprocate/os/MD5Stream.hxx"
14 #include "resiprocate/os/compat.hxx"
15 #include "resiprocate/os/vmd5.hxx"
16 #include "resiprocate/os/Coders.hxx"
17 #include "resiprocate/os/Random.hxx"
18 #include "resiprocate/os/ParseBuffer.hxx"
19 #include "resiprocate/MsgHeaderScanner.hxx"
20 #include "resiprocate/os/WinLeakCheck.hxx"
21
22 using namespace resip;
23 using namespace std;
24
25 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
26
27 SipMessage::SipMessage(const Transport* fromWire)
28 : mIsExternal(fromWire != 0),
29 mTransport(fromWire),
30 mStartLine(0),
31 mContentsHfv(0),
32 mContents(0),
33 mRFC2543TransactionId(),
34 mRequest(false),
35 mResponse(false),
36 mCreatedTime(Timer::getTimeMicroSec()),
37 mForceTarget(0),
38 mTlsDomain(Data::Empty)
39 {
40 for (int i = 0; i < Headers::MAX_HEADERS; i++)
41 {
42 mHeaders[i] = 0;
43 }
44 }
45
46 SipMessage::SipMessage(const SipMessage& from)
47 : mStartLine(0),
48 mContentsHfv(0),
49 mContents(0),
50 mCreatedTime(Timer::getTimeMicroSec()),
51 mForceTarget(0)
52 {
53 for (int i = 0; i < Headers::MAX_HEADERS; i++)
54 {
55 mHeaders[i] = 0;
56 }
57
58 *this = from;
59 }
60
61 Message*
62 SipMessage::clone() const
63 {
64 return new SipMessage(*this);
65 }
66
67 SipMessage&
68 SipMessage::operator=(const SipMessage& rhs)
69 {
70 if (this != &rhs)
71 {
72 this->cleanUp();
73
74 mIsExternal = rhs.mIsExternal;
75 mTransport = rhs.mTransport;
76 mSource = rhs.mSource;
77 mDestination = rhs.mDestination;
78 mStartLine = 0;
79 mContentsHfv = 0;
80 mContents = 0;
81 mRFC2543TransactionId = rhs.mRFC2543TransactionId;
82 mRequest = rhs.mRequest;
83 mResponse = rhs.mResponse;
84 mForceTarget = 0;
85 mTlsDomain = rhs.mTlsDomain;
86
87 for (int i = 0; i < Headers::MAX_HEADERS; i++)
88 {
89 if (rhs.mHeaders[i] != 0)
90 {
91 mHeaders[i] = new HeaderFieldValueList(*rhs.mHeaders[i]);
92 }
93 else
94 {
95 mHeaders[i] = 0;
96 }
97 }
98
99 for (UnknownHeaders::const_iterator i = rhs.mUnknownHeaders.begin();
100 i != rhs.mUnknownHeaders.end(); i++)
101 {
102 mUnknownHeaders.push_back(pair<Data, HeaderFieldValueList*>(
103 i->first,
104 new HeaderFieldValueList(*i->second)));
105 }
106 if (rhs.mStartLine != 0)
107 {
108 mStartLine = new HeaderFieldValueList(*rhs.mStartLine);
109 }
110 if (rhs.mContents != 0)
111 {
112 mContents = rhs.mContents->clone();
113 }
114 else if (rhs.mContentsHfv != 0)
115 {
116 mContentsHfv = new HeaderFieldValue(*rhs.mContentsHfv);
117 }
118 else
119 {
120 // no body to copy
121 }
122 if (rhs.mForceTarget != 0)
123 {
124 mForceTarget = new Uri(*rhs.mForceTarget);
125 }
126 }
127
128 return *this;
129 }
130
131 SipMessage::~SipMessage()
132 {
133 cleanUp();
134 }
135
136 void
137 SipMessage::cleanUp()
138 {
139 for (int i = 0; i < Headers::MAX_HEADERS; i++)
140 {
141 delete mHeaders[i];
142 mHeaders[i] = 0;
143 }
144
145 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
146 i != mUnknownHeaders.end(); i++)
147 {
148 delete i->second;
149 }
150 mUnknownHeaders.clear();
151
152 for (vector<char*>::iterator i = mBufferList.begin();
153 i != mBufferList.end(); i++)
154 {
155 delete [] *i;
156 }
157 mBufferList.clear();
158
159 delete mStartLine;
160 mStartLine = 0;
161 delete mContents;
162 mContents = 0;
163 delete mContentsHfv;
164 mContentsHfv = 0;
165 delete mForceTarget;
166 mForceTarget = 0;
167 }
168
169 SipMessage*
170 SipMessage::make(const Data& data, bool isExternal)
171 {
172 Transport* external = (Transport*)(0xFFFF);
173 SipMessage* msg = new SipMessage(isExternal ? external : 0);
174
175 size_t len = data.size();
176 char *buffer = new char[len + 5];
177
178 msg->addBuffer(buffer);
179 memcpy(buffer,data.data(), len);
180 MsgHeaderScanner msgHeaderScanner;
181 msgHeaderScanner.prepareForMessage(msg);
182
183 char *unprocessedCharPtr;
184 if (msgHeaderScanner.scanChunk(buffer, len, &unprocessedCharPtr) != MsgHeaderScanner::scrEnd)
185 {
186 DebugLog(<<"Scanner rejecting buffer as unparsable / fragmented.");
187 DebugLog(<< data);
188 delete msg;
189 msg = 0;
190 return 0;
191 }
192
193 // no pp error
194 unsigned int used = unprocessedCharPtr - buffer;
195
196 if (used < len)
197 {
198 // body is present .. add it up.
199 // NB. The Sip Message uses an overlay (again)
200 // for the body. It ALSO expects that the body
201 // will be contiguous (of course).
202 // it doesn't need a new buffer in UDP b/c there
203 // will only be one datagram per buffer. (1:1 strict)
204
205 msg->setBody(buffer+used,len-used);
206 //DebugLog(<<"added " << len-used << " byte body");
207 }
208
209 return msg;
210 }
211
212
213 const Data&
214 SipMessage::getTransactionId() const
215 {
216 if (!this->exists(h_Vias) || this->header(h_Vias).empty())
217 {
218 InfoLog (<< "Bad message with no Vias: " << *this);
219 throw Exception("No Via in message", __FILE__,__LINE__);
220 }
221
222 assert(exists(h_Vias) && !header(h_Vias).empty());
223 if( exists(h_Vias) && header(h_Vias).front().exists(p_branch)
224 && header(h_Vias).front().param(p_branch).hasMagicCookie() )
225 {
226 assert (!header(h_Vias).front().param(p_branch).getTransactionId().empty());
227 return header(h_Vias).front().param(p_branch).getTransactionId();
228 }
229 else
230 {
231 if (mRFC2543TransactionId.empty())
232 {
233 compute2543TransactionHash();
234 }
235 return mRFC2543TransactionId;
236 }
237 }
238
239 void
240 SipMessage::compute2543TransactionHash() const
241 {
242 assert (mRFC2543TransactionId.empty());
243
244 /* From rfc3261, 17.2.3
245 The INVITE request matches a transaction if the Request-URI, To tag,
246 From tag, Call-ID, CSeq, and top Via header field match those of the
247 INVITE request which created the transaction. In this case, the
248 INVITE is a retransmission of the original one that created the
249 transaction.
250
251 The ACK request matches a transaction if the Request-URI, From tag,
252 Call-ID, CSeq number (not the method), and top Via header field match
253 those of the INVITE request which created the transaction, and the To
254 tag of the ACK matches the To tag of the response sent by the server
255 transaction.
256
257 Matching is done based on the matching rules defined for each of those
258 header fields. Inclusion of the tag in the To header field in the ACK
259 matching process helps disambiguate ACK for 2xx from ACK for other
260 responses at a proxy, which may have forwarded both responses (This
261 can occur in unusual conditions. Specifically, when a proxy forked a
262 request, and then crashes, the responses may be delivered to another
263 proxy, which might end up forwarding multiple responses upstream). An
264 ACK request that matches an INVITE transaction matched by a previous
265 ACK is considered a retransmission of that previous ACK.
266
267 For all other request methods, a request is matched to a transaction
268 if the Request-URI, To tag, From tag, Call-ID, CSeq (including the
269 method), and top Via header field match those of the request that
270 created the transaction. Matching is done based on the matching
271 */
272
273 // If it is here and isn't a request, leave the transactionId empty, this
274 // will cause the Transaction to send it statelessly
275
276 if (isRequest())
277 {
278 MD5Stream strm;
279 // See section 17.2.3 Matching Requests to Server Transactions in rfc 3261
280
281 //#define VONAGE_FIX
282 #ifndef VONAGE_FIX
283 strm << header(h_RequestLine).uri().scheme();
284 strm << header(h_RequestLine).uri().user();
285 strm << header(h_RequestLine).uri().host();
286 strm << header(h_RequestLine).uri().port();
287 strm << header(h_RequestLine).uri().password();
288 strm << header(h_RequestLine).uri().commutativeParameterHash();
289 #endif
290 if (exists(h_Vias) && !header(h_Vias).empty())
291 {
292 strm << header(h_Vias).front().protocolName();
293 strm << header(h_Vias).front().protocolVersion();
294 strm << header(h_Vias).front().transport();
295 strm << header(h_Vias).front().sentHost();
296 strm << header(h_Vias).front().sentPort();
297 strm << header(h_Vias).front().commutativeParameterHash();
298 }
299
300 if (header(h_From).exists(p_tag))
301 {
302 strm << header(h_From).param(p_tag);
303 }
304
305 // Only include the totag for non-invite requests
306 if (header(h_RequestLine).getMethod() != INVITE &&
307 header(h_RequestLine).getMethod() != ACK &&
308 header(h_RequestLine).getMethod() != CANCEL &&
309 header(h_To).exists(p_tag))
310 {
311 strm << header(h_To).param(p_tag);
312 }
313
314 strm << header(h_CallID).value();
315
316 if (header(h_RequestLine).getMethod() == ACK ||
317 header(h_RequestLine).getMethod() == CANCEL)
318 {
319 strm << INVITE;
320 strm << header(h_CSeq).sequence();
321 }
322 else
323 {
324 strm << header(h_CSeq).method();
325 strm << header(h_CSeq).sequence();
326 }
327
328 mRFC2543TransactionId = strm.getHex();
329 }
330 else
331 {
332 InfoLog (<< "Trying to compute a transaction id on a 2543 response. Drop the response");
333 DebugLog (<< *this);
334 throw Exception("Drop invalid 2543 response", __FILE__, __LINE__);
335 }
336 }
337
338 const Data&
339 SipMessage::getRFC2543TransactionId() const
340 {
341 if(!( exists(h_Vias) && header(h_Vias).front().exists(p_branch) &&
342 header(h_Vias).front().param(p_branch).hasMagicCookie() ) )
343 {
344 if (mRFC2543TransactionId.empty())
345 {
346 compute2543TransactionHash();
347 }
348 }
349 return mRFC2543TransactionId;
350 }
351
352
353 Data
354 SipMessage::getCanonicalIdentityString() const
355 {
356 Data result;
357 DataStream strm(result);
358
359 // digest-string = addr-spec ":" addr-spec ":" callid ":" 1*DIGIT SP method ":"
360 // SIP-Date ":" [ addr-spec ] ":" message-body
361
362 strm << header(h_From).uri();
363 strm << Symbols::COLON;
364
365 strm << header(h_To).uri();
366 strm << Symbols::COLON;
367
368 strm << header(h_CallId).value();
369 strm << Symbols::COLON;
370
371 strm << header(h_CSeq).sequence(); // force parsed
372 header(h_CSeq).encodeParsed( strm );
373 strm << Symbols::COLON;
374
375 // if there is no date, it will throw
376 if ( !exists(h_Date) )
377 {
378 WarningLog( << "Computing Identity on message with no Date header" );
379 }
380 header(h_Date).dayOfMonth(); // force it to be parsed
381 header(h_Date).encodeParsed( strm );
382 strm << Symbols::COLON;
383
384 if ( exists(h_Contacts) )
385 {
386 if ( header(h_Contacts).front().isAllContacts() )
387 {
388 strm << Symbols::STAR;
389 }
390 else
391 {
392 strm << header(h_Contacts).front().uri();
393 }
394 }
395 strm << Symbols::COLON;
396
397 // bodies
398 if (mContents != 0)
399 {
400 mContents->encode(strm);
401 }
402 else if (mContentsHfv != 0)
403 {
404 mContentsHfv->encode(strm);
405 }
406
407 strm.flush();
408
409 DebugLog( << "Indentity Canonical String is: " << result );
410
411 return result;
412 }
413
414
415 void
416 SipMessage::setRFC2543TransactionId(const Data& tid)
417 {
418 mRFC2543TransactionId = tid;
419 }
420
421 bool
422 SipMessage::isRequest() const
423 {
424 return mRequest;
425 }
426
427 bool
428 SipMessage::isResponse() const
429 {
430 return mResponse;
431 }
432
433 Data
434 SipMessage::brief() const
435 {
436 Data result(128, true);
437
438 static const Data request("SipReq: ");
439 static const Data response("SipResp: ");
440 static const Data tid(" tid=");
441 static const Data contact(" contact=");
442 static const Data cseq(" cseq=");
443 static const Data slash(" / ");
444 static const Data wire(" from(wire)");
445 static const Data tu(" from(tu)");
446
447 // !dlb! should be checked earlier
448 #if 0
449 if (!exists(h_CSeq))
450 {
451 result = "MALFORMED; missing CSeq";
452 return result;
453 }
454 if (!exists(h_CallId))
455 {
456 result = "MALFORMED; missing Call-Id";
457 return result;
458 }
459 #endif
460
461 if (isRequest())
462 {
463 result += request;
464 MethodTypes meth = header(h_RequestLine).getMethod();
465 if (meth != UNKNOWN)
466 {
467 result += getMethodName(meth);
468 }
469 else
470 {
471 result += header(h_RequestLine).unknownMethodName();
472 }
473
474 result += Symbols::SPACE;
475 result += header(h_RequestLine).uri().getAor();
476 }
477 else if (isResponse())
478 {
479 result += response;
480 result += Data(header(h_StatusLine).responseCode());
481 }
482 if (exists(h_Vias) && !this->header(h_Vias).empty())
483 {
484 result += tid;
485 result += getTransactionId();
486 }
487 else
488 {
489 result += " NO-VIAS ";
490 }
491
492 result += cseq;
493 if (header(h_CSeq).method() != UNKNOWN)
494 {
495 result += getMethodName(header(h_CSeq).method());
496 }
497 else
498 {
499 result += header(h_CSeq).unknownMethodName();
500 }
501
502 if (exists(h_Contacts) && !header(h_Contacts).empty())
503 {
504 result += contact;
505 result += header(h_Contacts).front().uri().getAor();
506 }
507
508 result += slash;
509 result += Data(header(h_CSeq).sequence());
510 result += mIsExternal ? wire : tu;
511
512 return result;
513 }
514
515 bool
516 SipMessage::isClientTransaction() const
517 {
518 assert(mRequest || mResponse);
519 return ((mIsExternal && mResponse) || (!mIsExternal && mRequest));
520 }
521
522 std::ostream&
523 SipMessage::encode(std::ostream& str) const
524 {
525 return encode(str, false);
526 }
527
528 std::ostream&
529 SipMessage::encodeSipFrag(std::ostream& str) const
530 {
531 return encode(str, true);
532 }
533
534 // dynamic_cast &str to DataStream* to avoid CountStream?
535
536 std::ostream&
537 SipMessage::encode(std::ostream& str, bool isSipFrag) const
538 {
539 if (mStartLine != 0)
540 {
541 mStartLine->encode(Data::Empty, str);
542 }
543
544 for (int i = 0; i < Headers::MAX_HEADERS; i++)
545 {
546 if (i != Headers::ContentLength) // !dlb! hack...
547 {
548 if (mHeaders[i] != 0)
549 {
550 mHeaders[i]->encode(i, str);
551 }
552 }
553 else
554 {
555 if (mContents != 0)
556 {
557 size_t size;
558 {
559 CountStream cs(size);
560 mContents->encode(cs);
561 }
562 str << "Content-Length: " << size << "\r\n";
563 }
564 else if (mContentsHfv != 0)
565 {
566 str << "Content-Length: " << mContentsHfv->mFieldLength << "\r\n";
567 }
568 else if (!isSipFrag)
569 {
570 str << "Content-Length: 0\r\n";
571 }
572 }
573 }
574
575 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
576 i != mUnknownHeaders.end(); i++)
577 {
578 i->second->encode(i->first, str);
579 }
580
581 str << Symbols::CRLF;
582
583 if (mContents != 0)
584 {
585 mContents->encode(str);
586 }
587 else if (mContentsHfv != 0)
588 {
589 mContentsHfv->encode(str);
590 }
591
592 return str;
593 }
594
595 std::ostream&
596 SipMessage::encodeEmbedded(std::ostream& str) const
597 {
598 bool first = true;
599 for (int i = 0; i < Headers::MAX_HEADERS; i++)
600 {
601 if (i != Headers::ContentLength)
602 {
603 if (mHeaders[i] != 0)
604 {
605 if (first)
606 {
607 str << Symbols::QUESTION;
608 first = false;
609 }
610 else
611 {
612 str << Symbols::AMPERSAND;
613 }
614 mHeaders[i]->encodeEmbedded(Headers::getHeaderName(i), str);
615 }
616 }
617 }
618
619 for (UnknownHeaders::const_iterator i = mUnknownHeaders.begin();
620 i != mUnknownHeaders.end(); i++)
621 {
622 if (first)
623 {
624 str << Symbols::QUESTION;
625 first = false;
626 }
627 else
628 {
629 str << Symbols::AMPERSAND;
630 }
631 i->second->encodeEmbedded(i->first, str);
632 }
633
634 if (mContents != 0)
635 {
636 if (first)
637 {
638 str << Symbols::QUESTION;
639 }
640 else
641 {
642 str << Symbols::AMPERSAND;
643 }
644 str << "body=";
645 // !dlb! encode escaped for characters
646 Data contents;
647 {
648 DataStream s(contents);
649 mContents->encode(s);
650 }
651 str << Embedded::encode(contents);
652 }
653 else if (mContentsHfv != 0)
654 {
655 if (first)
656 {
657 str << Symbols::QUESTION;
658 }
659 else
660 {
661 str << Symbols::AMPERSAND;
662 }
663 str << "body=";
664 // !dlb! encode escaped for characters
665 Data contents;
666 {
667 DataStream s(contents);
668 mContentsHfv->encode(str);
669 }
670 str << Embedded::encode(contents);
671 }
672
673 return str;
674 }
675
676 void
677 SipMessage::addBuffer(char* buf)
678 {
679 mBufferList.push_back(buf);
680 }
681
682 void
683 SipMessage::setStartLine(const char* st, int len)
684 {
685 mStartLine = new HeaderFieldValueList;
686 mStartLine-> push_back(new HeaderFieldValue(st, len));
687 ParseBuffer pb(st, len);
688 const char* start;
689 start = pb.skipWhitespace();
690 pb.skipNonWhitespace();
691 MethodTypes method = getMethodType(start, pb.position() - start);
692 if (method == UNKNOWN) //probably a status line
693 {
694 start = pb.skipChar(Symbols::SPACE[0]);
695 pb.skipNonWhitespace();
696 if ((pb.position() - start) == 3)
697 {
698 mStartLine->setParserContainer(new ParserContainer<StatusLine>(mStartLine, Headers::NONE));
699 //!dcm! should invoke the statusline parser here once it does limited validation
700 mResponse = true;
701 }
702 }
703 if (!mResponse)
704 {
705 mStartLine->setParserContainer(new ParserContainer<RequestLine>(mStartLine, Headers::NONE));
706 //!dcm! should invoke the responseline parser here once it does limited validation
707 mRequest = true;
708 }
709 }
710
711 void
712 SipMessage::setBody(const char* start, int len)
713 {
714 mContentsHfv = new HeaderFieldValue(start, len);
715 }
716
717 void
718 SipMessage::setContents(auto_ptr<Contents> contents)
719 {
720 Contents* contentsP = contents.release();
721
722 delete mContents;
723 mContents = 0;
724 delete mContentsHfv;
725 mContentsHfv = 0;
726
727 if (contentsP == 0)
728 {
729 // The semantics of setContents(0) are to delete message contents
730 remove(h_ContentType);
731 remove(h_ContentDisposition);
732 remove(h_ContentTransferEncoding);
733 remove(h_ContentLanguages);
734 return;
735 }
736
737 mContents = contentsP;
738
739 // copy contents headers into message
740 if (mContents->exists(h_ContentDisposition))
741 {
742 header(h_ContentDisposition) = mContents->header(h_ContentDisposition);
743 }
744 if (mContents->exists(h_ContentTransferEncoding))
745 {
746 header(h_ContentTransferEncoding) = mContents->header(h_ContentTransferEncoding);
747 }
748 if (mContents->exists(h_ContentLanguages))
749 {
750 header(h_ContentLanguages) = mContents->header(h_ContentLanguages);
751 }
752 if (mContents->exists(h_ContentType))
753 {
754 header(h_ContentType) = mContents->header(h_ContentType);
755 assert( header(h_ContentType).type() == mContents->getType().type() );
756 assert( header(h_ContentType).subType() == mContents->getType().subType() );
757 }
758 else
759 {
760 header(h_ContentType) = mContents->getType();
761 }
762 }
763
764 void
765 SipMessage::setContents(const Contents* contents)
766 {
767 if (contents)
768 {
769 setContents(auto_ptr<Contents>(contents->clone()));
770 }
771 else
772 {
773 setContents(auto_ptr<Contents>(0));
774 }
775 }
776
777 Contents*
778 SipMessage::getContents() const
779 {
780 if (mContents == 0 && mContentsHfv != 0)
781 {
782 if (!exists(h_ContentType))
783 {
784 StackLog(<< "SipMessage::getContents: ContentType header does not exist - implies no contents");
785 return 0;
786 }
787 DebugLog(<< "SipMessage::getContents: "
788 << header(h_ContentType).type()
789 << "/"
790 << header(h_ContentType).subType());
791
792 if ( Contents::getFactoryMap().find(header(h_ContentType)) == Contents::getFactoryMap().end() )
793 {
794 InfoLog(<< "SipMessage::getContents: got content type ("
795 << header(h_ContentType).type()
796 << "/"
797 << header(h_ContentType).subType()
798 << ") that is not known, "
799 << "returning as opaque application/octet-stream");
800 mContents = Contents::getFactoryMap()[OctetContents::getStaticType()]->create(mContentsHfv, OctetContents::getStaticType());
801 }
802 else
803 {
804 mContents = Contents::getFactoryMap()[header(h_ContentType)]->create(mContentsHfv, header(h_ContentType));
805 }
806 assert( mContents );
807
808 // copy contents headers into the contents
809 if (exists(h_ContentDisposition))
810 {
811 mContents->header(h_ContentDisposition) = header(h_ContentDisposition);
812 }
813 if (exists(h_ContentTransferEncoding))
814 {
815 mContents->header(h_ContentTransferEncoding) = header(h_ContentTransferEncoding);
816 }
817 if (exists(h_ContentLanguages))
818 {
819 mContents->header(h_ContentLanguages) = header(h_ContentLanguages);
820 }
821 if (exists(h_ContentType))
822 {
823 mContents->header(h_ContentType) = header(h_ContentType);
824 }
825 // !dlb! Content-Transfer-Encoding?
826 }
827 return mContents;
828 }
829
830 auto_ptr<Contents>
831 SipMessage::releaseContents()
832 {
833 auto_ptr<Contents> ret(getContents());
834 if (ret.get() != 0)
835 {
836 // the buffer may go away...
837 ret->checkParsed();
838 mContents = 0;
839 // ...here
840 }
841 setContents(auto_ptr<Contents>(0));
842
843 return ret;
844 }
845
846 // unknown header interface
847 const StringCategories&
848 SipMessage::header(const ExtensionHeader& headerName) const
849 {
850 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
851 i != mUnknownHeaders.end(); i++)
852 {
853 // !dlb! case sensitive?
854 if (i->first == headerName.getName())
855 {
856 HeaderFieldValueList* hfvs = i->second;
857 if (hfvs->getParserContainer() == 0)
858 {
859 hfvs->setParserContainer(new ParserContainer<StringCategory>(hfvs, Headers::NONE));
860 }
861 return *dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
862 }
863 }
864 // missing extension header
865 assert(false);
866
867 return *(StringCategories*)0;
868 }
869
870 StringCategories&
871 SipMessage::header(const ExtensionHeader& headerName)
872 {
873 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
874 i != mUnknownHeaders.end(); i++)
875 {
876 // !dlb! case sensitive?
877 if (i->first == headerName.getName())
878 {
879 HeaderFieldValueList* hfvs = i->second;
880 if (hfvs->getParserContainer() == 0)
881 {
882 hfvs->setParserContainer(new ParserContainer<StringCategory>(hfvs, Headers::NONE));
883 }
884 return *dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
885 }
886 }
887
888 // create the list empty
889 HeaderFieldValueList* hfvs = new HeaderFieldValueList;
890 hfvs->setParserContainer(new ParserContainer<StringCategory>(hfvs, Headers::NONE));
891 mUnknownHeaders.push_back(make_pair(headerName.getName(), hfvs));
892 return *dynamic_cast<ParserContainer<StringCategory>*>(hfvs->getParserContainer());
893 }
894
895 bool
896 SipMessage::exists(const ExtensionHeader& symbol) const
897 {
898 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
899 i != mUnknownHeaders.end(); i++)
900 {
901 if (i->first == symbol.getName())
902 {
903 return true;
904 }
905 }
906 return false;
907 }
908
909 void
910 SipMessage::remove(const ExtensionHeader& headerName)
911 {
912 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
913 i != mUnknownHeaders.end(); i++)
914 {
915 if (i->first == headerName.getName())
916 {
917 delete i->second;
918 mUnknownHeaders.erase(i);
919 return;
920 }
921 }
922 }
923
924 void
925 SipMessage::addHeader(Headers::Type header, const char* headerName, int headerLen,
926 const char* start, int len)
927 {
928 if (header != Headers::UNKNOWN)
929 {
930 if (mHeaders[header] == 0)
931 {
932 mHeaders[header] = new HeaderFieldValueList;
933 }
934 if (len)
935 {
936 mHeaders[header]->push_back(new HeaderFieldValue(start, len));
937 }
938 }
939 else
940 {
941 for (UnknownHeaders::iterator i = mUnknownHeaders.begin();
942 i != mUnknownHeaders.end(); i++)
943 {
944 if (strncasecmp(i->first.data(), headerName, headerLen) == 0)
945 {
946 // add to end of list
947 if (len)
948 {
949 i->second->push_back(new HeaderFieldValue(start, len));
950 }
951 return;
952 }
953 }
954
955 // didn't find it, add an entry
956 HeaderFieldValueList *hfvs = new HeaderFieldValueList();
957 if (len)
958 {
959 hfvs->push_back(new HeaderFieldValue(start, len));
960 }
961 mUnknownHeaders.push_back(pair<Data, HeaderFieldValueList*>(Data(headerName, headerLen),
962 hfvs));
963 }
964 }
965
966 Data&
967 SipMessage::getEncoded()
968 {
969 return mEncoded;
970 }
971
972 RequestLine&
973 SipMessage::header(const RequestLineType& l)
974 {
975 assert (!isResponse());
976 if (mStartLine == 0 )
977 {
978 mStartLine = new HeaderFieldValueList;
979 mStartLine->push_back(new HeaderFieldValue);
980 mStartLine->setParserContainer(new ParserContainer<RequestLine>(mStartLine, Headers::NONE));
981 mRequest = true;
982 }
983 return dynamic_cast<ParserContainer<RequestLine>*>(mStartLine->getParserContainer())->front();
984 }
985
986 const RequestLine&
987 SipMessage::header(const RequestLineType& l) const
988 {
989 assert (!isResponse());
990 if (mStartLine == 0 )
991 {
992 // request line missing
993 assert(false);
994 }
995 return dynamic_cast<ParserContainer<RequestLine>*>(mStartLine->getParserContainer())->front();
996 }
997
998 StatusLine&
999 SipMessage::header(const StatusLineType& l)
1000 {
1001 assert (!isRequest());
1002 if (mStartLine == 0 )
1003 {
1004 mStartLine = new HeaderFieldValueList;
1005 mStartLine->push_back(new HeaderFieldValue);
1006 mStartLine->setParserContainer(new ParserContainer<StatusLine>(mStartLine, Headers::NONE));
1007 mResponse = true;
1008 }
1009 return dynamic_cast<ParserContainer<StatusLine>*>(mStartLine->getParserContainer())->front();
1010 }
1011
1012 const StatusLine&
1013 SipMessage::header(const StatusLineType& l) const
1014 {
1015 assert (!isRequest());
1016 if (mStartLine == 0 )
1017 {
1018 // status line missing
1019 assert(false);
1020 }
1021 return dynamic_cast<ParserContainer<StatusLine>*>(mStartLine->getParserContainer())->front();
1022 }
1023
1024 HeaderFieldValueList*
1025 SipMessage::ensureHeaders(Headers::Type type, bool single)
1026 {
1027 HeaderFieldValueList* hfvs = mHeaders[type];
1028
1029 // empty?
1030 if (hfvs == 0)
1031 {
1032 // create the list with a new component
1033 hfvs = new HeaderFieldValueList;
1034 mHeaders[type] = hfvs;
1035 if (single)
1036 {
1037 HeaderFieldValue* hfv = new HeaderFieldValue;
1038 hfvs->push_back(hfv);
1039 }
1040 }
1041 // !dlb! not thrilled about checking this every access
1042 else if (single)
1043 {
1044 if (hfvs->parsedEmpty())
1045 {
1046 // create an unparsed shared header field value // !dlb! when will this happen?
1047 hfvs->push_back(new HeaderFieldValue(Data::Empty.data(), 0));
1048 }
1049 }
1050
1051 return hfvs;
1052 }
1053
1054 HeaderFieldValueList*
1055 SipMessage::ensureHeaders(Headers::Type type, bool single) const
1056 {
1057 HeaderFieldValueList* hfvs = mHeaders[type];
1058
1059 // empty?
1060 if (hfvs == 0)
1061 {
1062 // header missing
1063 // assert(false);
1064 InfoLog( << "Missing Header [" << Headers::getHeaderName(type) << "]");
1065 DebugLog (<< *this);
1066 throw Exception("Missing header " + Headers::getHeaderName(type), __FILE__, __LINE__);
1067 }
1068 // !dlb! not thrilled about checking this every access
1069 else if (single)
1070 {
1071 if (hfvs->parsedEmpty())
1072 {
1073 // !dlb! when will this happen?
1074 // assert(false);
1075 InfoLog( << "Missing Header " << Headers::getHeaderName(type) );
1076 DebugLog (<< *this);
1077 throw Exception("Empty header", __FILE__, __LINE__);
1078 }
1079 }
1080
1081 return hfvs;
1082 }
1083
1084 // type safe header accessors
1085 bool
1086 SipMessage::exists(const HeaderBase& headerType) const
1087 {
1088 return mHeaders[headerType.getTypeNum()] != 0;
1089 };
1090
1091 void
1092 SipMessage::remove(const HeaderBase& headerType)
1093 {
1094 delete mHeaders[headerType.getTypeNum()];
1095 mHeaders[headerType.getTypeNum()] = 0;
1096 };
1097
1098 #ifndef PARTIAL_TEMPLATE_SPECIALIZATION
1099
1100 #undef defineHeader
1101 #define defineHeader(_header, _name, _type, _rfc) \
1102 const H_##_header::Type& \
1103 SipMessage::header(const H_##_header& headerType) const \
1104 { \
1105 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum(), true); \
1106 if (hfvs->getParserContainer() == 0) \
1107 { \
1108 hfvs->setParserContainer(new ParserContainer<H_##_header::Type>(hfvs, headerType.getTypeNum())); \
1109 } \
1110 return dynamic_cast<ParserContainer<H_##_header::Type>*>(hfvs->getParserContainer())->front(); \
1111 } \
1112 \
1113 H_##_header::Type& \
1114 SipMessage::header(const H_##_header& headerType) \
1115 { \
1116 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum(), true); \
1117 if (hfvs->getParserContainer() == 0) \
1118 { \
1119 hfvs->setParserContainer(new ParserContainer<H_##_header::Type>(hfvs, headerType.getTypeNum())); \
1120 } \
1121 return dynamic_cast<ParserContainer<H_##_header::Type>*>(hfvs->getParserContainer())->front(); \
1122 }
1123
1124 #undef defineMultiHeader
1125 #define defineMultiHeader(_header, _name, _type, _rfc) \
1126 const H_##_header##s::Type& \
1127 SipMessage::header(const H_##_header##s& headerType) const \
1128 { \
1129 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum(), false); \
1130 if (hfvs->getParserContainer() == 0) \
1131 { \
1132 hfvs->setParserContainer(new H_##_header##s::Type(hfvs, headerType.getTypeNum())); \
1133 } \
1134 return *dynamic_cast<H_##_header##s::Type*>(hfvs->getParserContainer()); \
1135 } \
1136 \
1137 H_##_header##s::Type& \
1138 SipMessage::header(const H_##_header##s& headerType) \
1139 { \
1140 HeaderFieldValueList* hfvs = ensureHeaders(headerType.getTypeNum(), false); \
1141 if (hfvs->getParserContainer() == 0) \
1142 { \
1143 hfvs->setParserContainer(new H_##_header##s::Type(hfvs, headerType.getTypeNum())); \
1144 } \
1145 return *dynamic_cast<H_##_header##s::Type*>(hfvs->getParserContainer()); \
1146 }
1147
1148 defineHeader(ContentDisposition, "Content-Disposition", Token, "RFC 3261");
1149 defineHeader(ContentEncoding, "Content-Encoding", Token, "RFC 3261");
1150 defineHeader(MIMEVersion, "Mime-Version", Token, "RFC 3261");
1151 defineHeader(Priority, "Priority", Token, "RFC 3261");
1152 defineHeader(Event, "Event", Token, "RFC 3265");
1153 defineHeader(SubscriptionState, "Subscription-State", Token, "RFC 3265");
1154 defineHeader(SIPETag, "SIP-ETag", Token, "RFC 3903");
1155 defineHeader(SIPIfMatch, "SIP-If-Match", Token, "RFC 3903");
1156 defineHeader(ContentId, "Content-ID", Token, "RFC 2045");
1157 defineMultiHeader(AllowEvents, "Allow-Events", Token, "RFC 3265");
1158 defineHeader(Identity, "Identity", StringCategory, "draft-sip-identity-03");
1159 defineMultiHeader(AcceptEncoding, "Accept-Encoding", Token, "RFC 3261");
1160 defineMultiHeader(AcceptLanguage, "Accept-Language", Token, "RFC 3261");
1161 defineMultiHeader(Allow, "Allow", Token, "RFC 3261");
1162 defineMultiHeader(ContentLanguage, "Content-Language", Token, "RFC 3261");
1163 defineMultiHeader(ProxyRequire, "Proxy-Require", Token, "RFC 3261");
1164 defineMultiHeader(Require, "Require", Token, "RFC 3261");
1165 defineMultiHeader(Supported, "Supported", Token, "RFC 3261");
1166 defineMultiHeader(Unsupported, "Unsupported", Token, "RFC 3261");
1167 defineMultiHeader(SecurityClient, "Security-Client", Token, "RFC 3329");
1168 defineMultiHeader(SecurityServer, "Security-Server", Token, "RFC 3329");
1169 defineMultiHeader(SecurityVerify, "Security-Verify", Token, "RFC 3329");
1170 defineMultiHeader(RequestDisposition, "Request-Disposition", Token, "RFC 3841");
1171 defineMultiHeader(Reason, "Reason", Token, "RFC 3326");
1172 defineMultiHeader(Privacy, "Privacy", Token, "RFC 3323");
1173 defineMultiHeader(PMediaAuthorization, "P-Media-Authorization", Token, "RFC 3313");
1174
1175 defineMultiHeader(Accept, "Accept", Mime, "RFC 3261");
1176 defineHeader(ContentType, "Content-Type", Mime, "RFC 3261");
1177
1178 defineMultiHeader(CallInfo, "Call-Info", GenericUri, "RFC 3261");
1179 defineMultiHeader(AlertInfo, "Alert-Info", GenericUri, "RFC 3261");
1180 defineMultiHeader(ErrorInfo, "Error-Info", GenericUri, "RFC 3261");
1181 defineHeader(IdentityInfo, "Identity-Info", GenericUri, "draft-sip-identity-03");
1182
1183 defineMultiHeader(RecordRoute, "Record-Route", NameAddr, "RFC 3261");
1184 defineMultiHeader(Route, "Route", NameAddr, "RFC 3261");
1185 defineMultiHeader(Contact, "Contact", NameAddr, "RFC 3261");
1186 defineHeader(From, "From", NameAddr, "RFC 3261");
1187 defineHeader(To, "To", NameAddr, "RFC 3261");
1188 defineHeader(ReplyTo, "Reply-To", NameAddr, "RFC 3261");
1189 defineHeader(ReferTo, "Refer-To", NameAddr, "RFC 3515");
1190 defineHeader(ReferredBy, "Referred-By", NameAddr, "RFC 3892");
1191 defineMultiHeader(Path, "Path", NameAddr, "RFC 3327");
1192 defineMultiHeader(AcceptContact, "Accept-Contact", NameAddr, "RFC 3841");
1193 defineMultiHeader(RejectContact, "Reject-Contact", NameAddr, "RFC 3841");
1194 defineMultiHeader(PAssertedIdentity, "P-Asserted-Identity", NameAddr, "RFC 3325");
1195 defineMultiHeader(PPreferredIdentity, "P-Preferred-Identity", NameAddr, "RFC 3325");
1196 defineHeader(PCalledPartyId, "P-Called-Party-ID", NameAddr, "RFC 3455");
1197 defineMultiHeader(PAssociatedUri, "P-Associated-URI", NameAddr, "RFC 3455");
1198 defineMultiHeader(ServiceRoute, "Service-Route", NameAddr, "RFC 3608");
1199
1200 defineHeader(ContentTransferEncoding, "Content-Transfer-Encoding", StringCategory, "RFC ?");
1201 defineHeader(Organization, "Organization", StringCategory, "RFC 3261");
1202 defineHeader(Server, "Server", StringCategory, "RFC 3261");
1203 defineHeader(Subject, "Subject", StringCategory, "RFC 3261");
1204 defineHeader(UserAgent, "User-Agent", StringCategory, "RFC 3261");
1205 defineHeader(Timestamp, "Timestamp", StringCategory, "RFC 3261");
1206
1207 defineHeader(ContentLength, "Content-Length", IntegerCategory, "RFC 3261");
1208 defineHeader(MaxForwards, "Max-Forwards", IntegerCategory, "RFC 3261");
1209 defineHeader(MinExpires, "Min-Expires", IntegerCategory, "RFC 3261");
1210 defineHeader(RSeq, "RSeq", IntegerCategory, "RFC 3261");
1211
1212 // !dlb! this one is not quite right -- can have (comment) after field value
1213 defineHeader(RetryAfter, "Retry-After", IntegerCategory, "RFC 3261");
1214
1215 defineHeader(Expires, "Expires", ExpiresCategory, "RFC 3261");
1216 defineHeader(SessionExpires, "Session-Expires", ExpiresCategory, "Session Timer draft");
1217 defineHeader(MinSE, "Min-SE", ExpiresCategory, "Session Timer draft");
1218
1219 defineHeader(CallID, "Call-ID", CallID, "RFC 3261");
1220 defineHeader(Replaces, "Replaces", CallID, "RFC 3261");
1221 defineHeader(InReplyTo, "In-Reply-To", CallID, "RFC 3261");
1222 defineHeader(Join, "Join", CallId, "RFC 3911");
1223 defineHeader(TargetDialog, "Target-Dialog", CallId, "Target Dialog draft");
1224
1225 defineHeader(AuthenticationInfo, "Authentication-Info", Auth, "RFC 3261");
1226 defineMultiHeader(Authorization, "Authorization", Auth, "RFC 3261");
1227 defineMultiHeader(ProxyAuthenticate, "Proxy-Authenticate", Auth, "RFC 3261");
1228 defineMultiHeader(ProxyAuthorization, "Proxy-Authorization", Auth, "RFC 3261");
1229 defineMultiHeader(WWWAuthenticate, "Www-Authenticate", Auth, "RFC 3261");
1230
1231 defineHeader(CSeq, "CSeq", CSeqCategory, "RFC 3261");
1232 defineHeader(Date, "Date", DateCategory, "RFC 3261");
1233 defineMultiHeader(Warning, "Warning", WarningCategory, "RFC 3261");
1234 defineMultiHeader(Via, "Via", Via, "RFC 3261");
1235 defineHeader(RAck, "RAck", RAckCategory, "RFC 3262");
1236
1237 #endif
1238
1239 const HeaderFieldValueList*
1240 SipMessage::getRawHeader(Headers::Type headerType) const
1241 {
1242 return mHeaders[headerType];
1243 }
1244
1245 void
1246 SipMessage::setRawHeader(const HeaderFieldValueList* hfvs, Headers::Type headerType)
1247 {
1248 if (mHeaders[headerType] != hfvs)
1249 {
1250 delete mHeaders[headerType];
1251 mHeaders[headerType] = new HeaderFieldValueList(*hfvs);
1252 }
1253 }
1254
1255 void
1256 SipMessage::setForceTarget(const Uri& uri)
1257 {
1258 if (mForceTarget)
1259 {
1260 *mForceTarget = uri;
1261 }
1262 else
1263 {
1264 mForceTarget = new Uri(uri);
1265 }
1266 }
1267
1268 void
1269 SipMessage::clearForceTarget()
1270 {
1271 delete mForceTarget;
1272 mForceTarget = 0;
1273 }
1274
1275 const Uri&
1276 SipMessage::getForceTarget() const
1277 {
1278 assert(mForceTarget);
1279 return *mForceTarget;
1280 }
1281
1282 bool
1283 SipMessage::hasForceTarget() const
1284 {
1285 return (mForceTarget != 0);
1286 }
1287
1288 SipMessage&
1289 SipMessage::mergeUri(const Uri& source)
1290 {
1291 header(h_RequestLine).uri() = source;
1292 header(h_RequestLine).uri().removeEmbedded();
1293
1294 if (source.exists(p_method))
1295 {
1296 header(h_RequestLine).method() = getMethodType(source.param(p_method));
1297 header(h_RequestLine).uri().remove(p_method);
1298 }
1299
1300 //19.1.5
1301 //dangerous headers not included in merge:
1302 // From, Call-ID, Cseq, Via, Record Route, Route, Accept, Accept-Encoding,
1303 // Accept-Langauge, Allow, Contact, Organization, Supported, User-Agent
1304
1305 //from the should-verify section, remove for now, some never seem to make
1306 //sense:
1307 // Content-Encoding, Content-Language, Content-Length, Content-Type, Date,
1308 // Mime-Version, and TimeStamp
1309
1310 if (source.hasEmbedded())
1311 {
1312 h_AuthenticationInfo.merge(*this, source.embedded());
1313 h_ContentTransferEncoding.merge(*this, source.embedded());
1314 h_Event.merge(*this, source.embedded());
1315 h_Expires.merge(*this, source.embedded());
1316 h_SessionExpires.merge(*this, source.embedded());
1317 h_MinSE.merge(*this, source.embedded());
1318 h_InReplyTo.merge(*this, source.embedded());
1319 h_MaxForwards.merge(*this, source.embedded());
1320 h_MinExpires.merge(*this, source.embedded());
1321 h_Priority.merge(*this, source.embedded());
1322 h_ReferTo.merge(*this, source.embedded());
1323 h_ReferredBy.merge(*this, source.embedded());
1324 h_Replaces.merge(*this, source.embedded());
1325 h_ReplyTo.merge(*this, source.embedded());
1326 h_RetryAfter.merge(*this, source.embedded());
1327 h_Server.merge(*this, source.embedded());
1328 h_SIPETag.merge(*this, source.embedded());
1329 h_SIPIfMatch.merge(*this, source.embedded());
1330 h_Subject.merge(*this, source.embedded());
1331 h_SubscriptionState.merge(*this, source.embedded());
1332 h_To.merge(*this, source.embedded());
1333 h_Warnings.merge(*this, source.embedded());
1334
1335 h_SecurityClients.merge(*this, source.embedded());
1336 h_SecurityServers.merge(*this, source.embedded());
1337 h_SecurityVerifys.merge(*this, source.embedded());
1338
1339 h_Authorizations.merge(*this, source.embedded());
1340 h_ProxyAuthenticates.merge(*this, source.embedded());
1341 h_WWWAuthenticates.merge(*this, source.embedded());
1342 h_ProxyAuthorizations.merge(*this, source.embedded());
1343
1344 h_AlertInfos.merge(*this, source.embedded());
1345 h_AllowEvents.merge(*this, source.embedded());
1346 h_CallInfos.merge(*this, source.embedded());
1347 h_ErrorInfos.merge(*this, source.embedded());
1348 h_ProxyRequires.merge(*this, source.embedded());
1349 h_Requires.merge(*this, source.embedded());
1350 h_Unsupporteds.merge(*this, source.embedded());
1351
1352 h_RSeq.merge(*this, source.embedded());
1353 h_RAck.merge(*this, source.embedded());
1354 }
1355 //unknown header merge
1356 return *this;
1357 }
1358
1359 void
1360 SipMessage::setSecurityAttributes(auto_ptr<SecurityAttributes> sec) const
1361 {
1362 mSecurityAttributes = sec;
1363 }
1364
1365
1366 #if defined(DEBUG) && defined(DEBUG_MEMORY)
1367 namespace resip
1368 {
1369
1370 void*
1371 operator new(size_t size)
1372 {
1373 void * p = std::operator new(size);
1374 DebugLog(<<"operator new | " << hex << p << " | "
1375 << dec << size);
1376 if (size == 60)
1377 {
1378 3;
1379 }
1380
1381 return p;
1382 }
1383
1384 void operator delete(void* p)
1385 {
1386 DebugLog(<<"operator delete | " << hex << p << dec);
1387 return std::operator delete( p );
1388 }
1389
1390 void operator delete[](void* p)
1391 {
1392 DebugLog(<<"operator delete [] | " << hex << p << dec);
1393 return std::operator delete[] ( p );
1394 }
1395
1396 }
1397
1398 #endif
1399
1400 /* ====================================================================
1401 * The Vovida Software License, Version 1.0
1402 *
1403 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1404 *
1405 * Redistribution and use in source and binary forms, with or without
1406 * modification, are permitted provided that the following conditions
1407 * are met:
1408 *
1409 * 1. Redistributions of source code must retain the above copyright
1410 * notice, this list of conditions and the following disclaimer.
1411 *
1412 * 2. Redistributions in binary form must reproduce the above copyright
1413 * notice, this list of conditions and the following disclaimer in
1414 * the documentation and/or other materials provided with the
1415 * distribution.
1416 *
1417 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1418 * and "Vovida Open Communication Application Library (VOCAL)" must
1419 * not be used to endorse or promote products derived from this
1420 * software without prior written permission. For written
1421 * permission, please contact vocal@vovida.org.
1422 *
1423 * 4. Products derived from this software may not be called "VOCAL", nor
1424 * may "VOCAL" appear in their name, without prior written
1425 * permission of Vovida Networks, Inc.
1426 *
1427 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1428 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1429 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1430 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1431 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1432 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1433 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1434 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1435 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1436 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1437 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1438 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1439 * DAMAGE.
1440 *
1441 * ====================================================================
1442 *
1443 * This software consists of voluntary contributions made by Vovida
1444 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1445 * Inc. For more information on Vovida Networks, Inc., please see
1446 * <http://www.vovida.org/>.
1447 *
1448 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27