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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3112 - (hide annotations) (download)
Thu Jul 15 21:36:48 2004 UTC (15 years, 4 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 20758 byte(s)
DialogSet cancel change(deletion while iterating problem)
Dialog routeset now updated by 200
DialogUsageManager send copies message if ProcessStrictRoute will modify the message
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 derek 3101 //handled in Dialog
198     assert(0);
199 derek 2961 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 derek 3112 SipMessage&
285     InviteSession::makeRefer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
286     {
287     if (!sessionToReplace.isValid())
288     {
289     throw new UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
290     }
291    
292     mDialog.makeRequest(mLastRequest, REFER);
293     mLastRequest.header(h_ReferTo) = referTo;
294     CallId replaces;
295     DialogId id = sessionToReplace->mDialog.getId();
296     replaces.value() = id.getCallId();
297     replaces.param(p_toTag) = id.getRemoteTag();
298     replaces.param(p_fromTag) = id.getLocalTag();
299    
300     mLastRequest.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
301     return mLastRequest;
302     }
303    
304 jason 2809 SipMessage&
305 jason 2621 InviteSession::end()
306     {
307 derek 3006 InfoLog ( << "InviteSession::end, state: " << mState);
308 derek 2961 switch (mState)
309     {
310     case Terminated:
311 derek 2965 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
312 derek 2961 break;
313     case Connected:
314 derek 3006 case Accepting:
315     InfoLog ( << "InviteSession::end, connected or Accepting" );
316 derek 2961 mDialog.makeRequest(mLastRequest, BYE);
317 derek 2985 //new transaction
318     assert(mLastRequest.header(h_Vias).size() == 1);
319 derek 3079 // mLastRequest.header(h_Vias).front().param(p_branch).reset();
320 derek 2961 mState = Terminated;
321     return mLastRequest;
322     break;
323     default:
324     assert(0); // out of states
325     }
326 derek 2981 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
327 jason 2621 }
328    
329 jason 2809 // If sdp==0, it means the last offer failed
330 derek 2965 // !dcm! -- eventually handle confused UA's that send offers/answers at
331     // inappropriate times, probably with a different callback
332 jason 2846 void
333     InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
334 jason 2809 {
335     switch (mOfferState)
336     {
337 jason 2846 case Nothing:
338 jason 2809 assert(mCurrentLocalSdp == 0);
339     assert(mCurrentRemoteSdp == 0);
340 sgodin 3091 assert(mProposedLocalSdp == 0);
341     assert(mProposedRemoteSdp == 0);
342 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
343 jason 2809 mOfferState = Offerred;
344 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
345 jason 2809 break;
346    
347     case Offerred:
348 sgodin 3091 assert(mCurrentLocalSdp == 0);
349     assert(mCurrentRemoteSdp == 0);
350 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
351 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
352 sgodin 3091 delete mProposedRemoteSdp;
353 jason 2809 mProposedLocalSdp = 0;
354     mProposedRemoteSdp = 0;
355     mOfferState = Answered;
356 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
357 jason 2809 break;
358    
359     case Answered:
360     assert(mProposedLocalSdp == 0);
361     assert(mProposedRemoteSdp == 0);
362 jason 2846 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
363 jason 2809 mOfferState = CounterOfferred;
364 jason 2846 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
365 jason 2809 break;
366 derek 2965
367 jason 2809 case CounterOfferred:
368     assert(mCurrentLocalSdp);
369     assert(mCurrentRemoteSdp);
370 jason 2846 mOfferState = Answered;
371 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
372 jason 2809 {
373 derek 2965 delete mCurrentLocalSdp;
374     delete mCurrentRemoteSdp;
375 jason 2809 mCurrentLocalSdp = mProposedLocalSdp;
376 jason 2846 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
377 sgodin 3091 delete mProposedRemoteSdp;
378 derek 2965 mProposedLocalSdp = 0;
379     mProposedRemoteSdp = 0;
380     mOfferState = Answered;
381 jason 2846 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
382 jason 2809 }
383     else
384     {
385 sgodin 3091 delete mProposedLocalSdp;
386     delete mProposedRemoteSdp;
387 jason 2809 mProposedLocalSdp = 0;
388     mProposedRemoteSdp = 0;
389 jason 2846 // !jf! is this right?
390     mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
391 jason 2809 }
392     break;
393     }
394     }
395    
396 derek 2965 void
397     InviteSession::send(SipMessage& msg)
398     {
399     if (msg.isRequest())
400     {
401     //unless the message is an ACK(in which case it is mAck)
402     //strip out the SDP after sending
403 derek 3089 switch(msg.header(h_RequestLine).getMethod())
404     {
405     case INVITE:
406     case UPDATE:
407     if (mNextOfferOrAnswerSdp)
408     {
409 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
410 derek 3089 sendSdp(mNextOfferOrAnswerSdp);
411     mNextOfferOrAnswerSdp = 0;
412     }
413     break;
414     default:
415     break;
416     }
417    
418 derek 2965 if (msg.header(h_RequestLine).getMethod() == ACK)
419     {
420     mDum.send(msg);
421     }
422     else
423     {
424     mDum.send(msg);
425     msg.releaseContents();
426     }
427     }
428     else
429     {
430     int code = msg.header(h_StatusLine).statusCode();
431     //!dcm! -- probably kill this object earlier, handle 200 to bye in
432     //DialogUsageManager...very soon
433     if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
434    
435     {
436     mState = Terminated;
437     mDum.send(msg);
438     delete this;
439     }
440 derek 2978 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
441 derek 2965 {
442 derek 2978 assert(&msg == &mFinalResponse);
443 derek 2990 mCurrentRetransmit200 = T1;
444 derek 3079 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), 0);
445     mDum.addTimerMs(DumTimeout::WaitForAck, TimerH, getBaseHandle(), 0);
446 derek 2990
447     //!dcm! -- this should be mFinalResponse...maybe assign here in
448 derek 2965 //case the user wants to be very strange
449     if (mNextOfferOrAnswerSdp)
450     {
451 sgodin 3091 msg.setContents(mNextOfferOrAnswerSdp);
452 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
453 derek 2997 mNextOfferOrAnswerSdp = 0;
454 derek 2978 }
455     mDum.send(msg);
456     }
457     else
458     {
459     mDum.send(msg);
460     msg.releaseContents();
461     }
462 derek 2965 }
463     }
464    
465 jason 2621 void
466 derek 2965 InviteSession::sendSdp(SdpContents* sdp)
467 jason 2809 {
468     switch (mOfferState)
469     {
470 jason 2846 case Nothing:
471 jason 2809 assert(mCurrentLocalSdp == 0);
472     assert(mCurrentRemoteSdp == 0);
473 derek 2965 mProposedLocalSdp = sdp;
474 jason 2809 mOfferState = Offerred;
475     break;
476    
477     case Offerred:
478 sgodin 3091 assert(mCurrentLocalSdp == 0);
479     assert(mCurrentRemoteSdp == 0);
480 derek 2965 mCurrentLocalSdp = sdp;
481 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
482 sgodin 3091 delete mProposedLocalSdp;
483 jason 2809 mProposedLocalSdp = 0;
484     mProposedRemoteSdp = 0;
485     mOfferState = Answered;
486     break;
487    
488     case Answered:
489     assert(mProposedLocalSdp == 0);
490     assert(mProposedRemoteSdp == 0);
491 derek 2965 mProposedLocalSdp = sdp;
492 jason 2809 mOfferState = CounterOfferred;
493     break;
494    
495     case CounterOfferred:
496     assert(mCurrentLocalSdp);
497     assert(mCurrentRemoteSdp);
498 sgodin 3071 if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0
499 jason 2809 {
500 derek 3064 delete mCurrentLocalSdp;
501     delete mCurrentRemoteSdp;
502 sgodin 3091 mCurrentLocalSdp = sdp;
503 jason 2809 mCurrentRemoteSdp = mProposedRemoteSdp;
504 sgodin 3091 delete mProposedLocalSdp;
505     mProposedLocalSdp = 0;
506     mProposedRemoteSdp = 0;
507 jason 2809 }
508 sgodin 3091 else
509     {
510     delete mProposedLocalSdp;
511     delete mProposedRemoteSdp;
512     mProposedLocalSdp = 0;
513     mProposedRemoteSdp = 0;
514     }
515 jason 2809 mOfferState = Answered;
516     break;
517     }
518     }
519    
520 jason 2846 std::pair<InviteSession::OfferAnswerType, const SdpContents*>
521     InviteSession::getOfferOrAnswer(const SipMessage& msg) const
522     {
523     std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
524     ret.first = None;
525    
526     const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
527     if (contents)
528     {
529     static Token c100rel(Symbols::C100rel);
530 derek 2976 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
531 jason 2846 msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
532     {
533     switch (mOfferState)
534     {
535     case None:
536     ret.first = Offer;
537     ret.second = contents;
538     break;
539    
540     case Offerred:
541     ret.first = Answer;
542     ret.second = contents;
543     break;
544    
545     case Answered:
546     ret.first = Offer;
547     ret.second = contents;
548     break;
549    
550     case CounterOfferred:
551     ret.first = Answer;
552     ret.second = contents;
553     break;
554     }
555     }
556     }
557     return ret;
558     }
559    
560 jason 2809 void
561 jason 2621 InviteSession::copyAuthorizations(SipMessage& request)
562     {
563 jason 2725 #if 0
564 jason 2621 if (mLastRequest.exists(h_ProxyAuthorizations))
565     {
566     // should make the next auth (change nextNonce)
567     request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
568     }
569     if (mLastRequest.exists(h_ProxyAuthorizations))
570     {
571     // should make the next auth (change nextNonce)
572     request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
573     }
574 jason 2725 #endif
575 jason 2621 }
576    
577 derek 2955 SipMessage&
578 derek 2965 InviteSession::rejectOffer(int statusCode)
579     {
580 derek 3101 if (statusCode < 400)
581     {
582     throw new UsageUseException("Must reject with a 4xx", __FILE__, __LINE__);
583     }
584 derek 3069 //sdp state change here--go to initial state?
585 derek 2976 mDialog.makeResponse(mLastResponse, mLastRequest, statusCode);
586     return mLastResponse;
587 derek 2965 }
588    
589     SipMessage&
590 derek 2955 InviteSession::targetRefresh(const NameAddr& localUri)
591     {
592     assert(0);
593 derek 2981 return mLastRequest;
594 derek 2955 }
595 davidb 2576
596 derek 2981 SipMessage&
597     InviteSession::ackConnection()
598     {
599     //if not a reinvite, and a pending offer exists, throw
600     makeAck();
601 derek 2985 //new transaction
602     assert(mAck.header(h_Vias).size() == 1);
603 derek 3079 // mAck.header(h_Vias).front().param(p_branch).reset();
604 derek 2981 return mAck;
605     }
606    
607 derek 2955 void
608 derek 2965 InviteSession::makeAck()
609 derek 2849 {
610 derek 2965 mAck = mLastRequest;
611 derek 2992
612     InfoLog ( << "InviteSession::makeAck:before: " << mAck );
613    
614 derek 2965 mDialog.makeRequest(mAck, ACK);
615     if (mNextOfferOrAnswerSdp)
616     {
617 sgodin 3091 mAck.setContents(mNextOfferOrAnswerSdp);
618 derek 2965 sendSdp(mNextOfferOrAnswerSdp);
619 derek 2997 mNextOfferOrAnswerSdp = 0;
620 derek 2992 }
621    
622     InfoLog ( << "InviteSession::makeAck:after: " << mAck );
623 derek 2849 }
624    
625 davidb 2575 /* ====================================================================
626     * The Vovida Software License, Version 1.0
627     *
628     * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
629     *
630     * Redistribution and use in source and binary forms, with or without
631     * modification, are permitted provided that the following conditions
632     * are met:
633     *
634     * 1. Redistributions of source code must retain the above copyright
635     * notice, this list of conditions and the following disclaimer.
636     *
637     * 2. Redistributions in binary form must reproduce the above copyright
638     * notice, this list of conditions and the following disclaimer in
639     * the documentation and/or other materials provided with the
640    
641     * distribution.
642     *
643     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
644     * and "Vovida Open Communication Application Library (VOCAL)" must
645     * not be used to endorse or promote products derived from this
646     * software without prior written permission. For written
647     * permission, please contact vocal@vovida.org.
648     *
649     * 4. Products derived from this software may not be called "VOCAL", nor
650     * may "VOCAL" appear in their name, without prior written
651     * permission of Vovida Networks, Inc.
652     *
653     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
654     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
655     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
656     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
657     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
658     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
659     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
660     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
661     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
662     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
663     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
664     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
665     * DAMAGE.
666     *
667     * ====================================================================
668     *
669     * This software consists of voluntary contributions made by Vovida
670     * Networks, Inc. and many individuals on behalf of Vovida Networks,
671     * Inc. For more information on Vovida Networks, Inc., please see
672     * <http://www.vovida.org/>.
673     *
674     */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27