4 * H.450 Helper functions
8 * Copyright (c) 2001 Norwood Systems Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.30 2006/06/27 12:35:03 csoutheren
28 * Patch 1366328 - Support for H.450.3 divertingLegInformation2
29 * Thanks to Norbert Bartalsky
31 * Revision 1.29 2006/05/16 11:38:27 shorne
32 * Added DNS SRV support
34 * Revision 1.28 2006/01/26 03:43:06 shorne
37 * Revision 1.27 2005/07/12 12:28:57 csoutheren
38 * Fixes for H.450 errors and return values
39 * Thanks to Iker Perez San Roman
41 * Revision 1.26 2005/06/27 00:36:45 csoutheren
42 * Added missing return after error
43 * Thanks to Iker Pérez de San Román
45 * Revision 1.25 2005/03/10 07:01:30 csoutheren
46 * Fixed problem with H.450 call identifiers not being unique across all calls on an
47 * endpoint. Thanks to Thien Nguyen
49 * Revision 1.24 2004/07/03 06:51:37 rjongbloed
50 * Added PTRACE_PARAM() macro to fix warnings on parameters used in PTRACE
53 * Revision 1.23 2004/04/25 01:52:47 rjongbloed
54 * Fixed GCC 3.4 warnings
56 * Revision 1.22 2004/02/17 09:53:54 csoutheren
57 * Removed incorrect assignment of m_silentMonitoringPermitted to FALSE
58 * See SourceForge bug 832371
59 * Thanks to Vyacheslav E. Andrejev
61 * Revision 1.21 2004/02/07 03:35:56 rjongbloed
62 * Fixed missing unlocks in some H.240 operations, in particular consultation transfer never being cleaned up. Thanks Sébastien Annedouche
64 * Revision 1.20 2003/07/15 11:22:07 csoutheren
65 * Improved handling of alias addresses thanks to Federico Pinna
67 * Revision 1.19 2002/11/21 22:37:47 robertj
68 * Fixed problems with unrecognized invoke APDU, thanks Andrea Bondavalli
70 * Revision 1.18 2002/10/01 06:47:39 robertj
71 * Fixed GNU compiler warning
73 * Revision 1.17 2002/09/25 05:21:11 robertj
74 * Fixed warning on no trace version.
76 * Revision 1.16 2002/08/05 10:03:47 robertj
77 * Cosmetic changes to normalise the usage of pragma interface/implementation.
79 * Revision 1.15 2002/07/04 00:40:34 robertj
80 * More H.450.11 call intrusion implementation, thanks Aleksandar Todorovic
82 * Revision 1.14 2002/06/25 09:56:07 robertj
85 * Revision 1.13 2002/06/22 05:48:42 robertj
86 * Added partial implementation for H.450.11 Call Intrusion
88 * Revision 1.12 2002/06/13 06:13:28 robertj
89 * Added trace dumps for outgoing H.450 supplementary service APDU's.
91 * Revision 1.11 2002/02/04 07:17:56 robertj
92 * Added H.450.2 Consultation Transfer, thanks Norwood Systems.
94 * Revision 1.10 2002/01/14 00:03:01 robertj
96 * Added extra "failure mode" parts of H.250.2.
97 * Various other bug fixes.
98 * Thanks Ben Madsen of Norwood Systems
100 * Revision 1.9 2001/11/19 07:40:44 robertj
101 * Fixed problem with error detection & state change in Call Transfer, thanks Graeme Reid
103 * Revision 1.8 2001/08/27 03:59:16 robertj
104 * Fixed GNU warnings.
106 * Revision 1.7 2001/08/16 07:49:19 robertj
107 * Changed the H.450 support to be more extensible. Protocol handlers
108 * are now in separate classes instead of all in H323Connection.
110 * Revision 1.6 2001/08/06 03:08:57 robertj
111 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
113 * Revision 1.5 2001/06/14 06:25:16 robertj
114 * Added further H.225 PDU build functions.
115 * Moved some functionality from connection to PDU class.
117 * Revision 1.4 2001/06/05 03:14:41 robertj
118 * Upgraded H.225 ASN to v4 and H.245 ASN to v7.
120 * Revision 1.3 2001/05/09 04:59:04 robertj
121 * Bug fixes in H.450.2, thanks Klein Stefan.
123 * Revision 1.2 2001/04/20 02:16:53 robertj
124 * Removed GNU C++ warnings.
126 * Revision 1.1 2001/04/11 03:01:29 robertj
127 * Added H.450.2 (call transfer), thanks a LOT to Graeme Reid & Norwood Systems
134 #pragma implementation "h450pdu.h"
151 X880_Invoke
& H450ServiceAPDU::BuildInvoke(int invokeId
, int operation
)
153 SetTag(X880_ROS::e_invoke
);
154 X880_Invoke
& invoke
= (X880_Invoke
&) *this;
156 invoke
.m_invokeId
= invokeId
;
158 invoke
.m_opcode
.SetTag(X880_Code::e_local
);
159 PASN_Integer
& opcode
= (PASN_Integer
&) invoke
.m_opcode
;
160 opcode
.SetValue(operation
);
166 X880_ReturnResult
& H450ServiceAPDU::BuildReturnResult(int invokeId
)
168 SetTag(X880_ROS::e_returnResult
);
169 X880_ReturnResult
& returnResult
= (X880_ReturnResult
&) *this;
171 returnResult
.m_invokeId
= invokeId
;
177 X880_ReturnError
& H450ServiceAPDU::BuildReturnError(int invokeId
, int error
)
179 SetTag(X880_ROS::e_returnError
);
180 X880_ReturnError
& returnError
= (X880_ReturnError
&) *this;
182 returnError
.m_invokeId
= invokeId
;
184 returnError
.m_errorCode
.SetTag(X880_Code::e_local
);
185 PASN_Integer
& errorCode
= (PASN_Integer
&) returnError
.m_errorCode
;
186 errorCode
.SetValue(error
);
192 X880_Reject
& H450ServiceAPDU::BuildReject(int invokeId
)
194 SetTag(X880_ROS::e_reject
);
195 X880_Reject
& reject
= (X880_Reject
&) *this;
197 reject
.m_invokeId
= invokeId
;
203 void H450ServiceAPDU::BuildCallTransferInitiate(int invokeId
,
204 const PString
& callIdentity
,
205 const PString
& alias
,
206 const H323TransportAddress
& address
)
208 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H4502_CallTransferOperation::e_callTransferInitiate
);
210 H4502_CTInitiateArg argument
;
212 argument
.m_callIdentity
= callIdentity
;
214 H4501_ArrayOf_AliasAddress
& aliasAddress
= argument
.m_reroutingNumber
.m_destinationAddress
;
216 // We have to have at least a destination transport address or alias.
217 if (!alias
.IsEmpty() && !address
.IsEmpty()) {
218 aliasAddress
.SetSize(2);
221 aliasAddress
[1].SetTag(H225_AliasAddress::e_dialedDigits
);
222 H323SetAliasAddress(alias
, aliasAddress
[1]);
225 aliasAddress
[0].SetTag(H225_AliasAddress::e_transportID
);
226 H225_TransportAddress
& cPartyTransport
= (H225_TransportAddress
&) aliasAddress
[0];
227 address
.SetPDU(cPartyTransport
);
230 aliasAddress
.SetSize(1);
231 if (alias
.IsEmpty()) {
232 // Set the transport, no alias present
233 aliasAddress
[0].SetTag(H225_AliasAddress::e_transportID
);
234 H225_TransportAddress
& cPartyTransport
= (H225_TransportAddress
&) aliasAddress
[0];
235 address
.SetPDU(cPartyTransport
);
238 // Set the alias, no transport
239 aliasAddress
[0].SetTag(H225_AliasAddress::e_dialedDigits
);
240 H323SetAliasAddress(alias
, aliasAddress
[0]);
244 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
245 << setprecision(2) << argument
);
247 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
248 invoke
.m_argument
.EncodeSubType(argument
);
252 void H450ServiceAPDU::BuildCallTransferSetup(int invokeId
,
253 const PString
& callIdentity
)
255 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H4502_CallTransferOperation::e_callTransferSetup
);
257 H4502_CTSetupArg argument
;
259 argument
.m_callIdentity
= callIdentity
;
261 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
262 << setprecision(2) << argument
);
264 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
265 invoke
.m_argument
.EncodeSubType(argument
);
269 void H450ServiceAPDU::BuildCallTransferIdentify(int invokeId
)
271 X880_Invoke invoke
= BuildInvoke(invokeId
, H4502_CallTransferOperation::e_callTransferIdentify
);
275 void H450ServiceAPDU::BuildCallTransferAbandon(int invokeId
)
277 X880_Invoke invoke
= BuildInvoke(invokeId
, H4502_CallTransferOperation::e_callTransferAbandon
);
281 void H450ServiceAPDU::BuildCallWaiting(int invokeId
, int numCallsWaiting
)
283 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H4506_CallWaitingOperations::e_callWaiting
);
285 H4506_CallWaitingArg argument
;
287 argument
.IncludeOptionalField(H4506_CallWaitingArg::e_nbOfAddWaitingCalls
);
288 argument
.m_nbOfAddWaitingCalls
= numCallsWaiting
;
290 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
291 << setprecision(2) << argument
);
293 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
294 invoke
.m_argument
.EncodeSubType(argument
);
298 void H450ServiceAPDU::BuildCallIntrusionForcedRelease(int invokeId
,
301 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease
);
303 H45011_CIFrcRelArg argument
;
305 argument
.m_ciCapabilityLevel
= CICL
;
307 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
308 invoke
.m_argument
.EncodeSubType(argument
);
312 X880_ReturnResult
& H450ServiceAPDU::BuildCallIntrusionForcedReleaseResult(int invokeId
)
314 PTRACE(1 ,"H450.11\tH450ServiceAPDU::BuildCallIntrusionForcedReleaseResult BEGIN");
316 X880_ReturnResult
& result
= BuildReturnResult(invokeId
);
317 result
.IncludeOptionalField(X880_ReturnResult::e_result
);
318 result
.m_result
.m_opcode
.SetTag(X880_Code::e_local
);
319 PASN_Integer
& operation
= (PASN_Integer
&) result
.m_result
.m_opcode
;
320 operation
.SetValue(H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease
);
322 H45011_CIFrcRelOptRes ciCIPLRes
;
324 PPER_Stream resultStream
;
325 ciCIPLRes
.Encode(resultStream
);
326 resultStream
.CompleteEncoding();
327 result
.m_result
.m_result
.SetValue(resultStream
);
328 PTRACE(4 ,"H450.11\tH450ServiceAPDU::BuildCallIntrusionForcedReleaseResult END");
334 void H450ServiceAPDU::BuildCallIntrusionForcedReleaseError()
342 void H450ServiceAPDU::BuildCallIntrusionGetCIPL(int invokeId
)
344 PTRACE(4, "H450.11\tBuildCallIntrusionGetCIPL invokeId=" << invokeId
);
345 X880_Invoke invoke
= BuildInvoke(invokeId
, H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL
);
349 void H450ServiceAPDU::BuildCallIntrusionImpending(int invokeId
)
351 PTRACE(4, "H450.11\tBuildCallIntrusionImpending invokeId=" << invokeId
);
352 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H45011_H323CallIntrusionOperations::e_callIntrusionNotification
);
354 H45011_CINotificationArg argument
;
356 argument
.m_ciStatusInformation
= H45011_CIStatusInformation::e_callIntrusionImpending
;
358 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
359 invoke
.m_argument
.EncodeSubType(argument
);
363 void H450ServiceAPDU::BuildCallIntrusionForceRelesed(int invokeId
)
365 PTRACE(4, "H450.11\tBuildCallIntrusionForceRelesed invokeId=" << invokeId
);
366 X880_Invoke
& invoke
= BuildInvoke(invokeId
, H45011_H323CallIntrusionOperations::e_callIntrusionNotification
);
368 H45011_CINotificationArg argument
;
370 argument
.m_ciStatusInformation
= H45011_CIStatusInformation::e_callForceReleased
;
372 invoke
.IncludeOptionalField(X880_Invoke::e_argument
);
373 invoke
.m_argument
.EncodeSubType(argument
);
377 void H450ServiceAPDU::AttachSupplementaryServiceAPDU(H323SignalPDU
& pdu
)
379 H4501_SupplementaryService supplementaryService
;
381 // Create an H.450.1 supplementary service object
382 // and store the H450ServiceAPDU in the ROS array.
383 supplementaryService
.m_serviceApdu
.SetTag(H4501_ServiceApdus::e_rosApdus
);
384 H4501_ArrayOf_ROS
& operations
= (H4501_ArrayOf_ROS
&)supplementaryService
.m_serviceApdu
;
385 operations
.SetSize(1);
386 operations
[0] = *this;
388 PTRACE(4, "H4501\tSending supplementary service PDU:\n "
389 << setprecision(2) << supplementaryService
);
391 // Add the H.450 PDU to the H.323 User-to-User PDU as an OCTET STRING
392 pdu
.m_h323_uu_pdu
.IncludeOptionalField(H225_H323_UU_PDU::e_h4501SupplementaryService
);
393 pdu
.m_h323_uu_pdu
.m_h4501SupplementaryService
.SetSize(1);
394 pdu
.m_h323_uu_pdu
.m_h4501SupplementaryService
[0].EncodeSubType(supplementaryService
);
398 BOOL
H450ServiceAPDU::WriteFacilityPDU(H323Connection
& connection
)
400 H323SignalPDU facilityPDU
;
401 facilityPDU
.BuildFacility(connection
, TRUE
);
403 AttachSupplementaryServiceAPDU(facilityPDU
);
405 return connection
.WriteSignalPDU(facilityPDU
);
409 void H450ServiceAPDU::ParseEndpointAddress(H4501_EndpointAddress
& endpointAddress
,
410 PString
& remoteParty
)
412 H4501_ArrayOf_AliasAddress
& destinationAddress
= endpointAddress
.m_destinationAddress
;
415 H323TransportAddress transportAddress
;
417 for (PINDEX i
= 0; i
< destinationAddress
.GetSize(); i
++) {
418 H225_AliasAddress
& aliasAddress
= destinationAddress
[i
];
420 if (aliasAddress
.GetTag() == H225_AliasAddress::e_transportID
)
421 transportAddress
= (H225_TransportAddress
&)aliasAddress
;
423 alias
= ::H323GetAliasAddressString(aliasAddress
);
426 if (alias
.IsEmpty()) {
427 remoteParty
= transportAddress
;
429 else if (transportAddress
.IsEmpty()) {
433 remoteParty
= alias
+ '@' + transportAddress
;
438 /////////////////////////////////////////////////////////////////////////////
440 H450xDispatcher::H450xDispatcher(H323Connection
& conn
)
443 opcodeHandler
.DisallowDeleteObjects();
449 void H450xDispatcher::AddOpCode(unsigned opcode
, H450xHandler
* handler
)
451 if (PAssertNULL(handler
) == NULL
)
454 if (handlers
.GetObjectsIndex(handler
) == P_MAX_INDEX
)
455 handlers
.Append(handler
);
457 opcodeHandler
.SetAt(opcode
, handler
);
461 void H450xDispatcher::AttachToSetup(H323SignalPDU
& pdu
)
463 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++)
464 handlers
[i
].AttachToSetup(pdu
);
468 void H450xDispatcher::AttachToAlerting(H323SignalPDU
& pdu
)
470 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++)
471 handlers
[i
].AttachToAlerting(pdu
);
475 void H450xDispatcher::AttachToConnect(H323SignalPDU
& pdu
)
477 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++)
478 handlers
[i
].AttachToConnect(pdu
);
482 void H450xDispatcher::AttachToReleaseComplete(H323SignalPDU
& pdu
)
484 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++)
485 handlers
[i
].AttachToReleaseComplete(pdu
);
489 BOOL
H450xDispatcher::HandlePDU(const H323SignalPDU
& pdu
)
492 for (PINDEX i
= 0; i
< pdu
.m_h323_uu_pdu
.m_h4501SupplementaryService
.GetSize(); i
++) {
493 H4501_SupplementaryService supplementaryService
;
495 // Decode the supplementary service PDU from the PPER Stream
496 if (pdu
.m_h323_uu_pdu
.m_h4501SupplementaryService
[i
].DecodeSubType(supplementaryService
)) {
497 PTRACE(4, "H4501\tReceived supplementary service PDU:\n "
498 << setprecision(2) << supplementaryService
);
501 PTRACE(1, "H4501\tInvalid supplementary service PDU decode:\n "
502 << setprecision(2) << supplementaryService
);
506 H4501_InterpretationApdu
& interpretation
= supplementaryService
.m_interpretationApdu
;
508 if (supplementaryService
.m_serviceApdu
.GetTag() == H4501_ServiceApdus::e_rosApdus
) {
509 H4501_ArrayOf_ROS
& operations
= (H4501_ArrayOf_ROS
&) supplementaryService
.m_serviceApdu
;
511 for (PINDEX j
= 0; j
< operations
.GetSize(); j
++) {
512 X880_ROS
& operation
= operations
[j
];
514 PTRACE(3, "H4501\tX880 ROS " << operation
.GetTagName());
516 switch (operation
.GetTag()) {
517 case X880_ROS::e_invoke
:
518 result
= OnReceivedInvoke((X880_Invoke
&)operation
, interpretation
);
521 case X880_ROS::e_returnResult
:
522 result
= OnReceivedReturnResult((X880_ReturnResult
&)operation
);
525 case X880_ROS::e_returnError
:
526 result
= OnReceivedReturnError((X880_ReturnError
&)operation
);
529 case X880_ROS::e_reject
:
530 result
= OnReceivedReject((X880_Reject
&)operation
);
542 BOOL
H450xDispatcher::OnReceivedInvoke(X880_Invoke
& invoke
, H4501_InterpretationApdu
& interpretation
)
546 int invokeId
= invoke
.m_invokeId
.GetValue();
548 // Get the linkedId if present
550 if (invoke
.HasOptionalField(X880_Invoke::e_linkedId
)) {
551 linkedId
= invoke
.m_linkedId
.GetValue();
554 // Get the argument if present
555 PASN_OctetString
* argument
= NULL
;
556 if (invoke
.HasOptionalField(X880_Invoke::e_argument
)) {
557 argument
= &invoke
.m_argument
;
561 if (invoke
.m_opcode
.GetTag() == X880_Code::e_local
) {
562 int opcode
= ((PASN_Integer
&) invoke
.m_opcode
).GetValue();
563 if (!opcodeHandler
.Contains(opcode
)) {
564 PTRACE(2, "H4501\tInvoke of unsupported local opcode:\n " << invoke
);
565 if (interpretation
.GetTag() != H4501_InterpretationApdu::e_discardAnyUnrecognizedInvokePdu
)
566 SendInvokeReject(invokeId
, 1 /*X880_InvokeProblem::e_unrecognisedOperation*/);
567 if (interpretation
.GetTag() == H4501_InterpretationApdu::e_clearCallIfAnyInvokePduNotRecognized
)
571 result
= opcodeHandler
[opcode
].OnReceivedInvoke(opcode
, invokeId
, linkedId
, argument
);
574 if (interpretation
.GetTag() != H4501_InterpretationApdu::e_discardAnyUnrecognizedInvokePdu
)
575 SendInvokeReject(invokeId
, 1 /*X880_InvokeProblem::e_unrecognisedOperation*/);
576 PTRACE(2, "H4501\tInvoke of unsupported global opcode:\n " << invoke
);
577 if (interpretation
.GetTag() == H4501_InterpretationApdu::e_clearCallIfAnyInvokePduNotRecognized
)
584 BOOL
H450xDispatcher::OnReceivedReturnResult(X880_ReturnResult
& returnResult
)
586 unsigned invokeId
= returnResult
.m_invokeId
.GetValue();
588 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++) {
589 if (handlers
[i
].GetInvokeId() == invokeId
) {
590 handlers
[i
].OnReceivedReturnResult(returnResult
);
598 BOOL
H450xDispatcher::OnReceivedReturnError(X880_ReturnError
& returnError
)
601 unsigned invokeId
= returnError
.m_invokeId
.GetValue();
604 if (returnError
.m_errorCode
.GetTag() == X880_Code::e_local
)
605 errorCode
= ((PASN_Integer
&) returnError
.m_errorCode
).GetValue();
607 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++) {
608 if (handlers
[i
].GetInvokeId() == invokeId
) {
609 result
= handlers
[i
].OnReceivedReturnError(errorCode
, returnError
);
617 BOOL
H450xDispatcher::OnReceivedReject(X880_Reject
& reject
)
621 switch (reject
.m_problem
.GetTag()) {
622 case X880_Reject_problem::e_general
:
624 X880_GeneralProblem
& generalProblem
= reject
.m_problem
;
625 problem
= generalProblem
.GetValue();
629 case X880_Reject_problem::e_invoke
:
631 X880_InvokeProblem
& invokeProblem
= reject
.m_problem
;
632 problem
= invokeProblem
.GetValue();
636 case X880_Reject_problem::e_returnResult
:
638 X880_ReturnResultProblem
& returnResultProblem
= reject
.m_problem
;
639 problem
= returnResultProblem
.GetValue();
643 case X880_Reject_problem::e_returnError
:
645 X880_ReturnErrorProblem
& returnErrorProblem
= reject
.m_problem
;
646 problem
= returnErrorProblem
.GetValue();
655 unsigned invokeId
= reject
.m_invokeId
;
656 for (PINDEX i
= 0; i
< handlers
.GetSize(); i
++) {
657 if (handlers
[i
].GetInvokeId() == invokeId
) {
658 handlers
[i
].OnReceivedReject(reject
.m_problem
.GetTag(), problem
);
666 void H450xDispatcher::SendReturnError(int invokeId
, int returnError
)
668 H450ServiceAPDU serviceAPDU
;
670 serviceAPDU
.BuildReturnError(invokeId
, returnError
);
672 serviceAPDU
.WriteFacilityPDU(connection
);
676 void H450xDispatcher::SendGeneralReject(int invokeId
, int problem
)
678 H450ServiceAPDU serviceAPDU
;
680 X880_Reject
& reject
= serviceAPDU
.BuildReject(invokeId
);
681 reject
.m_problem
.SetTag(X880_Reject_problem::e_general
);
682 X880_GeneralProblem
& generalProblem
= (X880_GeneralProblem
&) reject
.m_problem
;
683 generalProblem
= problem
;
685 serviceAPDU
.WriteFacilityPDU(connection
);
689 void H450xDispatcher::SendInvokeReject(int invokeId
, int problem
)
691 H450ServiceAPDU serviceAPDU
;
693 X880_Reject
& reject
= serviceAPDU
.BuildReject(invokeId
);
694 reject
.m_problem
.SetTag(X880_Reject_problem::e_invoke
);
695 X880_InvokeProblem
& invokeProblem
= (X880_InvokeProblem
&) reject
.m_problem
;
696 invokeProblem
= problem
;
698 serviceAPDU
.WriteFacilityPDU(connection
);
702 void H450xDispatcher::SendReturnResultReject(int invokeId
, int problem
)
704 H450ServiceAPDU serviceAPDU
;
706 X880_Reject
& reject
= serviceAPDU
.BuildReject(invokeId
);
707 reject
.m_problem
.SetTag(X880_Reject_problem::e_returnResult
);
708 X880_ReturnResultProblem
& returnResultProblem
= reject
.m_problem
;
709 returnResultProblem
= problem
;
711 serviceAPDU
.WriteFacilityPDU(connection
);
715 void H450xDispatcher::SendReturnErrorReject(int invokeId
, int problem
)
717 H450ServiceAPDU serviceAPDU
;
719 X880_Reject
& reject
= serviceAPDU
.BuildReject(invokeId
);
720 reject
.m_problem
.SetTag(X880_Reject_problem::e_returnError
);
721 X880_ReturnErrorProblem
& returnErrorProblem
= reject
.m_problem
;
722 returnErrorProblem
= problem
;
724 serviceAPDU
.WriteFacilityPDU(connection
);
728 /////////////////////////////////////////////////////////////////////////////
730 H450xHandler::H450xHandler(H323Connection
& conn
, H450xDispatcher
& disp
)
731 : endpoint(conn
.GetEndPoint()),
739 void H450xHandler::AttachToSetup(H323SignalPDU
&)
744 void H450xHandler::AttachToAlerting(H323SignalPDU
&)
749 void H450xHandler::AttachToConnect(H323SignalPDU
&)
754 void H450xHandler::AttachToReleaseComplete(H323SignalPDU
&)
759 BOOL
H450xHandler::OnReceivedReturnResult(X880_ReturnResult
& /*returnResult*/)
765 BOOL
H450xHandler::OnReceivedReturnError(int /*errorCode*/,
766 X880_ReturnError
& /*returnError*/)
772 BOOL
H450xHandler::OnReceivedReject(int /*problemType*/,
773 int /*problemNumber*/)
779 void H450xHandler::SendReturnError(int returnError
)
781 dispatcher
.SendReturnError(currentInvokeId
, returnError
);
786 void H450xHandler::SendGeneralReject(int problem
)
788 dispatcher
.SendGeneralReject(currentInvokeId
, problem
);
793 void H450xHandler::SendInvokeReject(int problem
)
795 dispatcher
.SendInvokeReject(currentInvokeId
, problem
);
800 void H450xHandler::SendReturnResultReject(int problem
)
802 dispatcher
.SendReturnResultReject(currentInvokeId
, problem
);
807 void H450xHandler::SendReturnErrorReject(int problem
)
809 dispatcher
.SendReturnErrorReject(currentInvokeId
, problem
);
814 BOOL
H450xHandler::DecodeArguments(PASN_OctetString
* argString
,
815 PASN_Object
& argObject
,
818 if (argString
== NULL
) {
819 if (absentErrorCode
>= 0)
820 SendReturnError(absentErrorCode
);
824 PPER_Stream
argStream(*argString
);
825 if (argObject
.Decode(argStream
)) {
826 PTRACE(4, "H4501\tSupplementary service argument:\n "
827 << setprecision(2) << argObject
);
831 PTRACE(1, "H4501\tInvalid supplementary service argument:\n "
832 << setprecision(2) << argObject
);
837 /////////////////////////////////////////////////////////////////////////////
839 H4502Handler::H4502Handler(H323Connection
& conn
, H450xDispatcher
& disp
)
840 : H450xHandler(conn
, disp
)
842 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferIdentify
, this);
843 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferAbandon
, this);
844 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferInitiate
, this);
845 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferSetup
, this);
846 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferUpdate
, this);
847 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_subaddressTransfer
, this);
848 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferComplete
, this);
849 dispatcher
.AddOpCode(H4502_CallTransferOperation::e_callTransferActive
, this);
851 transferringCallToken
= "";
853 ctResponseSent
= FALSE
;
854 CallToken
= PString();
855 consultationTransfer
= FALSE
;
857 ctTimer
.SetNotifier(PCREATE_NOTIFIER(OnCallTransferTimeOut
));
861 void H4502Handler::AttachToSetup(H323SignalPDU
& pdu
)
863 // Do we need to attach a call transfer setup invoke APDU?
864 if (ctState
!= e_ctAwaitSetupResponse
)
867 H450ServiceAPDU serviceAPDU
;
869 // Store the outstanding invokeID associated with this connection
870 currentInvokeId
= dispatcher
.GetNextInvokeId();
872 // Use the call identity from the ctInitiateArg
873 serviceAPDU
.BuildCallTransferSetup(currentInvokeId
, transferringCallIdentity
);
875 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
879 void H4502Handler::AttachToAlerting(H323SignalPDU
& pdu
)
881 // Do we need to send a callTransferSetup return result APDU?
882 if (currentInvokeId
== 0 || ctResponseSent
)
885 H450ServiceAPDU serviceAPDU
;
886 serviceAPDU
.BuildReturnResult(currentInvokeId
);
887 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
888 ctResponseSent
= TRUE
;
893 void H4502Handler::AttachToConnect(H323SignalPDU
& pdu
)
895 // Do we need to include a ctInitiateReturnResult APDU in our Release Complete Message?
896 if (currentInvokeId
== 0 || ctResponseSent
)
899 H450ServiceAPDU serviceAPDU
;
900 serviceAPDU
.BuildReturnResult(currentInvokeId
);
901 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
902 ctResponseSent
= TRUE
;
907 void H4502Handler::AttachToReleaseComplete(H323SignalPDU
& pdu
)
909 // Do we need to include a ctInitiateReturnResult APDU in our Release Complete Message?
910 if (currentInvokeId
== 0)
913 // If the SETUP message we received from the other end had a callTransferSetup APDU
914 // in it, then we need to send back a RELEASE COMPLETE PDU with a callTransferSetup
916 // Else normal call - clear it down
917 H450ServiceAPDU serviceAPDU
;
919 if (ctResponseSent
) {
920 serviceAPDU
.BuildReturnResult(currentInvokeId
);
921 ctResponseSent
= FALSE
;
925 serviceAPDU
.BuildReturnError(currentInvokeId
, H4501_GeneralErrorList::e_notAvailable
);
926 ctResponseSent
= TRUE
;
930 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
934 BOOL
H4502Handler::OnReceivedInvoke(int opcode
,
937 PASN_OctetString
* argument
)
939 currentInvokeId
= invokeId
;
942 case H4502_CallTransferOperation::e_callTransferIdentify
:
943 OnReceivedCallTransferIdentify(linkedId
);
946 case H4502_CallTransferOperation::e_callTransferAbandon
:
947 OnReceivedCallTransferAbandon(linkedId
);
950 case H4502_CallTransferOperation::e_callTransferInitiate
:
951 OnReceivedCallTransferInitiate(linkedId
, argument
);
954 case H4502_CallTransferOperation::e_callTransferSetup
:
955 OnReceivedCallTransferSetup(linkedId
, argument
);
958 case H4502_CallTransferOperation::e_callTransferUpdate
:
959 OnReceivedCallTransferUpdate(linkedId
, argument
);
962 case H4502_CallTransferOperation::e_subaddressTransfer
:
963 OnReceivedSubaddressTransfer(linkedId
, argument
);
966 case H4502_CallTransferOperation::e_callTransferComplete
:
967 OnReceivedCallTransferComplete(linkedId
, argument
);
970 case H4502_CallTransferOperation::e_callTransferActive
:
971 OnReceivedCallTransferActive(linkedId
, argument
);
983 void H4502Handler::OnReceivedCallTransferIdentify(int /*linkedId*/)
985 if (!endpoint
.OnCallTransferIdentify(connection
)) {
986 SendReturnError(H4501_GeneralErrorList::e_notAvailable
);
990 // Send a FACILITY message with a callTransferIdentify return result
991 // Supplementary Service PDU to the transferring endpoint.
992 H450ServiceAPDU serviceAPDU
;
994 X880_ReturnResult
& result
= serviceAPDU
.BuildReturnResult(currentInvokeId
);
995 result
.IncludeOptionalField(X880_ReturnResult::e_result
);
996 result
.m_result
.m_opcode
.SetTag(X880_Code::e_local
);
997 PASN_Integer
& operation
= (PASN_Integer
&) result
.m_result
.m_opcode
;
998 operation
.SetValue(H4502_CallTransferOperation::e_callTransferIdentify
);
1000 H4502_CTIdentifyRes ctIdentifyResult
;
1002 // Restrict the generated value to 4 digits (13 bits)
1003 unsigned int id
= endpoint
.GetNextH450CallIdentityValue() & 0x1FFF;
1004 PString
pstrId(PString::Unsigned
, id
);
1005 ctIdentifyResult
.m_callIdentity
= pstrId
;
1007 // Store the callIdentity of this connection in the dictionary
1008 endpoint
.GetCallIdentityDictionary().SetAt(pstrId
, &connection
);
1010 H4501_ArrayOf_AliasAddress
& aliasAddress
= ctIdentifyResult
.m_reroutingNumber
.m_destinationAddress
;
1012 PString localName
= connection
.GetLocalPartyName();
1013 if (localName
.IsEmpty())
1014 aliasAddress
.SetSize(1);
1016 aliasAddress
.SetSize(2);
1017 aliasAddress
[1].SetTag(H225_AliasAddress::e_dialedDigits
);
1018 H323SetAliasAddress(localName
, aliasAddress
[1]); // Will encode as h323-Id if not E.164
1021 H323TransportAddress address
;
1022 address
= connection
.GetSignallingChannel()->GetLocalAddress();
1024 aliasAddress
[0].SetTag(H225_AliasAddress::e_transportID
);
1025 H225_TransportAddress
& cPartyTransport
= (H225_TransportAddress
&) aliasAddress
[0];
1026 address
.SetPDU(cPartyTransport
);
1028 PPER_Stream resultStream
;
1029 ctIdentifyResult
.Encode(resultStream
);
1030 resultStream
.CompleteEncoding();
1031 result
.m_result
.m_result
.SetValue(resultStream
);
1033 serviceAPDU
.WriteFacilityPDU(connection
);
1035 ctState
= e_ctAwaitSetup
;
1037 // start timer CT-T2
1038 PTRACE(4, "H450.2\tStarting timer CT-T2");
1039 StartctTimer(endpoint
.GetCallTransferT2());
1043 void H4502Handler::OnReceivedCallTransferAbandon(int /*linkedId*/)
1046 case e_ctAwaitSetup
:
1048 // Stop Timer CT-T2 and enter state e_ctIdle
1050 PTRACE(4, "H4502\tStopping timer CT-T2");
1052 currentInvokeId
= 0;
1063 void H4502Handler::OnReceivedCallTransferInitiate(int /*linkedId*/,
1064 PASN_OctetString
* argument
)
1066 // TBD: Check Call Hold status. If call is held, it must first be
1067 // retrieved before being transferred. -- dcassel 4/01
1069 H4502_CTInitiateArg ctInitiateArg
;
1070 if (!DecodeArguments(argument
, ctInitiateArg
,
1071 H4502_CallTransferErrors::e_invalidReroutingNumber
))
1074 ctResponseSent
= TRUE
;
1076 PString remoteParty
;
1077 H450ServiceAPDU::ParseEndpointAddress(ctInitiateArg
.m_reroutingNumber
, remoteParty
);
1080 if (!endpoint
.OnCallTransferInitiate(connection
, remoteParty
) ||
1081 endpoint
.SetupTransfer(connection
.GetCallToken(),
1082 ctInitiateArg
.m_callIdentity
.GetValue(),
1083 remoteParty
, newToken
) == NULL
)
1084 SendReturnError(H4502_CallTransferErrors::e_establishmentFailure
);
1088 void H4502Handler::OnReceivedCallTransferSetup(int /*linkedId*/,
1089 PASN_OctetString
* argument
)
1091 H4502_CTSetupArg ctSetupArg
;
1092 if (!DecodeArguments(argument
, ctSetupArg
,
1093 H4502_CallTransferErrors::e_unrecognizedCallIdentity
))
1096 // Get the Transferring User's details if present
1097 PString transferringParty
;
1098 if (ctSetupArg
.HasOptionalField(H4502_CTSetupArg::e_transferringNumber
)) {
1099 H450ServiceAPDU::ParseEndpointAddress(ctSetupArg
.m_transferringNumber
, transferringParty
);
1102 PString callIdentity
;
1103 callIdentity
= ctSetupArg
.m_callIdentity
;
1105 if (callIdentity
.IsEmpty()) { // Blind Transfer
1108 ctState
= e_ctAwaitSetupResponse
;
1116 else { // Transfer through Consultation
1118 // We need to check that the call identity and destination address information match those in the
1119 // second call. For the time being we just check that the call identities match as there does not
1120 // appear to be an elegant solution to compare the destination address information.
1122 // Get this callIdentity from our dictionary (if present)
1123 H323Connection
*secondaryCall
= endpoint
.GetCallIdentityDictionary().GetAt(callIdentity
);
1125 if (secondaryCall
!= NULL
)
1126 secondaryCall
->HandleConsultationTransfer(callIdentity
, connection
);
1127 else // Mismatched callIdentity
1128 SendReturnError(H4502_CallTransferErrors::e_unrecognizedCallIdentity
);
1133 void H4502Handler::OnReceivedCallTransferUpdate(int /*linkedId*/,
1134 PASN_OctetString
* argument
)
1136 H4502_CTUpdateArg ctUpdateArg
;
1137 if (!DecodeArguments(argument
, ctUpdateArg
, -1))
1143 void H4502Handler::OnReceivedSubaddressTransfer(int /*linkedId*/,
1144 PASN_OctetString
* argument
)
1146 H4502_SubaddressTransferArg subaddressTransferArg
;
1147 if (!DecodeArguments(argument
, subaddressTransferArg
, -1))
1153 void H4502Handler::OnReceivedCallTransferComplete(int /*linkedId*/,
1154 PASN_OctetString
* argument
)
1156 H4502_CTCompleteArg ctCompleteArg
;
1157 if (!DecodeArguments(argument
, ctCompleteArg
, -1))
1163 void H4502Handler::OnReceivedCallTransferActive(int /*linkedId*/,
1164 PASN_OctetString
* argument
)
1166 H4502_CTActiveArg ctActiveArg
;
1167 if (!DecodeArguments(argument
, ctActiveArg
, -1))
1173 BOOL
H4502Handler::OnReceivedReturnResult(X880_ReturnResult
& returnResult
)
1175 if (currentInvokeId
== returnResult
.m_invokeId
.GetValue()) {
1177 case e_ctAwaitInitiateResponse
:
1178 OnReceivedInitiateReturnResult();
1181 case e_ctAwaitSetupResponse
:
1182 OnReceivedSetupReturnResult();
1185 case e_ctAwaitIdentifyResponse
:
1186 OnReceivedIdentifyReturnResult(returnResult
);
1197 void H4502Handler::OnReceivedInitiateReturnResult()
1201 PTRACE(4, "H4502\tStopping timer CT-T3");
1203 currentInvokeId
= 0;
1205 // clear the primary and secondary call if not already cleared,
1209 void H4502Handler::OnReceivedSetupReturnResult()
1213 PTRACE(4, "H4502\tStopping timer CT-T4");
1215 currentInvokeId
= 0;
1217 // Clear the primary call
1218 endpoint
.ClearCall(transferringCallToken
, H323Connection::EndedByCallForwarded
);
1222 void H4502Handler::OnReceivedIdentifyReturnResult(X880_ReturnResult
&returnResult
)
1226 PTRACE(4, "H4502\tStopping timer CT-T1");
1228 // Have received response.
1231 // Get the return result if present
1232 PASN_OctetString
* result
= NULL
;
1233 if (returnResult
.HasOptionalField(X880_ReturnResult::e_result
)) {
1234 result
= &returnResult
.m_result
.m_result
;
1236 // Extract the C Party Details
1237 H4502_CTIdentifyRes ctIdentifyResult
;
1239 PPER_Stream
resultStream(*result
);
1240 ctIdentifyResult
.Decode(resultStream
);
1241 PString callIdentity
= ctIdentifyResult
.m_callIdentity
.GetValue();
1243 PString remoteParty
;
1244 H450ServiceAPDU::ParseEndpointAddress(ctIdentifyResult
.m_reroutingNumber
, remoteParty
);
1246 // Store the secondary call token on the primary connection so we can send a
1247 // callTransferAbandon invoke APDU on the secondary call at a later stage if we
1248 // get back a callTransferInitiateReturnError
1249 H323Connection
* primaryConnection
= endpoint
.FindConnectionWithLock(CallToken
);
1250 if (primaryConnection
!= NULL
) {
1251 primaryConnection
->SetAssociatedCallToken(connection
.GetCallToken());
1253 // Send a callTransferInitiate invoke APDU in a FACILITY message
1254 // to the transferred endpoint on the primary call
1255 endpoint
.TransferCall(primaryConnection
->GetCallToken(), remoteParty
, callIdentity
);
1257 primaryConnection
->Unlock();
1263 BOOL
H4502Handler::OnReceivedReturnError(int errorCode
, X880_ReturnError
&returnError
)
1265 if (currentInvokeId
== returnError
.m_invokeId
.GetValue()) {
1267 case e_ctAwaitInitiateResponse
:
1268 OnReceivedInitiateReturnError();
1271 case e_ctAwaitSetupResponse
:
1272 OnReceivedSetupReturnError(errorCode
);
1275 case e_ctAwaitIdentifyResponse
:
1276 OnReceivedIdentifyReturnError();
1287 void H4502Handler::OnReceivedInitiateReturnError(const bool timerExpiry
)
1292 PTRACE(4, "H4502\tStopping timer CT-T3 on Error");
1295 PTRACE(4, "H4502\tTimer CT-T3 has expired on the Transferring Endpoint awaiting a response to a callTransferInitiate APDU.");
1297 currentInvokeId
= 0;
1301 // Send a callTransferAbandon invoke APDU in a FACILITY message on the secondary call
1302 // (if it exists) and enter state CT-Idle.
1303 H323Connection
* secondaryConnection
= endpoint
.FindConnectionWithLock(CallToken
);
1305 if (secondaryConnection
!= NULL
) {
1306 H450ServiceAPDU serviceAPDU
;
1308 serviceAPDU
.BuildCallTransferAbandon(dispatcher
.GetNextInvokeId());
1309 serviceAPDU
.WriteFacilityPDU(*secondaryConnection
);
1310 secondaryConnection
->Unlock();
1313 if (!transferringCallToken
) {
1314 H323Connection
* primaryConnection
= endpoint
.FindConnectionWithLock(transferringCallToken
);
1315 primaryConnection
->OnReceivedInitiateReturnError();
1316 primaryConnection
->Unlock();
1318 endpoint
.OnReceivedInitiateReturnError();
1323 void H4502Handler::OnReceivedSetupReturnError(int errorCode
,
1324 const bool timerExpiry
)
1327 currentInvokeId
= 0;
1330 // stop timer CT-T4 if it is running
1332 PTRACE(4, "H4502\tStopping timer CT-T4");
1335 PTRACE(3, "H4502\tTimer CT-T4 has expired on the Transferred Endpoint awaiting a response to a callTransferSetup APDU.");
1337 // Clear the transferred call.
1338 endpoint
.ClearCall(connection
.GetCallToken());
1341 // Send a facility message to the transferring endpoint
1342 // containing a call transfer initiate return error
1343 H323Connection
* primaryConnection
= endpoint
.FindConnectionWithLock(transferringCallToken
);
1345 if (primaryConnection
!= NULL
) {
1346 primaryConnection
->HandleCallTransferFailure(errorCode
);
1347 primaryConnection
->Unlock();
1352 void H4502Handler::OnReceivedIdentifyReturnError(const bool timerExpiry
)
1354 // The transferred-to user cannot participate in our transfer request
1356 currentInvokeId
= 0;
1361 PTRACE(4, "H4502\tStopping timer CT-T1");
1364 PTRACE(4, "H4502\tTimer CT-T1 has expired on the Transferring Endpoint awaiting a response to a callTransferIdentify APDU.");
1366 // send a callTransferAbandon invoke APDU in a FACILITY message on the secondary call
1367 // and enter state CT-Idle.
1370 H450ServiceAPDU serviceAPDU
;
1372 serviceAPDU
.BuildCallTransferAbandon(dispatcher
.GetNextInvokeId());
1373 serviceAPDU
.WriteFacilityPDU(connection
);
1375 connection
.Unlock();
1379 void H4502Handler::TransferCall(const PString
& remoteParty
,
1380 const PString
& callIdentity
)
1382 currentInvokeId
= dispatcher
.GetNextInvokeId();
1384 // Send a FACILITY message with a callTransferInitiate Invoke
1385 // Supplementary Service PDU to the transferred endpoint.
1386 H450ServiceAPDU serviceAPDU
;
1389 H323TransportAddress address
;
1391 PStringList Addresses
;
1392 endpoint
.ResolveCallParty(remoteParty
, Addresses
);
1393 endpoint
.ParsePartyName(Addresses
[0], alias
, address
);
1395 serviceAPDU
.BuildCallTransferInitiate(currentInvokeId
, callIdentity
, alias
, address
);
1396 serviceAPDU
.WriteFacilityPDU(connection
);
1398 ctState
= e_ctAwaitInitiateResponse
;
1400 // start timer CT-T3
1401 PTRACE(4, "H4502\tStarting timer CT-T3");
1402 StartctTimer(connection
.GetEndPoint().GetCallTransferT3());
1406 void H4502Handler::ConsultationTransfer(const PString
& primaryCallToken
)
1408 currentInvokeId
= dispatcher
.GetNextInvokeId();
1410 // Store the call token of the primary call on the secondary call.
1411 SetAssociatedCallToken(primaryCallToken
);
1413 // Send a FACILITY message with a callTransferIdentify Invoke
1414 // Supplementary Service PDU to the transferred-to endpoint.
1415 H450ServiceAPDU serviceAPDU
;
1417 serviceAPDU
.BuildCallTransferIdentify(currentInvokeId
);
1418 serviceAPDU
.WriteFacilityPDU(connection
);
1420 ctState
= e_ctAwaitIdentifyResponse
;
1422 // start timer CT-T1
1423 PTRACE(4, "H4502\tStarting timer CT-T1");
1424 StartctTimer(endpoint
.GetCallTransferT1());
1428 void H4502Handler::HandleConsultationTransfer(const PString
& callIdentity
,
1429 H323Connection
& incoming
)
1432 case e_ctAwaitSetup
:
1434 // Remove this callIdentity, connection pair from our dictionary as we no longer need it
1435 endpoint
.GetCallIdentityDictionary().RemoveAt(callIdentity
);
1439 PTRACE(4, "H4502\tStopping timer CT-T2");
1441 PTRACE(4, "H450.2\tConsultation Transfer successful, clearing secondary call");
1443 incoming
.OnConsultationTransferSuccess(connection
);
1445 currentInvokeId
= 0;
1448 endpoint
.ClearCall(connection
.GetCallToken());
1452 // Wrong Call Transfer State
1460 void H4502Handler::AwaitSetupResponse(const PString
& token
,
1461 const PString
& identity
)
1463 transferringCallToken
= token
;
1464 transferringCallIdentity
= identity
;
1465 ctState
= e_ctAwaitSetupResponse
;
1467 // start timer CT-T4
1468 PTRACE(4, "H450.2\tStarting timer CT-T4");
1469 StartctTimer(connection
.GetEndPoint().GetCallTransferT4());
1473 void H4502Handler::onReceivedAdmissionReject(const int returnError
)
1475 if (ctState
== e_ctAwaitSetupResponse
) {
1478 // Stop timer CT-T4 if it is running
1480 PTRACE(3, "H4502\tStopping timer CT-T4");
1482 // Send a FACILITY message back to the transferring party on the primary connection
1483 H323Connection
* primaryConnection
= endpoint
.FindConnectionWithLock(transferringCallToken
);
1485 if (primaryConnection
!= NULL
) {
1486 PTRACE(3, "H4502\tReceived an Admission Reject at the Transferred Endpoint - aborting the transfer.");
1487 primaryConnection
->HandleCallTransferFailure(returnError
);
1488 primaryConnection
->Unlock();
1494 void H4502Handler::HandleCallTransferFailure(const int returnError
)
1496 SendReturnError(returnError
);
1500 void H4502Handler::StopctTimer()
1502 if (ctTimer
.IsRunning())
1507 void H4502Handler::OnCallTransferTimeOut(PTimer
&, INT
)
1511 case e_ctAwaitInitiateResponse
:
1512 OnReceivedInitiateReturnError(true);
1516 case e_ctAwaitIdentifyResponse
:
1517 OnReceivedIdentifyReturnError(true);
1521 case e_ctAwaitSetup
:
1523 // Abort the call transfer
1525 currentInvokeId
= 0;
1526 PTRACE(4, "H450.2\tTimer CT-T2 has expired on the Transferred-to endpoint awaiting a callTransferSetup APDU.");
1531 case e_ctAwaitSetupResponse
:
1532 OnReceivedSetupReturnError(H4502_CallTransferErrors::e_establishmentFailure
, true);
1540 /////////////////////////////////////////////////////////////////////////////
1542 H4503Handler::H4503Handler(H323Connection
& conn
, H450xDispatcher
& disp
)
1543 : H450xHandler(conn
, disp
)
1545 dispatcher
.AddOpCode(H4503_H323CallDiversionOperations::e_divertingLegInformation2
, this);
1549 BOOL
H4503Handler::OnReceivedInvoke(int opcode
,
1552 PASN_OctetString
*argument
)
1554 currentInvokeId
= invokeId
;
1556 case H4503_H323CallDiversionOperations::e_divertingLegInformation2
:
1557 OnReceivedDivertingLegInfo2(linkedId
, argument
);
1561 currentInvokeId
= 0;
1568 void H4503Handler::OnReceivedDivertingLegInfo2(int /* linkedId*/, PASN_OctetString
* argument
)
1570 PTRACE(4, "H4503\tReceived a DivertingLegInfo2 Invoke APDU from the remote endpoint.");
1571 H4503_DivertingLegInfo2Arg divertingLegInfo2Arg
;
1572 DecodeArguments(argument
, divertingLegInfo2Arg
, -1);
1574 if(divertingLegInfo2Arg
.HasOptionalField(H4503_DivertingLegInfo2Arg::e_originalCalledNr
)) {
1575 //m_originalCalledNr = divertingLegInfo2Arg.m_originalCalledNr.GetTypeAsString();
1576 H450ServiceAPDU::ParseEndpointAddress(divertingLegInfo2Arg
.m_originalCalledNr
, m_originalCalledNr
);
1579 if(divertingLegInfo2Arg
.HasOptionalField(H4503_DivertingLegInfo2Arg::e_divertingNr
))
1580 m_lastDivertingNr
= divertingLegInfo2Arg
.m_divertingNr
.GetTypeAsString();
1582 m_diversionCounter
= divertingLegInfo2Arg
.m_diversionCounter
.GetValue();
1583 m_diversionReason
= divertingLegInfo2Arg
.m_diversionReason
.GetValue();
1585 PTRACE(4, "H450.3\tOnReceivedDivertingLegInfo2 redirNUm=" << m_originalCalledNr
);
1590 BOOL
H4503Handler::GetRedirectingNumber(PString
&originalCalledNr
, PString
&lastDivertingNr
, int &divCounter
, int &origdivReason
, int &divReason
)
1592 BOOL bRedirAvail
=false;
1594 if(!m_originalCalledNr
.IsEmpty()) {
1595 originalCalledNr
= m_originalCalledNr
;
1598 if(!m_lastDivertingNr
.IsEmpty()) {
1599 lastDivertingNr
= m_lastDivertingNr
;
1603 divCounter
= m_diversionCounter
;
1604 divReason
= m_diversionReason
;
1605 origdivReason
= m_origdiversionReason
;
1612 /////////////////////////////////////////////////////////////////////////////
1614 H4504Handler::H4504Handler(H323Connection
& conn
, H450xDispatcher
& disp
)
1615 : H450xHandler(conn
, disp
)
1617 dispatcher
.AddOpCode(H4504_CallHoldOperation::e_holdNotific
, this);
1618 dispatcher
.AddOpCode(H4504_CallHoldOperation::e_retrieveNotific
, this);
1619 dispatcher
.AddOpCode(H4504_CallHoldOperation::e_remoteHold
, this);
1620 dispatcher
.AddOpCode(H4504_CallHoldOperation::e_remoteRetrieve
, this);
1622 holdState
= e_ch_Idle
;
1626 BOOL
H4504Handler::OnReceivedInvoke(int opcode
,
1631 currentInvokeId
= invokeId
;
1634 case H4504_CallHoldOperation::e_holdNotific
:
1635 OnReceivedLocalCallHold(linkedId
);
1638 case H4504_CallHoldOperation::e_retrieveNotific
:
1639 OnReceivedLocalCallRetrieve(linkedId
);
1642 case H4504_CallHoldOperation::e_remoteHold
:
1643 OnReceivedRemoteCallHold(linkedId
);
1646 case H4504_CallHoldOperation::e_remoteRetrieve
:
1647 OnReceivedRemoteCallRetrieve(linkedId
);
1651 currentInvokeId
= 0;
1659 void H4504Handler::OnReceivedLocalCallHold(int /*linkedId*/)
1661 PTRACE(4, "H4504\tReceived a holdNotific Invoke APDU from the remote endpoint.");
1662 // Optionally close our transmit channel.
1666 void H4504Handler::OnReceivedLocalCallRetrieve(int /*linkedId*/)
1668 PTRACE(4, "H4504\tReceived a retrieveNotific Invoke APDU from the remote endpoint.");
1669 // Re-open our transmit channel if we previously closed it.
1673 void H4504Handler::OnReceivedRemoteCallHold(int /*linkedId*/)
1679 void H4504Handler::OnReceivedRemoteCallRetrieve(int /*linkedId*/)
1685 void H4504Handler::HoldCall(BOOL localHold
)
1687 // TBD: Implement Remote Hold. This implementation only does
1688 // local hold. -- dcassel 4/01.
1692 // Send a FACILITY message with a callNotific Invoke
1693 // Supplementary Service PDU to the held endpoint.
1694 PTRACE(4, "H4504\tTransmitting a holdNotific Invoke APDU to the remote endpoint.");
1696 H450ServiceAPDU serviceAPDU
;
1698 currentInvokeId
= dispatcher
.GetNextInvokeId();
1699 serviceAPDU
.BuildInvoke(currentInvokeId
, H4504_CallHoldOperation::e_holdNotific
);
1700 serviceAPDU
.WriteFacilityPDU(connection
);
1702 // Update hold state
1703 holdState
= e_ch_NE_Held
;
1707 void H4504Handler::RetrieveCall()
1709 // TBD: Implement Remote Hold. This implementation only does
1711 // Send a FACILITY message with a retrieveNotific Invoke
1712 // Supplementary Service PDU to the held endpoint.
1713 PTRACE(4, "H4504\tTransmitting a retrieveNotific Invoke APDU to the remote endpoint.");
1715 H450ServiceAPDU serviceAPDU
;
1717 currentInvokeId
= dispatcher
.GetNextInvokeId();
1718 serviceAPDU
.BuildInvoke(currentInvokeId
, H4504_CallHoldOperation::e_retrieveNotific
);
1719 serviceAPDU
.WriteFacilityPDU(connection
);
1721 // Update hold state
1722 holdState
= e_ch_Idle
;
1726 /////////////////////////////////////////////////////////////////////////////
1728 H4506Handler::H4506Handler(H323Connection
& conn
, H450xDispatcher
& disp
)
1729 : H450xHandler(conn
, disp
)
1731 dispatcher
.AddOpCode(H4506_CallWaitingOperations::e_callWaiting
, this);
1733 cwState
= e_cw_Idle
;
1737 BOOL
H4506Handler::OnReceivedInvoke(int opcode
,
1740 PASN_OctetString
*argument
)
1742 currentInvokeId
= invokeId
;
1745 case H4506_CallWaitingOperations::e_callWaiting
:
1746 OnReceivedCallWaitingIndication(linkedId
, argument
);
1750 currentInvokeId
= 0;
1758 void H4506Handler::OnReceivedCallWaitingIndication(int /*linkedId*/,
1759 PASN_OctetString
*argument
)
1761 H4506_CallWaitingArg cwArg
;
1763 if(!DecodeArguments(argument
, cwArg
, -1))
1766 connection
.SetRemoteCallWaiting(cwArg
.m_nbOfAddWaitingCalls
.GetValue());
1771 void H4506Handler::AttachToAlerting(H323SignalPDU
& pdu
,
1772 unsigned numberOfCallsWaiting
)
1774 PTRACE(4, "H450.6\tAttaching a Call Waiting Invoke PDU to this Alerting message.");
1776 H450ServiceAPDU serviceAPDU
;
1778 // Store the call waiting invokeID associated with this connection
1779 currentInvokeId
= dispatcher
.GetNextInvokeId();
1781 serviceAPDU
.BuildCallWaiting(currentInvokeId
, numberOfCallsWaiting
);
1782 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
1784 cwState
= e_cw_Invoked
;
1788 /////////////////////////////////////////////////////////////////////////////
1790 H45011Handler::H45011Handler(H323Connection
& conn
, H450xDispatcher
& disp
)
1791 : H450xHandler(conn
, disp
)
1793 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionRequest
, this);
1794 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL
, this);
1795 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionIsolate
, this);
1796 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease
, this);
1797 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionWOBRequest
, this);
1798 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionSilentMonitor
, this);
1799 dispatcher
.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionNotification
, this);
1801 dispatcher
.AddOpCode(H45010_H323CallOfferOperations::e_cfbOverride
, this);
1802 dispatcher
.AddOpCode(H45010_H323CallOfferOperations::e_remoteUserAlerting
, this);
1804 dispatcher
.AddOpCode(H4506_CallWaitingOperations::e_callWaiting
, this);
1806 ciState
= e_ci_Idle
;
1807 ciSendState
= e_ci_sIdle
;
1808 ciReturnState
= e_ci_rIdle
;
1809 ciTimer
.SetNotifier(PCREATE_NOTIFIER(OnCallIntrudeTimeOut
));
1813 BOOL
H45011Handler::OnReceivedInvoke(int opcode
,
1816 PASN_OctetString
* argument
)
1819 currentInvokeId
= invokeId
;
1822 case H45011_H323CallIntrusionOperations::e_callIntrusionRequest
:
1823 OnReceivedCallIntrusionRequest(linkedId
, argument
);
1826 case H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL
:
1827 OnReceivedCallIntrusionGetCIPL(linkedId
, argument
);
1830 case H45011_H323CallIntrusionOperations::e_callIntrusionIsolate
:
1831 OnReceivedCallIntrusionIsolate(linkedId
, argument
);
1834 case H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease
:
1835 result
= OnReceivedCallIntrusionForcedRelease(linkedId
, argument
);
1838 case H45011_H323CallIntrusionOperations::e_callIntrusionWOBRequest
:
1839 OnReceivedCallIntrusionWOBRequest(linkedId
, argument
);
1842 case H45011_H323CallIntrusionOperations::e_callIntrusionSilentMonitor
:
1843 OnReceivedCallIntrusionSilentMonitor(linkedId
, argument
);
1846 case H45011_H323CallIntrusionOperations::e_callIntrusionNotification
:
1847 OnReceivedCallIntrusionNotification(linkedId
, argument
);
1850 case H45010_H323CallOfferOperations::e_cfbOverride
:
1851 OnReceivedCfbOverride(linkedId
, argument
);
1854 case H45010_H323CallOfferOperations::e_remoteUserAlerting
:
1855 OnReceivedRemoteUserAlerting(linkedId
, argument
);
1858 case H4506_CallWaitingOperations::e_callWaiting
:
1859 OnReceivedCallWaiting(linkedId
, argument
);
1863 currentInvokeId
= 0;
1871 void H45011Handler::AttachToSetup(H323SignalPDU
& pdu
)
1873 // Do we need to attach a call transfer setup invoke APDU?
1874 if (ciSendState
!= e_ci_sAttachToSetup
)
1877 H450ServiceAPDU serviceAPDU
;
1879 // Store the outstanding invokeID associated with this connection
1880 currentInvokeId
= dispatcher
.GetNextInvokeId();
1881 PTRACE(4, "H450.11\tAttachToSetup Invoke ID=" << currentInvokeId
);
1883 switch (ciGenerateState
){
1884 case e_ci_gConferenceRequest
:
1886 case e_ci_gHeldRequest
:
1888 case e_ci_gSilentMonitorRequest
:
1890 case e_ci_gIsolationRequest
:
1892 case e_ci_gForcedReleaseRequest
:
1893 serviceAPDU
.BuildCallIntrusionForcedRelease(currentInvokeId
, ciCICL
);
1895 case e_ci_gWOBRequest
:
1901 if(ciGenerateState
!= e_ci_gIdle
){
1902 // Use the call identity from the ctInitiateArg
1903 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
1904 // start timer CT-T1
1905 PTRACE(4, "H450.11\tStarting timer CI-T1");
1906 StartciTimer(connection
.GetEndPoint().GetCallIntrusionT1());
1907 ciState
= e_ci_WaitAck
;
1910 ciSendState
= e_ci_sIdle
;
1911 ciGenerateState
= e_ci_gIdle
;
1915 void H45011Handler::AttachToAlerting(H323SignalPDU
& pdu
)
1917 if (ciSendState
!= e_ci_sAttachToAlerting
)
1920 PTRACE(4, "H450.11\tAttachToAlerting Invoke ID=" << currentInvokeId
);
1922 // Store the outstanding invokeID associated with this connection
1923 currentInvokeId
= dispatcher
.GetNextInvokeId();
1924 PTRACE(4, "H450.11\tAttachToAlerting Invoke ID=" << currentInvokeId
);
1925 if(ciReturnState
!=e_ci_rIdle
){
1926 H450ServiceAPDU serviceAPDU
;
1927 switch (ciReturnState
){
1928 case e_ci_rCallIntrusionImpending
:
1929 serviceAPDU
.BuildCallIntrusionImpending(currentInvokeId
);
1930 PTRACE(4, "H450.11\tReturned e_ci_rCallIntrusionImpending");
1932 case e_ci_rCallIntruded
:
1934 case e_ci_rCallIsolated
:
1936 case e_ci_rCallForceReleased
:
1938 case e_ci_rCallForceReleaseResult
:
1939 serviceAPDU
.BuildCallIntrusionForcedReleaseResult(currentInvokeId
);
1940 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
1942 case e_ci_rCallIntrusionComplete
:
1944 case e_ci_rCallIntrusionEnd
:
1947 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notBusy
);
1948 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
1950 case e_ci_rTempUnavailable
:
1951 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
1952 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_temporarilyUnavailable
);
1954 case e_ci_rNotAuthorized
:
1955 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
1956 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notAuthorized
);
1961 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
1964 ciState
= e_ci_Idle
;
1965 ciSendState
= e_ci_sIdle
;
1966 ciReturnState
= e_ci_rIdle
;
1970 void H45011Handler::AttachToConnect(H323SignalPDU
& pdu
)
1972 if ((currentInvokeId
== 0) || (ciSendState
!= e_ci_sAttachToConnect
))
1975 currentInvokeId
= dispatcher
.GetNextInvokeId();
1976 PTRACE(4, "H450.11\tAttachToConnect Invoke ID=" << currentInvokeId
);
1977 if(ciReturnState
!=e_ci_rIdle
){
1978 H450ServiceAPDU serviceAPDU
;
1979 switch (ciReturnState
){
1980 case e_ci_rCallIntrusionImpending
:
1982 case e_ci_rCallIntruded
:
1984 case e_ci_rCallIsolated
:
1986 case e_ci_rCallForceReleased
:
1988 case e_ci_rCallForceReleaseResult
:
1989 serviceAPDU
.BuildCallIntrusionForcedReleaseResult(currentInvokeId
);
1990 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
1992 case e_ci_rCallIntrusionComplete
:
1994 case e_ci_rCallIntrusionEnd
:
1997 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notBusy
);
1998 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2000 case e_ci_rTempUnavailable
:
2001 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2002 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_temporarilyUnavailable
);
2004 case e_ci_rNotAuthorized
:
2005 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2006 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notAuthorized
);
2012 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
2016 ciState
= e_ci_Idle
;
2017 ciSendState
= e_ci_sIdle
;
2018 ciReturnState
= e_ci_rIdle
;
2019 currentInvokeId
= 0;
2024 void H45011Handler::AttachToReleaseComplete(H323SignalPDU
& pdu
)
2026 // Do we need to attach a call transfer setup invoke APDU?
2027 if (ciSendState
!= e_ci_sAttachToReleseComplete
)
2030 PTRACE(4, "H450.11\tAttachToSetup Invoke ID=" << currentInvokeId
);
2031 if(ciReturnState
!=e_ci_rIdle
){
2032 H450ServiceAPDU serviceAPDU
;
2033 switch (ciReturnState
){
2035 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notBusy
);
2036 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2038 case e_ci_rTempUnavailable
:
2039 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2040 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_temporarilyUnavailable
);
2042 case e_ci_rNotAuthorized
:
2043 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2044 serviceAPDU
.BuildReturnError(currentInvokeId
, H45011_CallIntrusionErrors::e_notAuthorized
);
2046 case e_ci_rCallForceReleased
:
2047 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForceRelease::e_ci_rCallForceReleased");
2048 serviceAPDU
.BuildCallIntrusionForceRelesed(currentInvokeId
);
2053 serviceAPDU
.AttachSupplementaryServiceAPDU(pdu
);
2056 ciState
= e_ci_Idle
;
2057 ciSendState
= e_ci_sIdle
;
2058 ciReturnState
= e_ci_rIdle
;
2062 void H45011Handler::OnReceivedCallIntrusionRequest(int /*linkedId*/,
2063 PASN_OctetString
*argument
)
2066 H45011_CIRequestArg ciArg
;
2068 if(!DecodeArguments(argument
, ciArg
, -1))
2077 void H45011Handler::OnReceivedCallIntrusionGetCIPL(int /*linkedId*/,
2078 PASN_OctetString
*argument
)
2080 PTRACE(4, "H450.11\tReceived GetCIPL Invoke");
2082 H45011_CIGetCIPLOptArg ciArg
;
2085 DecodeArguments(argument
, ciArg
, -1);
2086 /* if(!DecodeArguments(argument, ciArg, -1))
2091 // Send a FACILITY message with a callTransferIdentify return result
2092 // Supplementary Service PDU to the transferring endpoint.
2093 H450ServiceAPDU serviceAPDU
;
2095 X880_ReturnResult
& result
= serviceAPDU
.BuildReturnResult(currentInvokeId
);
2096 result
.IncludeOptionalField(X880_ReturnResult::e_result
);
2097 result
.m_result
.m_opcode
.SetTag(X880_Code::e_local
);
2098 PASN_Integer
& operation
= (PASN_Integer
&) result
.m_result
.m_opcode
;
2099 operation
.SetValue(H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL
);
2101 H45011_CIGetCIPLRes ciCIPLRes
;
2103 ciCIPLRes
.m_ciProtectionLevel
= endpoint
.GetCallIntrusionProtectionLevel();
2104 ciCIPLRes
.IncludeOptionalField(H45011_CIGetCIPLRes::e_silentMonitoringPermitted
);
2106 PPER_Stream resultStream
;
2107 ciCIPLRes
.Encode(resultStream
);
2108 resultStream
.CompleteEncoding();
2109 result
.m_result
.m_result
.SetValue(resultStream
);
2111 serviceAPDU
.WriteFacilityPDU(connection
);
2112 PTRACE(4, "H450.11\tSent GetCIPL Result CIPL=" << ciCIPLRes
.m_ciProtectionLevel
);
2120 void H45011Handler::OnReceivedCallIntrusionIsolate(int /*linkedId*/,
2121 PASN_OctetString
*argument
)
2124 H45011_CIIsOptArg ciArg
;
2126 if(!DecodeArguments(argument
, ciArg
, -1))
2135 BOOL
H45011Handler::OnReceivedCallIntrusionForcedRelease(int /*linkedId*/,
2136 PASN_OctetString
*argument
)
2139 PTRACE(4, "H450.11\tReceived ForcedRelease Invoke");
2141 H45011_CIFrcRelArg ciArg
;
2143 if(!DecodeArguments(argument
, ciArg
, -1))
2146 PStringList tokens
= endpoint
.GetAllConnections();
2148 if(tokens
.GetSize() >1) {
2149 for (PINDEX i
= 0; i
< tokens
.GetSize(); i
++) {
2150 if(endpoint
.HasConnection(tokens
[i
])){
2151 H323Connection
* conn
= endpoint
.FindConnectionWithLock(tokens
[i
]);
2153 if (conn
->IsEstablished()){
2154 if((conn
->GetLocalCallIntrusionProtectionLevel() < ciArg
.m_ciCapabilityLevel
)){
2155 activeCallToken
= conn
->GetCallToken();
2156 intrudingCallToken
= connection
.GetCallToken();
2157 conn
->GetRemoteCallIntrusionProtectionLevel(connection
.GetCallToken (), (unsigned)ciArg
.m_ciCapabilityLevel
);
2170 ciSendState
= e_ci_sAttachToConnect
;
2171 ciReturnState
= e_ci_rCallForceReleaseResult
;
2172 connection
.SetCallIntrusion ();
2175 ciSendState
= e_ci_sAttachToReleseComplete
;
2176 ciReturnState
= e_ci_rNotAuthorized
;
2177 connection
.ClearCall(H323Connection::EndedByLocalBusy
);
2181 ciSendState
= e_ci_sAttachToAlerting
;
2182 ciReturnState
= e_ci_rNotBusy
;
2189 void H45011Handler::OnReceivedCallIntrusionWOBRequest(int /*linkedId*/,
2190 PASN_OctetString
*argument
)
2193 H45011_CIWobOptArg ciArg
;
2195 if(!DecodeArguments(argument
, ciArg
, -1))
2204 void H45011Handler::OnReceivedCallIntrusionSilentMonitor(int /*linkedId*/,
2205 PASN_OctetString
*argument
)
2208 H45011_CISilentArg ciArg
;
2210 if(!DecodeArguments(argument
, ciArg
, -1))
2219 void H45011Handler::OnReceivedCallIntrusionNotification(int /*linkedId*/,
2220 PASN_OctetString
*argument
)
2223 H45011_CINotificationArg ciArg
;
2225 if(!DecodeArguments(argument
, ciArg
, -1))
2234 void H45011Handler::OnReceivedCfbOverride(int /*linkedId*/,
2235 PASN_OctetString
*argument
)
2238 H45010_CfbOvrOptArg ciArg
;
2240 if(!DecodeArguments(argument
, ciArg
, -1))
2249 void H45011Handler::OnReceivedRemoteUserAlerting(int /*linkedId*/,
2250 PASN_OctetString
*argument
)
2253 H45010_RUAlertOptArg ciArg
;
2255 if(!DecodeArguments(argument
, ciArg
, -1))
2264 void H45011Handler::OnReceivedCallWaiting(int /*linkedId*/,
2265 PASN_OctetString
*argument
)
2268 H4506_CallWaitingArg ciArg
;
2270 if(!DecodeArguments(argument
, ciArg
, -1))
2279 BOOL
H45011Handler::OnReceivedReturnResult(X880_ReturnResult
& returnResult
)
2281 PTRACE(4, "H450.11\tReceived Return Result");
2282 if (currentInvokeId
== returnResult
.m_invokeId
.GetValue()) {
2283 PTRACE(4, "H450.11\tReceived Return Result Invoke ID=" << currentInvokeId
);
2286 OnReceivedCIRequestResult();
2289 OnReceivedCIGetCIPLResult(returnResult
);
2299 void H45011Handler::OnReceivedCIRequestResult()
2301 PTRACE(4, "H450.11\tOnReceivedCIRequestResult");
2303 PTRACE(4, "H450.11\tTrying to stop timer CI-T1");
2308 void H45011Handler::OnReceivedCIGetCIPLResult(X880_ReturnResult
& returnResult
)
2310 PTRACE(4, "H450.11\tOnReceivedCIRequestResult");
2311 // Get the return result if present
2312 PASN_OctetString
* result
= NULL
;
2313 if (returnResult
.HasOptionalField(X880_ReturnResult::e_result
)) {
2314 result
= &returnResult
.m_result
.m_result
;
2316 // Extract the C Party Details
2317 H45011_CIGetCIPLRes ciGetCIPLResult
;
2319 PPER_Stream
resultStream(*result
);
2320 ciGetCIPLResult
.Decode(resultStream
);
2322 PTRACE(4 ,"H450.11\tReceived CIPL=" << ciGetCIPLResult
.m_ciProtectionLevel
);
2324 if (intrudingCallCICL
> ciGetCIPLResult
.m_ciProtectionLevel
){
2326 // Send ciNotification.inv (ciImpending) To C
2328 H450ServiceAPDU serviceAPDU
;
2329 currentInvokeId
= dispatcher
.GetNextInvokeId();
2330 serviceAPDU
.BuildCallIntrusionImpending(currentInvokeId
);
2331 serviceAPDU
.WriteFacilityPDU(connection
);
2332 connection
.Unlock();
2334 // Send ciNotification.inv (ciImpending) to intruding (A)
2335 H323Connection
* conn
= endpoint
.FindConnectionWithLock(intrudingCallToken
);
2336 conn
->SetIntrusionImpending ();
2338 //Send Ringing to intruding (A)
2339 conn
->AnsweringCall (conn
->AnswerCallPending
);
2341 // MUST RETURN ciNotification.inv (callForceRelesed) to active call (C) when releasing call !!!!!!
2342 ciSendState
= e_ci_sAttachToReleseComplete
;
2343 ciReturnState
= e_ci_rCallForceReleased
;
2345 //Send Forced Release Accepted when Answering call to intruding (A)
2346 conn
->SetForcedReleaseAccepted();
2350 PTRACE(4 ,"H450.11\tCICL<CIPL -> Clear Call");
2351 // Clear Call with intruding (A)
2352 H323Connection
* conn
= endpoint
.FindConnectionWithLock(intrudingCallToken
);
2353 conn
->SetIntrusionNotAuthorized();
2355 endpoint
.ClearCall (intrudingCallToken
);
2360 PTRACE(4, "H450.11\tTrying to stop timer CI-T5");
2365 BOOL
H45011Handler::OnReceivedReturnError(int errorCode
, X880_ReturnError
&returnError
)
2368 PTRACE(4, "H450.11\tReceived Return Error CODE=" <<errorCode
<< ", InvokeId=" <<returnError
.m_invokeId
.GetValue());
2369 if (currentInvokeId
== returnError
.m_invokeId
.GetValue()) {
2372 result
= OnReceivedInvokeReturnError(errorCode
);
2375 result
= OnReceivedGetCIPLReturnError(errorCode
);
2385 BOOL
H45011Handler::OnReceivedInvokeReturnError(int errorCode
, const bool timerExpiry
)
2387 BOOL result
= FALSE
;
2388 PTRACE(4, "H450.11\tOnReceivedInvokeReturnError CODE =" << errorCode
);
2392 PTRACE(4, "H450.11\tStopping timer CI-T1");
2395 PTRACE(4, "H450.11\tTimer CI-T1 has expired awaiting a response to a callIntrusionInvoke return result.");
2397 currentInvokeId
= 0;
2398 ciState
= e_ci_Idle
;
2399 ciSendState
= e_ci_sIdle
;
2402 case H45011_CallIntrusionErrors::e_notBusy
:
2403 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notBusy");
2406 case H45011_CallIntrusionErrors::e_temporarilyUnavailable
:
2407 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_temporarilyUnavailable");
2409 case H45011_CallIntrusionErrors::e_notAuthorized
:
2410 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notAuthorized");
2414 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::DEFAULT");
2421 BOOL
H45011Handler::OnReceivedGetCIPLReturnError(int PTRACE_PARAM(errorCode
),
2422 const bool timerExpiry
)
2424 PTRACE(4, "H450.11\tOnReceivedGetCIPLReturnError ErrorCode=" << errorCode
);
2426 if (ciTimer
.IsRunning()){
2428 PTRACE(4, "H450.11\tStopping timer CI-TX");
2432 // Send ciNotification.inv (ciImpending) to active call (C)
2434 H450ServiceAPDU serviceAPDU
;
2435 currentInvokeId
= dispatcher
.GetNextInvokeId();
2436 serviceAPDU
.BuildCallIntrusionImpending(currentInvokeId
);
2437 serviceAPDU
.WriteFacilityPDU(connection
);
2438 connection
.Unlock();
2440 // Send ciNotification.inv (ciImpending) to intruding (A)
2441 H323Connection
* conn
= endpoint
.FindConnectionWithLock(intrudingCallToken
);
2442 conn
->SetIntrusionImpending ();
2444 //Send Ringing to intruding (A)
2445 conn
->AnsweringCall (conn
->AnswerCallPending
);
2447 ciSendState
= e_ci_sAttachToReleseComplete
;
2448 ciReturnState
= e_ci_rCallForceReleased
;
2450 //Forced Release Accepted to send when Answering call to intruding (A)
2451 conn
->SetForcedReleaseAccepted();
2458 void H45011Handler::IntrudeCall(int CICL
)
2460 ciSendState
= e_ci_sAttachToSetup
;
2461 ciGenerateState
= e_ci_gForcedReleaseRequest
;
2466 void H45011Handler::AwaitSetupResponse(const PString
& token
,
2467 const PString
& identity
)
2469 intrudingCallToken
= token
;
2470 intrudingCallIdentity
= identity
;
2471 ciState
= e_ci_WaitAck
;
2476 BOOL
H45011Handler::GetRemoteCallIntrusionProtectionLevel(const PString
& token
,
2477 unsigned intrusionCICL
)
2479 if (!connection
.Lock())
2482 intrudingCallToken
= token
;
2483 intrudingCallCICL
= intrusionCICL
;
2485 H450ServiceAPDU serviceAPDU
;
2487 currentInvokeId
= dispatcher
.GetNextInvokeId();
2489 serviceAPDU
.BuildCallIntrusionGetCIPL(currentInvokeId
);
2491 connection
.Unlock();
2493 if (!serviceAPDU
.WriteFacilityPDU(connection
))
2496 PTRACE(4, "H450.11\tStarting timer CI-T5");
2497 StartciTimer(connection
.GetEndPoint().GetCallIntrusionT5());
2498 ciState
= e_ci_GetCIPL
;
2503 void H45011Handler::SetIntrusionNotAuthorized()
2505 ciSendState
= e_ci_sAttachToReleseComplete
;
2506 ciReturnState
= e_ci_rNotAuthorized
;
2510 void H45011Handler::SetIntrusionImpending()
2512 ciSendState
= e_ci_sAttachToAlerting
;
2513 ciReturnState
= e_ci_rCallIntrusionImpending
;
2517 void H45011Handler::SetForcedReleaseAccepted()
2519 ciSendState
= e_ci_sAttachToConnect
;
2520 ciReturnState
= e_ci_rCallForceReleaseResult
;
2521 ciState
= e_ci_DestNotify
;
2523 StartciTimer(connection
.GetEndPoint().GetCallIntrusionT6());
2527 void H45011Handler::StopciTimer()
2529 if (ciTimer
.IsRunning()){
2531 PTRACE(4, "H450.11\tStopping timer CI-TX");
2536 void H45011Handler::OnCallIntrudeTimeOut(PTimer
&, INT
)
2541 PTRACE(4, "H450.11\tTimer CI-T1 has expired");
2542 OnReceivedInvokeReturnError(0,true);
2545 PTRACE(4, "H450.11\tTimer CI-T5 has expired");
2546 OnReceivedGetCIPLReturnError(0,true);
2548 case e_ci_DestNotify
:
2550 PTRACE(4, "H450.11\tOnCallIntrudeTimeOut Timer CI-T6 has expired");
2551 // Clear the active call (call with C)
2553 endpoint
.ClearCallSynchronous(activeCallToken
, H323Connection::EndedByLocalUser
, &sync
);
2554 // Answer intruding call (call with A)
2555 PTRACE(4, "H450.11\tOnCallIntrudeTimeOut Trying to answer Call");
2556 if(endpoint
.HasConnection(intrudingCallToken
)){
2557 H323Connection
* conn
= endpoint
.FindConnectionWithLock(intrudingCallToken
);
2558 conn
->AnsweringCall (conn
->AnswerCallNow
);
2569 BOOL
H45011Handler::OnReceivedReject(int PTRACE_PARAM(problemType
), int PTRACE_PARAM(problemNumber
))
2571 PTRACE(4, "H450.11\tH45011Handler::OnReceivedReject - problemType= "
2572 << problemType
<< ", problemNumber= " << problemNumber
);
2574 if (ciTimer
.IsRunning()){
2576 PTRACE(4, "H450.11\tStopping timer CI-TX");
2582 H323Connection
* conn
= endpoint
.FindConnectionWithLock(intrudingCallToken
);
2583 conn
->SetIntrusionImpending ();
2585 //Send Ringing to intruding (A)
2586 conn
->AnsweringCall (conn
->AnswerCallPending
);
2587 conn
->SetForcedReleaseAccepted();
2595 ciState
= e_ci_Idle
;