Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h450pdu.cxx
blob5198b37bc0470e8c4fb8e7a9d0a68bf73e7f7d7a
1 /*
2 * h450pdu.cxx
4 * H.450 Helper functions
6 * Open H323 Library
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
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
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
35 * Fix typo
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
51 * macros only.
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
83 * Fixed GNU warnings
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
95 * Added H.450.6
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
131 #include <ptlib.h>
133 #ifdef __GNUC__
134 #pragma implementation "h450pdu.h"
135 #endif
137 #include "h450pdu.h"
139 #include "h4501.h"
140 #include "h4502.h"
141 #include "h4503.h"
142 #include "h4504.h"
143 #include "h4506.h"
144 #include "h45010.h"
145 #include "h45011.h"
146 #include "h323pdu.h"
147 #include "h323ep.h"
148 #include "h323con.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);
162 return invoke;
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;
173 return returnResult;
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);
188 return returnError;
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;
199 return reject;
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);
220 // Set the alias
221 aliasAddress[1].SetTag(H225_AliasAddress::e_dialedDigits);
222 H323SetAliasAddress(alias, aliasAddress[1]);
224 // Set the transport
225 aliasAddress[0].SetTag(H225_AliasAddress::e_transportID);
226 H225_TransportAddress& cPartyTransport = (H225_TransportAddress&) aliasAddress[0];
227 address.SetPDU(cPartyTransport);
229 else {
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);
237 else {
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,
299 int CICL)
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");
330 return result;
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;
414 PString alias;
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;
422 else
423 alias = ::H323GetAliasAddressString(aliasAddress);
426 if (alias.IsEmpty()) {
427 remoteParty = transportAddress;
429 else if (transportAddress.IsEmpty()) {
430 remoteParty = alias;
432 else {
433 remoteParty = alias + '@' + transportAddress;
438 /////////////////////////////////////////////////////////////////////////////
440 H450xDispatcher::H450xDispatcher(H323Connection & conn)
441 : connection(conn)
443 opcodeHandler.DisallowDeleteObjects();
445 nextInvokeId = 0;
449 void H450xDispatcher::AddOpCode(unsigned opcode, H450xHandler * handler)
451 if (PAssertNULL(handler) == NULL)
452 return;
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)
491 BOOL result = TRUE;
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);
500 else {
501 PTRACE(1, "H4501\tInvalid supplementary service PDU decode:\n "
502 << setprecision(2) << supplementaryService);
503 continue;
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);
519 break;
521 case X880_ROS::e_returnResult:
522 result = OnReceivedReturnResult((X880_ReturnResult &)operation);
523 break;
525 case X880_ROS::e_returnError:
526 result = OnReceivedReturnError((X880_ReturnError &)operation);
527 break;
529 case X880_ROS::e_reject:
530 result = OnReceivedReject((X880_Reject &)operation);
531 break;
533 default :
534 break;
539 return result;
542 BOOL H450xDispatcher::OnReceivedInvoke(X880_Invoke & invoke, H4501_InterpretationApdu & interpretation)
544 BOOL result = TRUE;
545 // Get the invokeId
546 int invokeId = invoke.m_invokeId.GetValue();
548 // Get the linkedId if present
549 int linkedId = -1;
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;
560 // Get the opcode
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)
568 result = FALSE;
570 else
571 result = opcodeHandler[opcode].OnReceivedInvoke(opcode, invokeId, linkedId, argument);
573 else {
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)
578 result = FALSE;
580 return result;
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);
591 break;
594 return TRUE;
598 BOOL H450xDispatcher::OnReceivedReturnError(X880_ReturnError & returnError)
600 BOOL result=TRUE;
601 unsigned invokeId = returnError.m_invokeId.GetValue();
602 int errorCode = 0;
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);
610 break;
613 return result;
617 BOOL H450xDispatcher::OnReceivedReject(X880_Reject & reject)
619 int problem = 0;
621 switch (reject.m_problem.GetTag()) {
622 case X880_Reject_problem::e_general:
624 X880_GeneralProblem & generalProblem = reject.m_problem;
625 problem = generalProblem.GetValue();
627 break;
629 case X880_Reject_problem::e_invoke:
631 X880_InvokeProblem & invokeProblem = reject.m_problem;
632 problem = invokeProblem.GetValue();
634 break;
636 case X880_Reject_problem::e_returnResult:
638 X880_ReturnResultProblem & returnResultProblem = reject.m_problem;
639 problem = returnResultProblem.GetValue();
641 break;
643 case X880_Reject_problem::e_returnError:
645 X880_ReturnErrorProblem & returnErrorProblem = reject.m_problem;
646 problem = returnErrorProblem.GetValue();
648 break;
650 default:
651 break;
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);
659 break;
662 return TRUE;
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()),
732 connection(conn),
733 dispatcher(disp)
735 currentInvokeId = 0;
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*/)
761 return TRUE;
765 BOOL H450xHandler::OnReceivedReturnError(int /*errorCode*/,
766 X880_ReturnError & /*returnError*/)
768 return TRUE;
772 BOOL H450xHandler::OnReceivedReject(int /*problemType*/,
773 int /*problemNumber*/)
775 return TRUE;
779 void H450xHandler::SendReturnError(int returnError)
781 dispatcher.SendReturnError(currentInvokeId, returnError);
782 currentInvokeId = 0;
786 void H450xHandler::SendGeneralReject(int problem)
788 dispatcher.SendGeneralReject(currentInvokeId, problem);
789 currentInvokeId = 0;
793 void H450xHandler::SendInvokeReject(int problem)
795 dispatcher.SendInvokeReject(currentInvokeId, problem);
796 currentInvokeId = 0;
800 void H450xHandler::SendReturnResultReject(int problem)
802 dispatcher.SendReturnResultReject(currentInvokeId, problem);
803 currentInvokeId = 0;
807 void H450xHandler::SendReturnErrorReject(int problem)
809 dispatcher.SendReturnErrorReject(currentInvokeId, problem);
810 currentInvokeId = 0;
814 BOOL H450xHandler::DecodeArguments(PASN_OctetString * argString,
815 PASN_Object & argObject,
816 int absentErrorCode)
818 if (argString == NULL) {
819 if (absentErrorCode >= 0)
820 SendReturnError(absentErrorCode);
821 return FALSE;
824 PPER_Stream argStream(*argString);
825 if (argObject.Decode(argStream)) {
826 PTRACE(4, "H4501\tSupplementary service argument:\n "
827 << setprecision(2) << argObject);
828 return TRUE;
831 PTRACE(1, "H4501\tInvalid supplementary service argument:\n "
832 << setprecision(2) << argObject);
833 return FALSE;
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 = "";
852 ctState = e_ctIdle;
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)
865 return;
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)
883 return;
885 H450ServiceAPDU serviceAPDU;
886 serviceAPDU.BuildReturnResult(currentInvokeId);
887 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
888 ctResponseSent = TRUE;
889 currentInvokeId = 0;
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)
897 return;
899 H450ServiceAPDU serviceAPDU;
900 serviceAPDU.BuildReturnResult(currentInvokeId);
901 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
902 ctResponseSent = TRUE;
903 currentInvokeId = 0;
907 void H4502Handler::AttachToReleaseComplete(H323SignalPDU & pdu)
909 // Do we need to include a ctInitiateReturnResult APDU in our Release Complete Message?
910 if (currentInvokeId == 0)
911 return;
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
915 // ReturnError.
916 // Else normal call - clear it down
917 H450ServiceAPDU serviceAPDU;
919 if (ctResponseSent) {
920 serviceAPDU.BuildReturnResult(currentInvokeId);
921 ctResponseSent = FALSE;
922 currentInvokeId = 0;
924 else {
925 serviceAPDU.BuildReturnError(currentInvokeId, H4501_GeneralErrorList::e_notAvailable);
926 ctResponseSent = TRUE;
927 currentInvokeId = 0;
930 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
934 BOOL H4502Handler::OnReceivedInvoke(int opcode,
935 int invokeId,
936 int linkedId,
937 PASN_OctetString * argument)
939 currentInvokeId = invokeId;
941 switch (opcode) {
942 case H4502_CallTransferOperation::e_callTransferIdentify:
943 OnReceivedCallTransferIdentify(linkedId);
944 break;
946 case H4502_CallTransferOperation::e_callTransferAbandon:
947 OnReceivedCallTransferAbandon(linkedId);
948 break;
950 case H4502_CallTransferOperation::e_callTransferInitiate:
951 OnReceivedCallTransferInitiate(linkedId, argument);
952 break;
954 case H4502_CallTransferOperation::e_callTransferSetup:
955 OnReceivedCallTransferSetup(linkedId, argument);
956 break;
958 case H4502_CallTransferOperation::e_callTransferUpdate:
959 OnReceivedCallTransferUpdate(linkedId, argument);
960 break;
962 case H4502_CallTransferOperation::e_subaddressTransfer:
963 OnReceivedSubaddressTransfer(linkedId, argument);
964 break;
966 case H4502_CallTransferOperation::e_callTransferComplete:
967 OnReceivedCallTransferComplete(linkedId, argument);
968 break;
970 case H4502_CallTransferOperation::e_callTransferActive:
971 OnReceivedCallTransferActive(linkedId, argument);
972 break;
974 default:
975 currentInvokeId = 0;
976 return FALSE;
979 return TRUE;
983 void H4502Handler::OnReceivedCallTransferIdentify(int /*linkedId*/)
985 if (!endpoint.OnCallTransferIdentify(connection)) {
986 SendReturnError(H4501_GeneralErrorList::e_notAvailable);
987 return;
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);
1015 else {
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*/)
1045 switch (ctState) {
1046 case e_ctAwaitSetup:
1048 // Stop Timer CT-T2 and enter state e_ctIdle
1049 StopctTimer();
1050 PTRACE(4, "H4502\tStopping timer CT-T2");
1052 currentInvokeId = 0;
1053 ctState = e_ctIdle;
1055 break;
1057 default:
1058 break;
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))
1072 return;
1074 ctResponseSent = TRUE;
1076 PString remoteParty;
1077 H450ServiceAPDU::ParseEndpointAddress(ctInitiateArg.m_reroutingNumber, remoteParty);
1079 PString newToken;
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))
1094 return;
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
1106 switch (ctState) {
1107 case e_ctIdle:
1108 ctState = e_ctAwaitSetupResponse;
1109 break;
1111 // Wrong State
1112 default :
1113 break;
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))
1138 return;
1143 void H4502Handler::OnReceivedSubaddressTransfer(int /*linkedId*/,
1144 PASN_OctetString * argument)
1146 H4502_SubaddressTransferArg subaddressTransferArg;
1147 if (!DecodeArguments(argument, subaddressTransferArg, -1))
1148 return;
1153 void H4502Handler::OnReceivedCallTransferComplete(int /*linkedId*/,
1154 PASN_OctetString * argument)
1156 H4502_CTCompleteArg ctCompleteArg;
1157 if (!DecodeArguments(argument, ctCompleteArg, -1))
1158 return;
1163 void H4502Handler::OnReceivedCallTransferActive(int /*linkedId*/,
1164 PASN_OctetString * argument)
1166 H4502_CTActiveArg ctActiveArg;
1167 if (!DecodeArguments(argument, ctActiveArg, -1))
1168 return;
1173 BOOL H4502Handler::OnReceivedReturnResult(X880_ReturnResult & returnResult)
1175 if (currentInvokeId == returnResult.m_invokeId.GetValue()) {
1176 switch (ctState) {
1177 case e_ctAwaitInitiateResponse:
1178 OnReceivedInitiateReturnResult();
1179 break;
1181 case e_ctAwaitSetupResponse:
1182 OnReceivedSetupReturnResult();
1183 break;
1185 case e_ctAwaitIdentifyResponse:
1186 OnReceivedIdentifyReturnResult(returnResult);
1187 break;
1189 default :
1190 break;
1193 return TRUE;
1197 void H4502Handler::OnReceivedInitiateReturnResult()
1199 // stop timer CT-T3
1200 StopctTimer();
1201 PTRACE(4, "H4502\tStopping timer CT-T3");
1202 ctState = e_ctIdle;
1203 currentInvokeId = 0;
1205 // clear the primary and secondary call if not already cleared,
1209 void H4502Handler::OnReceivedSetupReturnResult()
1211 // stop timer CT-T4
1212 StopctTimer();
1213 PTRACE(4, "H4502\tStopping timer CT-T4");
1214 ctState = e_ctIdle;
1215 currentInvokeId = 0;
1217 // Clear the primary call
1218 endpoint.ClearCall(transferringCallToken, H323Connection::EndedByCallForwarded);
1222 void H4502Handler::OnReceivedIdentifyReturnResult(X880_ReturnResult &returnResult)
1224 // stop timer CT-T1
1225 StopctTimer();
1226 PTRACE(4, "H4502\tStopping timer CT-T1");
1228 // Have received response.
1229 ctState = e_ctIdle;
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()) {
1266 switch (ctState) {
1267 case e_ctAwaitInitiateResponse:
1268 OnReceivedInitiateReturnError();
1269 break;
1271 case e_ctAwaitSetupResponse:
1272 OnReceivedSetupReturnError(errorCode);
1273 break;
1275 case e_ctAwaitIdentifyResponse:
1276 OnReceivedIdentifyReturnError();
1277 break;
1279 default :
1280 break;
1283 return TRUE;
1287 void H4502Handler::OnReceivedInitiateReturnError(const bool timerExpiry)
1289 if (!timerExpiry) {
1290 // stop timer CT-T3
1291 StopctTimer();
1292 PTRACE(4, "H4502\tStopping timer CT-T3 on Error");
1294 else
1295 PTRACE(4, "H4502\tTimer CT-T3 has expired on the Transferring Endpoint awaiting a response to a callTransferInitiate APDU.");
1297 currentInvokeId = 0;
1298 ctState = e_ctIdle;
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();
1317 } else {
1318 endpoint.OnReceivedInitiateReturnError();
1323 void H4502Handler::OnReceivedSetupReturnError(int errorCode,
1324 const bool timerExpiry)
1326 ctState = e_ctIdle;
1327 currentInvokeId = 0;
1329 if (!timerExpiry) {
1330 // stop timer CT-T4 if it is running
1331 StopctTimer();
1332 PTRACE(4, "H4502\tStopping timer CT-T4");
1334 else {
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
1355 ctState = e_ctIdle;
1356 currentInvokeId = 0;
1358 if (!timerExpiry) {
1359 // stop timer CT-T1
1360 StopctTimer();
1361 PTRACE(4, "H4502\tStopping timer CT-T1");
1363 else {
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.
1368 connection.Lock();
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;
1388 PString alias;
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)
1431 switch (ctState) {
1432 case e_ctAwaitSetup:
1434 // Remove this callIdentity, connection pair from our dictionary as we no longer need it
1435 endpoint.GetCallIdentityDictionary().RemoveAt(callIdentity);
1437 // Stop timer CT-T2
1438 StopctTimer();
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;
1446 ctState = e_ctIdle;
1448 endpoint.ClearCall(connection.GetCallToken());
1450 break;
1452 // Wrong Call Transfer State
1453 default :
1454 break;
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) {
1476 ctState = e_ctIdle;
1478 // Stop timer CT-T4 if it is running
1479 StopctTimer();
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())
1503 ctTimer.Stop();
1507 void H4502Handler::OnCallTransferTimeOut(PTimer &, INT)
1509 switch (ctState) {
1510 // CT-T3 Timeout
1511 case e_ctAwaitInitiateResponse:
1512 OnReceivedInitiateReturnError(true);
1513 break;
1515 // CT-T1 Timeout
1516 case e_ctAwaitIdentifyResponse:
1517 OnReceivedIdentifyReturnError(true);
1518 break;
1520 // CT-T2 Timeout
1521 case e_ctAwaitSetup:
1523 // Abort the call transfer
1524 ctState = e_ctIdle;
1525 currentInvokeId = 0;
1526 PTRACE(4, "H450.2\tTimer CT-T2 has expired on the Transferred-to endpoint awaiting a callTransferSetup APDU.");
1528 break;
1530 // CT-T4 Timeout
1531 case e_ctAwaitSetupResponse:
1532 OnReceivedSetupReturnError(H4502_CallTransferErrors::e_establishmentFailure, true);
1533 break;
1535 default:
1536 break;
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,
1550 int invokeId,
1551 int linkedId,
1552 PASN_OctetString *argument)
1554 currentInvokeId = invokeId;
1555 switch (opcode) {
1556 case H4503_H323CallDiversionOperations::e_divertingLegInformation2:
1557 OnReceivedDivertingLegInfo2(linkedId, argument);
1558 break;
1560 default:
1561 currentInvokeId = 0;
1562 return FALSE;
1565 return TRUE;
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;
1596 bRedirAvail = true;
1598 if(!m_lastDivertingNr.IsEmpty()) {
1599 lastDivertingNr = m_lastDivertingNr;
1600 bRedirAvail = true;
1603 divCounter = m_diversionCounter;
1604 divReason = m_diversionReason;
1605 origdivReason = m_origdiversionReason;
1607 return bRedirAvail;
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,
1627 int invokeId,
1628 int linkedId,
1629 PASN_OctetString *)
1631 currentInvokeId = invokeId;
1633 switch (opcode) {
1634 case H4504_CallHoldOperation::e_holdNotific:
1635 OnReceivedLocalCallHold(linkedId);
1636 break;
1638 case H4504_CallHoldOperation::e_retrieveNotific:
1639 OnReceivedLocalCallRetrieve(linkedId);
1640 break;
1642 case H4504_CallHoldOperation::e_remoteHold:
1643 OnReceivedRemoteCallHold(linkedId);
1644 break;
1646 case H4504_CallHoldOperation::e_remoteRetrieve:
1647 OnReceivedRemoteCallRetrieve(linkedId);
1648 break;
1650 default:
1651 currentInvokeId = 0;
1652 return FALSE;
1655 return TRUE;
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*/)
1675 // TBD
1679 void H4504Handler::OnReceivedRemoteCallRetrieve(int /*linkedId*/)
1681 // TBD
1685 void H4504Handler::HoldCall(BOOL localHold)
1687 // TBD: Implement Remote Hold. This implementation only does
1688 // local hold. -- dcassel 4/01.
1689 if (!localHold)
1690 return;
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,
1738 int invokeId,
1739 int linkedId,
1740 PASN_OctetString *argument)
1742 currentInvokeId = invokeId;
1744 switch (opcode) {
1745 case H4506_CallWaitingOperations::e_callWaiting:
1746 OnReceivedCallWaitingIndication(linkedId, argument);
1747 break;
1749 default:
1750 currentInvokeId = 0;
1751 return FALSE;
1754 return TRUE;
1758 void H4506Handler::OnReceivedCallWaitingIndication(int /*linkedId*/,
1759 PASN_OctetString *argument)
1761 H4506_CallWaitingArg cwArg;
1763 if(!DecodeArguments(argument, cwArg, -1))
1764 return;
1766 connection.SetRemoteCallWaiting(cwArg.m_nbOfAddWaitingCalls.GetValue());
1767 return;
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,
1814 int invokeId,
1815 int linkedId,
1816 PASN_OctetString * argument)
1818 BOOL result = TRUE;
1819 currentInvokeId = invokeId;
1821 switch (opcode) {
1822 case H45011_H323CallIntrusionOperations::e_callIntrusionRequest:
1823 OnReceivedCallIntrusionRequest(linkedId, argument);
1824 break;
1826 case H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL:
1827 OnReceivedCallIntrusionGetCIPL(linkedId, argument);
1828 break;
1830 case H45011_H323CallIntrusionOperations::e_callIntrusionIsolate:
1831 OnReceivedCallIntrusionIsolate(linkedId, argument);
1832 break;
1834 case H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease:
1835 result = OnReceivedCallIntrusionForcedRelease(linkedId, argument);
1836 break;
1838 case H45011_H323CallIntrusionOperations::e_callIntrusionWOBRequest:
1839 OnReceivedCallIntrusionWOBRequest(linkedId, argument);
1840 break;
1842 case H45011_H323CallIntrusionOperations::e_callIntrusionSilentMonitor:
1843 OnReceivedCallIntrusionSilentMonitor(linkedId, argument);
1844 break;
1846 case H45011_H323CallIntrusionOperations::e_callIntrusionNotification:
1847 OnReceivedCallIntrusionNotification(linkedId, argument);
1848 break;
1850 case H45010_H323CallOfferOperations::e_cfbOverride:
1851 OnReceivedCfbOverride(linkedId, argument);
1852 break;
1854 case H45010_H323CallOfferOperations::e_remoteUserAlerting:
1855 OnReceivedRemoteUserAlerting(linkedId, argument);
1856 break;
1858 case H4506_CallWaitingOperations::e_callWaiting:
1859 OnReceivedCallWaiting(linkedId, argument);
1860 break;
1862 default:
1863 currentInvokeId = 0;
1864 return FALSE;
1867 return result;
1871 void H45011Handler::AttachToSetup(H323SignalPDU & pdu)
1873 // Do we need to attach a call transfer setup invoke APDU?
1874 if (ciSendState != e_ci_sAttachToSetup)
1875 return;
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:
1885 break;
1886 case e_ci_gHeldRequest:
1887 break;
1888 case e_ci_gSilentMonitorRequest:
1889 break;
1890 case e_ci_gIsolationRequest:
1891 break;
1892 case e_ci_gForcedReleaseRequest:
1893 serviceAPDU.BuildCallIntrusionForcedRelease(currentInvokeId, ciCICL);
1894 break;
1895 case e_ci_gWOBRequest:
1896 break;
1897 default:
1898 break;
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)
1918 return;
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");
1931 break;
1932 case e_ci_rCallIntruded:
1933 break;
1934 case e_ci_rCallIsolated:
1935 break;
1936 case e_ci_rCallForceReleased:
1937 break;
1938 case e_ci_rCallForceReleaseResult:
1939 serviceAPDU.BuildCallIntrusionForcedReleaseResult(currentInvokeId);
1940 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
1941 break;
1942 case e_ci_rCallIntrusionComplete:
1943 break;
1944 case e_ci_rCallIntrusionEnd:
1945 break;
1946 case e_ci_rNotBusy:
1947 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
1948 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
1949 break;
1950 case e_ci_rTempUnavailable:
1951 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
1952 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
1953 break;
1954 case e_ci_rNotAuthorized:
1955 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
1956 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
1957 break;
1958 default :
1959 break;
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))
1973 return;
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:
1981 break;
1982 case e_ci_rCallIntruded:
1983 break;
1984 case e_ci_rCallIsolated:
1985 break;
1986 case e_ci_rCallForceReleased:
1987 break;
1988 case e_ci_rCallForceReleaseResult:
1989 serviceAPDU.BuildCallIntrusionForcedReleaseResult(currentInvokeId);
1990 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
1991 break;
1992 case e_ci_rCallIntrusionComplete:
1993 break;
1994 case e_ci_rCallIntrusionEnd:
1995 break;
1996 case e_ci_rNotBusy:
1997 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
1998 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
1999 break;
2000 case e_ci_rTempUnavailable:
2001 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2002 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
2003 break;
2004 case e_ci_rNotAuthorized:
2005 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2006 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
2007 break;
2008 default :
2009 break;
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)
2028 return;
2030 PTRACE(4, "H450.11\tAttachToSetup Invoke ID=" << currentInvokeId);
2031 if(ciReturnState!=e_ci_rIdle){
2032 H450ServiceAPDU serviceAPDU;
2033 switch (ciReturnState){
2034 case e_ci_rNotBusy:
2035 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
2036 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2037 break;
2038 case e_ci_rTempUnavailable:
2039 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2040 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
2041 break;
2042 case e_ci_rNotAuthorized:
2043 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2044 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
2045 break;
2046 case e_ci_rCallForceReleased:
2047 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForceRelease::e_ci_rCallForceReleased");
2048 serviceAPDU.BuildCallIntrusionForceRelesed(currentInvokeId);
2049 break;
2050 default :
2051 break;
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))
2069 return;
2073 return;
2077 void H45011Handler::OnReceivedCallIntrusionGetCIPL(int /*linkedId*/,
2078 PASN_OctetString *argument)
2080 PTRACE(4, "H450.11\tReceived GetCIPL Invoke");
2082 H45011_CIGetCIPLOptArg ciArg;
2084 // !!!!!!!!
2085 DecodeArguments(argument, ciArg, -1);
2086 /* if(!DecodeArguments(argument, ciArg, -1))
2087 return;
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);
2116 return;
2120 void H45011Handler::OnReceivedCallIntrusionIsolate(int /*linkedId*/,
2121 PASN_OctetString *argument)
2124 H45011_CIIsOptArg ciArg;
2126 if(!DecodeArguments(argument, ciArg, -1))
2127 return;
2131 return;
2135 BOOL H45011Handler::OnReceivedCallIntrusionForcedRelease(int /*linkedId*/,
2136 PASN_OctetString *argument)
2138 BOOL result = TRUE;
2139 PTRACE(4, "H450.11\tReceived ForcedRelease Invoke");
2141 H45011_CIFrcRelArg ciArg;
2143 if(!DecodeArguments(argument, ciArg, -1))
2144 return FALSE;
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]);
2152 if (conn != NULL){
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);
2158 result = TRUE;
2159 conn->Unlock ();
2160 break;
2162 else
2163 result = FALSE;
2165 conn->Unlock ();
2169 if(result){
2170 ciSendState = e_ci_sAttachToConnect;
2171 ciReturnState = e_ci_rCallForceReleaseResult;
2172 connection.SetCallIntrusion ();
2174 else {
2175 ciSendState = e_ci_sAttachToReleseComplete;
2176 ciReturnState = e_ci_rNotAuthorized;
2177 connection.ClearCall(H323Connection::EndedByLocalBusy);
2180 else{
2181 ciSendState = e_ci_sAttachToAlerting;
2182 ciReturnState = e_ci_rNotBusy;
2185 return result;
2189 void H45011Handler::OnReceivedCallIntrusionWOBRequest(int /*linkedId*/,
2190 PASN_OctetString *argument)
2193 H45011_CIWobOptArg ciArg;
2195 if(!DecodeArguments(argument, ciArg, -1))
2196 return;
2200 return;
2204 void H45011Handler::OnReceivedCallIntrusionSilentMonitor(int /*linkedId*/,
2205 PASN_OctetString *argument)
2208 H45011_CISilentArg ciArg;
2210 if(!DecodeArguments(argument, ciArg, -1))
2211 return;
2215 return;
2219 void H45011Handler::OnReceivedCallIntrusionNotification(int /*linkedId*/,
2220 PASN_OctetString *argument)
2223 H45011_CINotificationArg ciArg;
2225 if(!DecodeArguments(argument, ciArg, -1))
2226 return;
2230 return;
2234 void H45011Handler::OnReceivedCfbOverride(int /*linkedId*/,
2235 PASN_OctetString *argument)
2238 H45010_CfbOvrOptArg ciArg;
2240 if(!DecodeArguments(argument, ciArg, -1))
2241 return;
2245 return;
2249 void H45011Handler::OnReceivedRemoteUserAlerting(int /*linkedId*/,
2250 PASN_OctetString *argument)
2253 H45010_RUAlertOptArg ciArg;
2255 if(!DecodeArguments(argument, ciArg, -1))
2256 return;
2260 return;
2264 void H45011Handler::OnReceivedCallWaiting(int /*linkedId*/,
2265 PASN_OctetString *argument)
2268 H4506_CallWaitingArg ciArg;
2270 if(!DecodeArguments(argument, ciArg, -1))
2271 return;
2275 return;
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);
2284 switch (ciState) {
2285 case e_ci_WaitAck:
2286 OnReceivedCIRequestResult();
2287 break;
2288 case e_ci_GetCIPL:
2289 OnReceivedCIGetCIPLResult(returnResult);
2290 break;
2291 default :
2292 break;
2295 return TRUE;
2299 void H45011Handler::OnReceivedCIRequestResult()
2301 PTRACE(4, "H450.11\tOnReceivedCIRequestResult");
2302 // stop timer CI-T1
2303 PTRACE(4, "H450.11\tTrying to stop timer CI-T1");
2304 StopciTimer();
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
2327 connection.Lock();
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();
2347 conn->Unlock ();
2349 else {
2350 PTRACE(4 ,"H450.11\tCICL<CIPL -> Clear Call");
2351 // Clear Call with intruding (A)
2352 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2353 conn->SetIntrusionNotAuthorized();
2354 conn->Unlock();
2355 endpoint.ClearCall (intrudingCallToken);
2359 // stop timer CI-T5
2360 PTRACE(4, "H450.11\tTrying to stop timer CI-T5");
2361 StopciTimer();
2365 BOOL H45011Handler::OnReceivedReturnError(int errorCode, X880_ReturnError &returnError)
2367 BOOL result = TRUE;
2368 PTRACE(4, "H450.11\tReceived Return Error CODE=" <<errorCode << ", InvokeId=" <<returnError.m_invokeId.GetValue());
2369 if (currentInvokeId == returnError.m_invokeId.GetValue()) {
2370 switch (ciState) {
2371 case e_ci_WaitAck:
2372 result = OnReceivedInvokeReturnError(errorCode);
2373 break;
2374 case e_ci_GetCIPL:
2375 result = OnReceivedGetCIPLReturnError(errorCode);
2376 break;
2377 default :
2378 break;
2381 return result;
2385 BOOL H45011Handler::OnReceivedInvokeReturnError(int errorCode, const bool timerExpiry)
2387 BOOL result = FALSE;
2388 PTRACE(4, "H450.11\tOnReceivedInvokeReturnError CODE =" << errorCode);
2389 if (!timerExpiry) {
2390 // stop timer CI-T1
2391 StopciTimer();
2392 PTRACE(4, "H450.11\tStopping timer CI-T1");
2394 else
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;
2401 switch(errorCode){
2402 case H45011_CallIntrusionErrors::e_notBusy :
2403 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notBusy");
2404 result = TRUE;
2405 break;
2406 case H45011_CallIntrusionErrors::e_temporarilyUnavailable :
2407 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_temporarilyUnavailable");
2408 break;
2409 case H45011_CallIntrusionErrors::e_notAuthorized :
2410 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notAuthorized");
2411 result = TRUE;
2412 break;
2413 default:
2414 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::DEFAULT");
2415 break;
2417 return result;
2421 BOOL H45011Handler::OnReceivedGetCIPLReturnError(int PTRACE_PARAM(errorCode),
2422 const bool timerExpiry)
2424 PTRACE(4, "H450.11\tOnReceivedGetCIPLReturnError ErrorCode=" << errorCode);
2425 if(!timerExpiry){
2426 if (ciTimer.IsRunning()){
2427 ciTimer.Stop();
2428 PTRACE(4, "H450.11\tStopping timer CI-TX");
2432 // Send ciNotification.inv (ciImpending) to active call (C)
2433 connection.Lock();
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();
2452 conn->Unlock ();
2454 return FALSE;
2458 void H45011Handler::IntrudeCall(int CICL)
2460 ciSendState = e_ci_sAttachToSetup;
2461 ciGenerateState = e_ci_gForcedReleaseRequest;
2462 ciCICL = CICL;
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())
2480 return FALSE;
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))
2494 return FALSE;
2496 PTRACE(4, "H450.11\tStarting timer CI-T5");
2497 StartciTimer(connection.GetEndPoint().GetCallIntrusionT5());
2498 ciState = e_ci_GetCIPL;
2499 return TRUE;
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()){
2530 ciTimer.Stop();
2531 PTRACE(4, "H450.11\tStopping timer CI-TX");
2536 void H45011Handler::OnCallIntrudeTimeOut(PTimer &, INT)
2538 switch (ciState) {
2539 // CI-T1 Timeout
2540 case e_ci_WaitAck:
2541 PTRACE(4, "H450.11\tTimer CI-T1 has expired");
2542 OnReceivedInvokeReturnError(0,true);
2543 break;
2544 case e_ci_GetCIPL:
2545 PTRACE(4, "H450.11\tTimer CI-T5 has expired");
2546 OnReceivedGetCIPLReturnError(0,true);
2547 break;
2548 case e_ci_DestNotify:
2550 PTRACE(4, "H450.11\tOnCallIntrudeTimeOut Timer CI-T6 has expired");
2551 // Clear the active call (call with C)
2552 PSyncPoint sync;
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);
2559 conn->Unlock ();
2562 break;
2563 default:
2564 break;
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()){
2575 ciTimer.Stop();
2576 PTRACE(4, "H450.11\tStopping timer CI-TX");
2579 switch (ciState) {
2580 case e_ci_GetCIPL:
2582 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2583 conn->SetIntrusionImpending ();
2585 //Send Ringing to intruding (A)
2586 conn->AnsweringCall (conn->AnswerCallPending);
2587 conn->SetForcedReleaseAccepted();
2588 conn->Unlock ();
2589 break;
2592 default:
2593 break;
2595 ciState = e_ci_Idle;
2596 return TRUE;