/[resiprocate]/main/resip/dum/InviteSession.cxx
ViewVC logotype

Annotation of /main/resip/dum/InviteSession.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3094 - (hide annotations) (download)
Mon Jul 12 19:46:17 2004 UTC (15 years, 5 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 19994 byte(s)
added catch to DUM process; couldn't handle FWD's 403
leak checking code now requires an additional define, so it doesn't interact w/ other overloaded new opterators in debug
1 jason 2725 #include "resiprocate/SipMessage.hxx"
2 jason 2846 #include "resiprocate/SdpContents.hxx"
3 jason 2725 #include "resiprocate/dum/Dialog.hxx"
4     #include "resiprocate/dum/DialogUsageManager.hxx"
5     #include "resiprocate/dum/InviteSession.hxx"
6 jason 2846 #include "resiprocate/dum/InviteSessionHandler.hxx"
7 derek 2961 #include "resiprocate/dum/UsageUseException.hxx"
8 jason 2856 #include "resiprocate/os/Logger.hxx"
9 jason 2555
10 derek 3094 #if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio
11 derek 3092 #define _CRTDBG_MAP_ALLOC
12     #include <stdlib.h>
13     #include <crtdbg.h>
14     #define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
15     #endif // defined(WIN32) && defined(_DEBUG)
16 sgodin 3091
17 derek 3092
18 jason 2856 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
19 jason 2846
20 davidb 2603 using namespace resip;
21    
22 derek 2990 unsigned long
23     InviteSession::T1 = 500;
24    
25     unsigned long
26     InviteSession::T2 = 8 * T1;
27    
28     unsigned long
29     InviteSession::TimerH = 64 * T1;
30    
31 derek 2976 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
32 derek 3089 : DialogUsage(dum, dialog),
33 derek 2976 mState(initialState),
34 jason 2846 mOfferState(Nothing),
35 jason 2725 mCurrentLocalSdp(0),
36     mCurrentRemoteSdp(0),
37     mProposedLocalSdp(0),
38 derek 2965 mProposedRemoteSdp(0),
39 derek 2990 mNextOfferOrAnswerSdp(0),
40     mCurrentRetransmit200(0)
41    
42 jason 2555 {
43 derek 3006 InfoLog ( << "^^^ InviteSession::InviteSession " << this);
44 jason 2846 assert(mDum.mInviteSessionHandler);
45 jason 2555 }
46    
47 derek 2858 InviteSession::~InviteSession()
48     {
49 derek 3006 InfoLog ( << "^^^ InviteSession::~InviteSession " << this);
50 derek 2965 delete mCurrentLocalSdp;
51     delete mCurrentRemoteSdp;
52     delete mProposedLocalSdp;
53     delete mProposedRemoteSdp;
54     delete mNextOfferOrAnswerSdp;
55 derek 2858 mDialog.mInviteSession = 0;
56     }
57 jason 2846
58 derek 3064 SipMessage&
59     InviteSession::modifySession()
60     {
61     if (mNextOfferOrAnswerSdp == 0 || mState != Connected)
62     {
63     throw new UsageUseException("Must be in the connected state and have propsed an offer to call modifySession",
64     __FILE__, __LINE__);
65     }
66     mState = ReInviting;
67     mDialog.makeRequest(mLastRequest, INVITE);
68     return mLastRequest;
69     }
70    
71    
72     SipMessage&
73     InviteSession::acceptOffer(int statusCode)
74     {
75     if (mNextOfferOrAnswerSdp == 0 || mState != ReInviting)
76     {
77     throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession",
78     __FILE__, __LINE__);
79     }
80     mState = AcceptingReInvite;
81 derek 3089 mDialog.makeResponse(mFinalResponse, mLastRequest, statusCode);
82     return mFinalResponse;
83 derek 3064 }
84    
85 jason 2866 void
86     InviteSession::setOffer(const SdpContents* sdp)
87     {
88 derek 2965 if (mProposedRemoteSdp)
89     {
90     throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__);
91     }
92 sgodin 3091 assert(mNextOfferOrAnswerSdp == 0);
93 derek 2965 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
94 jason 2866 }
95    
96     void
97     InviteSession::setAnswer(const SdpContents* sdp)
98     {
99 derek 2965 if (mProposedLocalSdp )
100     {
101     throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__);
102     }
103 sgodin 3091 assert(mNextOfferOrAnswerSdp == 0);
104 derek 2965 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
105 jason 2866 }
106    
107 jason 2555 const SdpContents*
108     InviteSession::getLocalSdp()
109     {
110 jason 2725 return mCurrentLocalSdp;
111 jason 2555 }
112    
113     const SdpContents*
114     InviteSession::getRemoteSdp()
115     {
116 jason 2725 return mCurrentRemoteSdp;
117 jason 2555 }
118 davidb 2575
119 jason 2941 InviteSessionHandle
120     InviteSession::getSessionHandle()
121     {
122     return InviteSessionHandle(mDum, getBaseHandle().getId());
123     }
124    
125 derek 2990
126 jason 2856 void
127 derek 2990 InviteSession::dispatch(const DumTimeout& timeout)
128     {
129 derek 3064 if (timeout.type() == DumTimeout::Retransmit200 && (mState == Accepting || mState == AcceptingReInvite ))
130 derek 2990 {
131 derek 3001 mDum.send(mFinalResponse);
132 derek 3079 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(T2, mCurrentRetransmit200*2), getBaseHandle(), 0);
133 derek 2990 }
134     else if (timeout.type() == DumTimeout::WaitForAck && mState != Connected)
135     {
136     mDialog.makeResponse(mLastResponse, mLastRequest, 408);
137     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), mLastResponse);
138     delete this;
139     }
140     }
141    
142     void
143 jason 2856 InviteSession::dispatch(const SipMessage& msg)
144     {
145     std::pair<OfferAnswerType, const SdpContents*> offans;
146     offans = InviteSession::getOfferOrAnswer(msg);
147    
148 derek 2961 switch(mState)
149 jason 2856 {
150 derek 2961 case Terminated:
151 derek 2978 //!dcm! -- 481 behaviour here, should pretty much die on anything
152 derek 2997 //eventually 200 to BYE could be handled further out
153     if (msg.isResponse())
154 derek 2961 {
155 derek 2997 int code = msg.header(h_StatusLine).statusCode();
156     if ((code == 200 && msg.header(h_CSeq).method() == BYE) || code > 399)
157     {
158     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
159     delete this;
160 derek 3006 return;
161 derek 2997 }
162 derek 2961 }
163     break;
164     case Connected:
165     if (msg.isRequest())
166     {
167     switch(msg.header(h_RequestLine).method())
168     {
169 sgodin 3091 // reINVITE
170 derek 2961 case INVITE:
171 derek 3089 mState = ReInviting;
172 derek 2961 mDialog.update(msg);
173 sgodin 3071 mLastRequest = msg; // !slg!
174 derek 2961 mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), msg);
175     if (offans.first != None)
176     {
177 derek 2976 incomingSdp(msg, offans.second);
178 derek 2961 }
179     break;
180 jason 2856
181 derek 2961 case BYE:
182 derek 2978 mState = Terminated;
183     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
184     mDialog.makeResponse(mLastResponse, msg, 200);
185     send(mLastResponse);
186 derek 2961 break;
187 jason 2856
188 derek 2961 case UPDATE:
189     assert(0);
190     break;
191 jason 2856
192 derek 2961 case INFO:
193     mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
194     break;
195 jason 2856
196 derek 2961 case REFER:
197     assert(0); // !jf!
198     mDum.mInviteSessionHandler->onRefer(getSessionHandle(), msg);
199     break;
200 jason 2856
201 derek 2961 default:
202     InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief());
203     break;
204     }
205 derek 3006 }
206     else
207     {
208     //!dcm! -- need to change this logic for when we don't have an ACK yet
209     if ( msg.header(h_StatusLine).statusCode() == 200)
210     {
211     //retransmist ack
212     mDum.send(mAck);
213     }
214     }
215 derek 3064 break;
216     case ReInviting:
217 derek 3089 if (msg.isResponse() && msg.header(h_CSeq).method() == INVITE
218     && msg.header(h_StatusLine).statusCode() == 200)
219 derek 3064 {
220 derek 3089 mState = Connected;
221 derek 3064 send(ackConnection());
222 derek 3089 if (offans.first != None)
223     {
224     incomingSdp(msg, offans.second);
225     }
226 derek 3064 }
227     else
228     {
229     ErrLog ( << "Spurious message sent to UAS " << msg );
230     return;
231     }
232     break;
233 derek 2976 case Accepting:
234     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
235     {
236     mState = Connected;
237     mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);
238     if (offans.first != None)
239     {
240     InviteSession::incomingSdp(msg, offans.second);
241     }
242     }
243     else
244     {
245 derek 2997 ErrLog ( << "Spurious message sent to UAS " << msg );
246     return;
247 derek 2976 }
248     break;
249 derek 3064 case AcceptingReInvite:
250     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
251     {
252     mState = Connected;
253     //this shouldn't happen, but it may be allowed(DUM API doesn't
254     //support this for re-invite)
255     if (offans.first != None)
256     {
257     InviteSession::incomingSdp(msg, offans.second);
258     }
259     }
260     else
261     {
262     ErrLog ( << "Spurious message sent to UAS " << msg );
263     return;
264     }
265     break;
266    
267    
268 derek 2961 default:
269 derek 3024 DebugLog ( << "Throwing away strange message: " << msg );
270     //throw message away
271     // assert(0); //all other cases should be handled in base classes
272    
273 jason 2856 }
274     }
275    
276 derek 2955 SipMessage&
277 derek 3039 InviteSession::makeRefer(const NameAddr& referTo)
278 derek 2955 {
279 derek 3058 mDialog.makeRequest(mLastRequest, REFER);
280     mLastRequest.header(h_ReferTo) = referTo;
281     return mLastRequest;
282 derek 2955 }
283 jason 2856
284 jason 2809 SipMessage&
285 jason 2621 InviteSession::end()
286     {
287 derek 3006 InfoLog ( << "InviteSession::end, state: " << mState);
288 derek 2961 switch (mState)
289     {
290     case Terminated:
291 derek 2965 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
292 derek 2961 break;
293     case Connected:
294 derek 3006 case Accepting:
295     InfoLog ( << "InviteSession::end, connected or Accepting" );
296 derek 2961 mDialog.makeRequest(mLastRequest, BYE);
297 derek 2985 //new transaction
298     assert(mLastRequest.header(h_Vias).size() == 1);
299 derek 3079 // mLastRequest.header(h_Vias).front().param(p_branch).reset();
300 derek 2961 mState = Terminated;
301     return mLastRequest;
302     break;
303     default:
304     assert(0); // out of states
305     }
306 derek 2981 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
307 jason 2621 }
308    
309 jason 2809 // If sdp==0, it means the last offer failed
310 derek 2965 // !dcm! -- eventually handle confused UA's that send offers/answers at
311     // inappropriate times, probably with a different callback
312 jason 2846 void
313     InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
314 jason 2809 {
315     switch (mOfferState)
316     {
317 jason 2846 case Nothing:
318 jason 2809 assert(mCurrentLocalSdp == 0);
319     assert(mCurrentRemoteSdp == 0);
320 sgodin 3091 assert(mProposedLocalSdp == 0);
321     assert(mProposedRemoteSdp == 0);
322 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
323 jason 2809 mOfferState = Offerred;
324 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
325 jason 2809 break;
326    
327     case Offerred:
328 sgodin 3091 assert(mCurrentLocalSdp == 0);
329     assert(mCurrentRemoteSdp == 0);
330 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
331 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
332 sgodin 3091 delete mProposedRemoteSdp;
333 jason 2809 mProposedLocalSdp = 0;
334     mProposedRemoteSdp = 0;
335     mOfferState = Answered;
336 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
337 jason 2809 break;
338    
339     case Answered:
340     assert(mProposedLocalSdp == 0);
341     assert(mProposedRemoteSdp == 0);
342 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
343 jason 2809 mOfferState = CounterOfferred;
344 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
345 jason 2809 break;
346 derek 2965
347 jason 2809 case CounterOfferred:
348     assert(mCurrentLocalSdp);
349     assert(mCurrentRemoteSdp);
350 jason 2846 mOfferState = Answered;
351 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
352 jason 2809 {
353 derek 2965 delete mCurrentLocalSdp;
354     delete mCurrentRemoteSdp;
355 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
356 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
357 sgodin 3091 delete mProposedRemoteSdp;
358 derek 2965 mProposedLocalSdp = 0;
359     mProposedRemoteSdp = 0;
360     mOfferState = Answered;
361 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
362 jason 2809 }
363     else
364     {
365 sgodin 3091 delete mProposedLocalSdp;
366     delete mProposedRemoteSdp;
367 jason 2809 mProposedLocalSdp = 0;
368     mProposedRemoteSdp = 0;
369 jason 2846 // !jf! is this right?
370     mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
371 jason 2809 }
372     break;
373     }
374     }
375    
376 derek 2965 void
377     InviteSession::send(SipMessage& msg)
378     {
379     if (msg.isRequest())
380     {
381     //unless the message is an ACK(in which case it is mAck)
382     //strip out the SDP after sending
383 derek 3089 switch(msg.header(h_RequestLine).getMethod())
384     {
385     case INVITE:
386     case UPDATE:
387     if (mNextOfferOrAnswerSdp)
388     {
389 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
390 derek 3089 sendSdp(mNextOfferOrAnswerSdp);
391     mNextOfferOrAnswerSdp = 0;
392     }
393     break;
394     default:
395     break;
396     }
397    
398 derek 2965 if (msg.header(h_RequestLine).getMethod() == ACK)
399     {
400     mDum.send(msg);
401     }
402     else
403     {
404     mDum.send(msg);
405     msg.releaseContents();
406     }
407     }
408     else
409     {
410     int code = msg.header(h_StatusLine).statusCode();
411     //!dcm! -- probably kill this object earlier, handle 200 to bye in
412     //DialogUsageManager...very soon
413     if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
414    
415     {
416     mState = Terminated;
417     mDum.send(msg);
418     delete this;
419     }
420 derek 2978 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
421 derek 2965 {
422 derek 2978 assert(&msg == &mFinalResponse);
423 derek 2990 mCurrentRetransmit200 = T1;
424 derek 3079 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), 0);
425     mDum.addTimerMs(DumTimeout::WaitForAck, TimerH, getBaseHandle(), 0);
426 derek 2990
427     //!dcm! -- this should be mFinalResponse...maybe assign here in
428 derek 2965 //case the user wants to be very strange
429     if (mNextOfferOrAnswerSdp)
430     {
431 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
432 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
433 derek 2997 mNextOfferOrAnswerSdp = 0;
434 derek 2978 }
435     mDum.send(msg);
436     }
437     else
438     {
439     mDum.send(msg);
440     msg.releaseContents();
441     }
442 derek 2965 }
443     }
444    
445 jason 2621 void
446 derek 2965 InviteSession::sendSdp(SdpContents* sdp)
447 jason 2809 {
448     switch (mOfferState)
449     {
450 jason 2846 case Nothing:
451 jason 2809 assert(mCurrentLocalSdp == 0);
452     assert(mCurrentRemoteSdp == 0);
453 derek 2965 mProposedLocalSdp = sdp;
454 jason 2809 mOfferState = Offerred;
455     break;
456    
457     case Offerred:
458 sgodin 3091 assert(mCurrentLocalSdp == 0);
459     assert(mCurrentRemoteSdp == 0);
460 derek 2965 mCurrentLocalSdp = sdp;
461 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
462 sgodin 3091 delete mProposedLocalSdp;
463 jason 2809 mProposedLocalSdp = 0;
464     mProposedRemoteSdp = 0;
465     mOfferState = Answered;
466     break;
467    
468     case Answered:
469     assert(mProposedLocalSdp == 0);
470     assert(mProposedRemoteSdp == 0);
471 derek 2965 mProposedLocalSdp = sdp;
472 jason 2809 mOfferState = CounterOfferred;
473     break;
474    
475     case CounterOfferred:
476     assert(mCurrentLocalSdp);
477     assert(mCurrentRemoteSdp);
478 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
479 jason 2809 {
480 derek 3064 delete mCurrentLocalSdp;
481     delete mCurrentRemoteSdp;
482 sgodin 3091 mCurrentLocalSdp = sdp;
483 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
484 sgodin 3091 delete mProposedLocalSdp;
485     mProposedLocalSdp = 0;
486     mProposedRemoteSdp = 0;
487 jason 2809 }
488 sgodin 3091 else
489     {
490     delete mProposedLocalSdp;
491     delete mProposedRemoteSdp;
492     mProposedLocalSdp = 0;
493     mProposedRemoteSdp = 0;
494     }
495 jason 2809 mOfferState = Answered;
496     break;
497     }
498     }
499    
500 jason 2846 std::pair<InviteSession::OfferAnswerType, const SdpContents*>
501     InviteSession::getOfferOrAnswer(const SipMessage& msg) const
502     {
503     std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
504     ret.first = None;
505    
506     const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
507     if (contents)
508     {
509     static Token c100rel(Symbols::C100rel);
510 derek 2976 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
511 jason 2846 msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
512     {
513     switch (mOfferState)
514     {
515     case None:
516     ret.first = Offer;
517     ret.second = contents;
518     break;
519    
520     case Offerred:
521     ret.first = Answer;
522     ret.second = contents;
523     break;
524    
525     case Answered:
526     ret.first = Offer;
527     ret.second = contents;
528     break;
529    
530     case CounterOfferred:
531     ret.first = Answer;
532     ret.second = contents;
533     break;
534     }
535     }
536     }
537     return ret;
538     }
539    
540 jason 2809 void
541 jason 2621 InviteSession::copyAuthorizations(SipMessage& request)
542     {
543 jason 2725 #if 0
544 jason 2621 if (mLastRequest.exists(h_ProxyAuthorizations))
545     {
546     // should make the next auth (change nextNonce)
547     request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
548     }
549     if (mLastRequest.exists(h_ProxyAuthorizations))
550     {
551     // should make the next auth (change nextNonce)
552     request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
553     }
554 jason 2725 #endif
555 jason 2621 }
556    
557 derek 2955 SipMessage&
558 derek 2965 InviteSession::rejectOffer(int statusCode)
559     {
560 derek 3069 //sdp state change here--go to initial state?
561 derek 2976 mDialog.makeResponse(mLastResponse, mLastRequest, statusCode);
562     return mLastResponse;
563 derek 2965 }
564    
565     SipMessage&
566 derek 2955 InviteSession::targetRefresh(const NameAddr& localUri)
567     {
568     assert(0);
569 derek 2981 return mLastRequest;
570 derek 2955 }
571 davidb 2576
572 derek 2981 SipMessage&
573     InviteSession::ackConnection()
574     {
575     //if not a reinvite, and a pending offer exists, throw
576     makeAck();
577 derek 2985 //new transaction
578     assert(mAck.header(h_Vias).size() == 1);
579 derek 3079 // mAck.header(h_Vias).front().param(p_branch).reset();
580 derek 2981 return mAck;
581     }
582    
583 derek 2955 void
584 derek 2965 InviteSession::makeAck()
585 derek 2849 {
586 derek 2965 mAck = mLastRequest;
587 derek 2992
588     InfoLog ( << "InviteSession::makeAck:before: " << mAck );
589    
590 derek 2965 mDialog.makeRequest(mAck, ACK);
591     if (mNextOfferOrAnswerSdp)
592     {
593 sgodin 3091 mAck.setContents(mNextOfferOrAnswerSdp);
594 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
595 derek 2997 mNextOfferOrAnswerSdp = 0;
596 derek 2992 }
597    
598     InfoLog ( << "InviteSession::makeAck:after: " << mAck );
599 derek 2849 }
600    
601 davidb 2575 /* ====================================================================
602     * The Vovida Software License, Version 1.0
603     *
604     * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
605     *
606     * Redistribution and use in source and binary forms, with or without
607     * modification, are permitted provided that the following conditions
608     * are met:
609     *
610     * 1. Redistributions of source code must retain the above copyright
611     * notice, this list of conditions and the following disclaimer.
612     *
613     * 2. Redistributions in binary form must reproduce the above copyright
614     * notice, this list of conditions and the following disclaimer in
615     * the documentation and/or other materials provided with the
616    
617     * distribution.
618     *
619     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
620     * and "Vovida Open Communication Application Library (VOCAL)" must
621     * not be used to endorse or promote products derived from this
622     * software without prior written permission. For written
623     * permission, please contact vocal@vovida.org.
624     *
625     * 4. Products derived from this software may not be called "VOCAL", nor
626     * may "VOCAL" appear in their name, without prior written
627     * permission of Vovida Networks, Inc.
628     *
629     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
630     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
631     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
632     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
633     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
634     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
635     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
636     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
637     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
638     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
639     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
640     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
641     * DAMAGE.
642     *
643     * ====================================================================
644     *
645     * This software consists of voluntary contributions made by Vovida
646     * Networks, Inc. and many individuals on behalf of Vovida Networks,
647     * Inc. For more information on Vovida Networks, Inc., please see
648     * <http://www.vovida.org/>.
649     *
650     */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27