1 /*
2 * h450pdu.cxx
3 *
4 * H.450 Helper functions
5 *
6 * Open H323 Library
7 *
8 * Copyright (c) 2001 Norwood Systems Pty. Ltd.
9 *
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/
14 *
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.
19 *
20 * The Original Code is Open H323 Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Id$
27 *
28 */
29
30 #include <ptlib.h>
31
32 #ifdef __GNUC__
33 #pragma implementation "h450pdu.h"
34 #endif
35
36 #include "h450/h450pdu.h"
37
38 #include "h450/h4501.h"
39 #include "h450/h4502.h"
40 #include "h450/h4503.h"
41 #include "h450/h4504.h"
42 #include "h450/h4506.h"
43 #include "h450/h4507.h"
44 #include "h450/h45010.h"
45 #include "h450/h45011.h"
46 #include "h323pdu.h"
47 #include "h323ep.h"
48 #include "h323con.h"
49
50
BuildInvoke(int invokeId,int operation)51 X880_Invoke& H450ServiceAPDU::BuildInvoke(int invokeId, int operation)
52 {
53 SetTag(X880_ROS::e_invoke);
54 X880_Invoke& invoke = (X880_Invoke&) *this;
55
56 invoke.m_invokeId = invokeId;
57
58 invoke.m_opcode.SetTag(X880_Code::e_local);
59 PASN_Integer& opcode = (PASN_Integer&) invoke.m_opcode;
60 opcode.SetValue(operation);
61
62 return invoke;
63 }
64
65
BuildReturnResult(int invokeId)66 X880_ReturnResult& H450ServiceAPDU::BuildReturnResult(int invokeId)
67 {
68 SetTag(X880_ROS::e_returnResult);
69 X880_ReturnResult& returnResult = (X880_ReturnResult&) *this;
70
71 returnResult.m_invokeId = invokeId;
72
73 return returnResult;
74 }
75
76
BuildReturnError(int invokeId,int error)77 X880_ReturnError& H450ServiceAPDU::BuildReturnError(int invokeId, int error)
78 {
79 SetTag(X880_ROS::e_returnError);
80 X880_ReturnError& returnError = (X880_ReturnError&) *this;
81
82 returnError.m_invokeId = invokeId;
83
84 returnError.m_errorCode.SetTag(X880_Code::e_local);
85 PASN_Integer& errorCode = (PASN_Integer&) returnError.m_errorCode;
86 errorCode.SetValue(error);
87
88 return returnError;
89 }
90
91
BuildReject(int invokeId)92 X880_Reject& H450ServiceAPDU::BuildReject(int invokeId)
93 {
94 SetTag(X880_ROS::e_reject);
95 X880_Reject& reject = (X880_Reject&) *this;
96
97 reject.m_invokeId = invokeId;
98
99 return reject;
100 }
101
102
BuildCallTransferInitiate(int invokeId,const PString & callIdentity,const PString & alias,const H323TransportAddress & address)103 void H450ServiceAPDU::BuildCallTransferInitiate(int invokeId,
104 const PString & callIdentity,
105 const PString & alias,
106 const H323TransportAddress & address)
107 {
108 X880_Invoke& invoke = BuildInvoke(invokeId, H4502_CallTransferOperation::e_callTransferInitiate);
109
110 H4502_CTInitiateArg argument;
111
112 if (callIdentity.IsEmpty()) {
113 // a callIdentity of size 0 is allowed according to the H.450.2 ASN,
114 // but if we encode an empty string, Wireshark (and other devices, eg. Innovaphone) consider the packet malformed
115 // could also be an encoder bug - JW
116 argument.m_callIdentity = " ";
117 } else {
118 argument.m_callIdentity = callIdentity;
119 }
120
121 H4501_ArrayOf_AliasAddress& aliasAddress = argument.m_reroutingNumber.m_destinationAddress;
122
123 // We have to have at least a destination transport address or alias.
124 if (!alias.IsEmpty() && !address.IsEmpty()) {
125 aliasAddress.SetSize(2);
126
127 // Set the alias
128 H323SetAliasAddress(alias, aliasAddress[1]);
129
130 // Set the transport
131 aliasAddress[0].SetTag(H225_AliasAddress::e_transportID);
132 H225_TransportAddress& cPartyTransport = (H225_TransportAddress&) aliasAddress[0];
133 address.SetPDU(cPartyTransport);
134 }
135 else {
136 aliasAddress.SetSize(1);
137 if (alias.IsEmpty()) {
138 // Set the transport, no alias present
139 aliasAddress[0].SetTag(H225_AliasAddress::e_transportID);
140 H225_TransportAddress& cPartyTransport = (H225_TransportAddress&) aliasAddress[0];
141 address.SetPDU(cPartyTransport);
142 }
143 else {
144 // Set the alias, no transport
145 H323SetAliasAddress(alias, aliasAddress[0]);
146 }
147 }
148
149 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
150 << setprecision(2) << argument);
151
152 invoke.IncludeOptionalField(X880_Invoke::e_argument);
153 invoke.m_argument.EncodeSubType(argument);
154 }
155
156
BuildCallTransferSetup(int invokeId,const PString & callIdentity)157 void H450ServiceAPDU::BuildCallTransferSetup(int invokeId,
158 const PString & callIdentity)
159 {
160 X880_Invoke& invoke = BuildInvoke(invokeId, H4502_CallTransferOperation::e_callTransferSetup);
161
162 H4502_CTSetupArg argument;
163
164 argument.m_callIdentity = callIdentity;
165
166 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
167 << setprecision(2) << argument);
168
169 invoke.IncludeOptionalField(X880_Invoke::e_argument);
170 invoke.m_argument.EncodeSubType(argument);
171 }
172
173
BuildCallTransferIdentify(int invokeId)174 void H450ServiceAPDU::BuildCallTransferIdentify(int invokeId)
175 {
176 X880_Invoke invoke = BuildInvoke(invokeId, H4502_CallTransferOperation::e_callTransferIdentify);
177 }
178
179
BuildCallTransferAbandon(int invokeId)180 void H450ServiceAPDU::BuildCallTransferAbandon(int invokeId)
181 {
182 X880_Invoke invoke = BuildInvoke(invokeId, H4502_CallTransferOperation::e_callTransferAbandon);
183 }
184
185
BuildCallWaiting(int invokeId,int numCallsWaiting)186 void H450ServiceAPDU::BuildCallWaiting(int invokeId, int numCallsWaiting)
187 {
188 X880_Invoke& invoke = BuildInvoke(invokeId, H4506_CallWaitingOperations::e_callWaiting);
189
190 H4506_CallWaitingArg argument;
191
192 argument.IncludeOptionalField(H4506_CallWaitingArg::e_nbOfAddWaitingCalls);
193 argument.m_nbOfAddWaitingCalls = numCallsWaiting;
194
195 PTRACE(4, "H4502\tSending supplementary service PDU argument:\n "
196 << setprecision(2) << argument);
197
198 invoke.IncludeOptionalField(X880_Invoke::e_argument);
199 invoke.m_argument.EncodeSubType(argument);
200 }
201
202 ////////////////////////////////////////////////////////////////////////////////
203
BuildMessageWaitIndicationActivate(int invokeId)204 X880_Invoke & H450ServiceAPDU::BuildMessageWaitIndicationActivate(int invokeId)
205 {
206 X880_Invoke & invoke = BuildInvoke(invokeId, H4507_H323_MWI_Operations::e_mwiActivate);
207 invoke.IncludeOptionalField(X880_Invoke::e_argument);
208
209 return invoke;
210 }
211
BuildMessageWaitIndicationDeactivate(int invokeId)212 X880_Invoke & H450ServiceAPDU::BuildMessageWaitIndicationDeactivate(int invokeId)
213 {
214 X880_Invoke & invoke = BuildInvoke(invokeId, H4507_H323_MWI_Operations::e_mwiDeactivate);
215 invoke.IncludeOptionalField(X880_Invoke::e_argument);
216
217 return invoke;
218 }
219
BuildMessageWaitIndicationInterrogate(int invokeId)220 X880_Invoke & H450ServiceAPDU::BuildMessageWaitIndicationInterrogate(int invokeId)
221 {
222 X880_Invoke & invoke = BuildInvoke(invokeId, H4507_H323_MWI_Operations::e_mwiInterrogate);
223 invoke.IncludeOptionalField(X880_Invoke::e_argument);
224
225 return invoke;
226 }
227
BuildMessageWaitIndicationResult(int invokeId,int opcode)228 X880_ReturnResult & H450ServiceAPDU::BuildMessageWaitIndicationResult(int invokeId, int opcode)
229 {
230
231 X880_ReturnResult& result = BuildReturnResult(invokeId);
232 result.IncludeOptionalField(X880_ReturnResult::e_result);
233 result.m_result.m_opcode.SetTag(X880_Code::e_local);
234 PASN_Integer& operation = (PASN_Integer&) result.m_result.m_opcode;
235 operation.SetValue(opcode);
236
237 return result;
238 }
239
240 ////////////////////////////////////////////////////////////////////////////////////////
241
BuildCallIntrusionForcedRelease(int invokeId,int CICL)242 void H450ServiceAPDU::BuildCallIntrusionForcedRelease(int invokeId,
243 int CICL)
244 {
245 X880_Invoke& invoke = BuildInvoke(invokeId, H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease);
246
247 H45011_CIFrcRelArg argument;
248
249 argument.m_ciCapabilityLevel = CICL;
250
251 invoke.IncludeOptionalField(X880_Invoke::e_argument);
252 invoke.m_argument.EncodeSubType(argument);
253 }
254
255
BuildCallIntrusionForcedReleaseResult(int invokeId)256 X880_ReturnResult& H450ServiceAPDU::BuildCallIntrusionForcedReleaseResult(int invokeId)
257 {
258 PTRACE(1 ,"H450.11\tH450ServiceAPDU::BuildCallIntrusionForcedReleaseResult BEGIN");
259
260 X880_ReturnResult& result = BuildReturnResult(invokeId);
261 result.IncludeOptionalField(X880_ReturnResult::e_result);
262 result.m_result.m_opcode.SetTag(X880_Code::e_local);
263 PASN_Integer& operation = (PASN_Integer&) result.m_result.m_opcode;
264 operation.SetValue(H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease);
265
266 H45011_CIFrcRelOptRes ciCIPLRes;
267
268 PPER_Stream resultStream;
269 ciCIPLRes.Encode(resultStream);
270 resultStream.CompleteEncoding();
271 result.m_result.m_result.SetValue(resultStream);
272 PTRACE(4 ,"H450.11\tH450ServiceAPDU::BuildCallIntrusionForcedReleaseResult END");
273
274 return result;
275 }
276
277
BuildCallIntrusionForcedReleaseError()278 void H450ServiceAPDU::BuildCallIntrusionForcedReleaseError()
279 {
280 /**
281 TBD
282 */
283 }
284
285
BuildCallIntrusionGetCIPL(int invokeId)286 void H450ServiceAPDU::BuildCallIntrusionGetCIPL(int invokeId)
287 {
288 PTRACE(4, "H450.11\tBuildCallIntrusionGetCIPL invokeId=" << invokeId);
289 X880_Invoke invoke = BuildInvoke(invokeId, H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL);
290 }
291
292
BuildCallIntrusionImpending(int invokeId)293 void H450ServiceAPDU::BuildCallIntrusionImpending(int invokeId)
294 {
295 PTRACE(4, "H450.11\tBuildCallIntrusionImpending invokeId=" << invokeId);
296 X880_Invoke& invoke = BuildInvoke(invokeId, H45011_H323CallIntrusionOperations::e_callIntrusionNotification);
297
298 H45011_CINotificationArg argument;
299
300 argument.m_ciStatusInformation = H45011_CIStatusInformation::e_callIntrusionImpending;
301
302 invoke.IncludeOptionalField(X880_Invoke::e_argument);
303 invoke.m_argument.EncodeSubType(argument);
304 }
305
306
BuildCallIntrusionForceRelesed(int invokeId)307 void H450ServiceAPDU::BuildCallIntrusionForceRelesed(int invokeId)
308 {
309 PTRACE(4, "H450.11\tBuildCallIntrusionForceRelesed invokeId=" << invokeId);
310 X880_Invoke& invoke = BuildInvoke(invokeId, H45011_H323CallIntrusionOperations::e_callIntrusionNotification);
311
312 H45011_CINotificationArg argument;
313
314 argument.m_ciStatusInformation = H45011_CIStatusInformation::e_callForceReleased;
315
316 invoke.IncludeOptionalField(X880_Invoke::e_argument);
317 invoke.m_argument.EncodeSubType(argument);
318 }
319
320
AttachSupplementaryServiceAPDU(H323SignalPDU & pdu)321 void H450ServiceAPDU::AttachSupplementaryServiceAPDU(H323SignalPDU & pdu)
322 {
323 H4501_SupplementaryService supplementaryService;
324
325 // Create an H.450.1 supplementary service object
326 // and store the H450ServiceAPDU in the ROS array.
327 supplementaryService.m_serviceApdu.SetTag(H4501_ServiceApdus::e_rosApdus);
328 H4501_ArrayOf_ROS & operations = (H4501_ArrayOf_ROS &)supplementaryService.m_serviceApdu;
329 operations.SetSize(1);
330 operations[0] = *this;
331
332 PTRACE(4, "H4501\tSending supplementary service PDU:\n "
333 << setprecision(2) << supplementaryService);
334
335 // Add the H.450 PDU to the H.323 User-to-User PDU as an OCTET STRING
336 pdu.m_h323_uu_pdu.IncludeOptionalField(H225_H323_UU_PDU::e_h4501SupplementaryService);
337 pdu.m_h323_uu_pdu.m_h4501SupplementaryService.SetSize(1);
338 pdu.m_h323_uu_pdu.m_h4501SupplementaryService[0].EncodeSubType(supplementaryService);
339 }
340
341
WriteFacilityPDU(H323Connection & connection)342 PBoolean H450ServiceAPDU::WriteFacilityPDU(H323Connection & connection)
343 {
344 H323SignalPDU facilityPDU;
345 facilityPDU.BuildFacility(connection, TRUE);
346
347 AttachSupplementaryServiceAPDU(facilityPDU);
348
349 return connection.WriteSignalPDU(facilityPDU);
350 }
351
352
ParseEndpointAddress(H4501_EndpointAddress & endpointAddress,PString & remoteParty)353 void H450ServiceAPDU::ParseEndpointAddress(H4501_EndpointAddress& endpointAddress,
354 PString& remoteParty)
355 {
356 H4501_ArrayOf_AliasAddress& destinationAddress = endpointAddress.m_destinationAddress;
357
358 PString alias;
359 H323TransportAddress transportAddress;
360
361 for (PINDEX i = 0; i < destinationAddress.GetSize(); i++) {
362 H225_AliasAddress& aliasAddress = destinationAddress[i];
363
364 if (aliasAddress.GetTag() == H225_AliasAddress::e_transportID)
365 transportAddress = (H225_TransportAddress &)aliasAddress;
366 else
367 alias = ::H323GetAliasAddressString(aliasAddress);
368 }
369
370 if (alias.IsEmpty()) {
371 remoteParty = transportAddress;
372 }
373 else if (transportAddress.IsEmpty()) {
374 remoteParty = alias;
375 }
376 else {
377 remoteParty = alias + '@' + transportAddress;
378 }
379 }
380
381
382 /////////////////////////////////////////////////////////////////////////////
383
H450xDispatcher(H323Connection & conn)384 H450xDispatcher::H450xDispatcher(H323Connection & conn)
385 : connection(conn)
386 {
387 opcodeHandler.DisallowDeleteObjects();
388
389 nextInvokeId = 0;
390 }
391
392
AddOpCode(unsigned opcode,H450xHandler * handler)393 void H450xDispatcher::AddOpCode(unsigned opcode, H450xHandler * handler)
394 {
395 if (PAssertNULL(handler) == NULL)
396 return;
397
398 if (handlers.GetObjectsIndex(handler) == P_MAX_INDEX)
399 handlers.Append(handler);
400
401 opcodeHandler.SetAt(opcode, handler);
402 }
403
404
AttachToSetup(H323SignalPDU & pdu)405 void H450xDispatcher::AttachToSetup(H323SignalPDU & pdu)
406 {
407 for (PINDEX i = 0; i < handlers.GetSize(); i++)
408 handlers[i].AttachToSetup(pdu);
409 }
410
411
AttachToAlerting(H323SignalPDU & pdu)412 void H450xDispatcher::AttachToAlerting(H323SignalPDU & pdu)
413 {
414 for (PINDEX i = 0; i < handlers.GetSize(); i++)
415 handlers[i].AttachToAlerting(pdu);
416 }
417
418
AttachToConnect(H323SignalPDU & pdu)419 void H450xDispatcher::AttachToConnect(H323SignalPDU & pdu)
420 {
421 for (PINDEX i = 0; i < handlers.GetSize(); i++)
422 handlers[i].AttachToConnect(pdu);
423 }
424
425
AttachToReleaseComplete(H323SignalPDU & pdu)426 void H450xDispatcher::AttachToReleaseComplete(H323SignalPDU & pdu)
427 {
428 for (PINDEX i = 0; i < handlers.GetSize(); i++)
429 handlers[i].AttachToReleaseComplete(pdu);
430 }
431
432
HandlePDU(const H323SignalPDU & pdu)433 PBoolean H450xDispatcher::HandlePDU(const H323SignalPDU & pdu)
434 {
435 PBoolean result = TRUE;
436 for (PINDEX i = 0; i < pdu.m_h323_uu_pdu.m_h4501SupplementaryService.GetSize(); i++) {
437 H4501_SupplementaryService supplementaryService;
438
439 // Decode the supplementary service PDU from the PPER Stream
440 if (pdu.m_h323_uu_pdu.m_h4501SupplementaryService[i].DecodeSubType(supplementaryService)) {
441 PTRACE(4, "H4501\tReceived supplementary service PDU:\n "
442 << setprecision(2) << supplementaryService);
443 }
444 else {
445 PTRACE(1, "H4501\tInvalid supplementary service PDU decode:\n "
446 << setprecision(2) << supplementaryService);
447 continue;
448 }
449
450 H4501_InterpretationApdu & interpretation = supplementaryService.m_interpretationApdu;
451
452 if (supplementaryService.m_serviceApdu.GetTag() == H4501_ServiceApdus::e_rosApdus) {
453 H4501_ArrayOf_ROS& operations = (H4501_ArrayOf_ROS&) supplementaryService.m_serviceApdu;
454
455 for (PINDEX j = 0; j < operations.GetSize(); j ++) {
456 X880_ROS& operation = operations[j];
457
458 PTRACE(3, "H4501\tX880 ROS " << operation.GetTagName());
459
460 switch (operation.GetTag()) {
461 case X880_ROS::e_invoke:
462 result = OnReceivedInvoke((X880_Invoke &)operation, interpretation);
463 break;
464
465 case X880_ROS::e_returnResult:
466 result = OnReceivedReturnResult((X880_ReturnResult &)operation);
467 break;
468
469 case X880_ROS::e_returnError:
470 result = OnReceivedReturnError((X880_ReturnError &)operation);
471 break;
472
473 case X880_ROS::e_reject:
474 result = OnReceivedReject((X880_Reject &)operation);
475 break;
476
477 default :
478 break;
479 }
480 }
481 }
482 }
483 return result;
484 }
485
OnReceivedInvoke(X880_Invoke & invoke,H4501_InterpretationApdu & interpretation)486 PBoolean H450xDispatcher::OnReceivedInvoke(X880_Invoke & invoke, H4501_InterpretationApdu & interpretation)
487 {
488 PBoolean result = TRUE;
489 // Get the invokeId
490 int invokeId = invoke.m_invokeId.GetValue();
491
492 // Get the linkedId if present
493 int linkedId = -1;
494 if (invoke.HasOptionalField(X880_Invoke::e_linkedId)) {
495 linkedId = invoke.m_linkedId.GetValue();
496 }
497
498 // Get the argument if present
499 PASN_OctetString * argument = NULL;
500 if (invoke.HasOptionalField(X880_Invoke::e_argument)) {
501 argument = &invoke.m_argument;
502 }
503
504 // Get the opcode
505 if (invoke.m_opcode.GetTag() == X880_Code::e_local) {
506 int opcode = ((PASN_Integer&) invoke.m_opcode).GetValue();
507 if (!opcodeHandler.Contains(opcode)) {
508 PTRACE(2, "H4501\tInvoke of unsupported local opcode:\n " << invoke);
509 if (interpretation.GetTag() != H4501_InterpretationApdu::e_discardAnyUnrecognizedInvokePdu)
510 SendInvokeReject(invokeId, 1 /*X880_InvokeProblem::e_unrecognisedOperation*/);
511 if (interpretation.GetTag() == H4501_InterpretationApdu::e_clearCallIfAnyInvokePduNotRecognized)
512 result = FALSE;
513 }
514 else
515 result = opcodeHandler[opcode].OnReceivedInvoke(opcode, invokeId, linkedId, argument);
516 }
517 else {
518 if (interpretation.GetTag() != H4501_InterpretationApdu::e_discardAnyUnrecognizedInvokePdu)
519 SendInvokeReject(invokeId, 1 /*X880_InvokeProblem::e_unrecognisedOperation*/);
520 PTRACE(2, "H4501\tInvoke of unsupported global opcode:\n " << invoke);
521 if (interpretation.GetTag() == H4501_InterpretationApdu::e_clearCallIfAnyInvokePduNotRecognized)
522 result = FALSE;
523 }
524 return result;
525 }
526
527
OnReceivedReturnResult(X880_ReturnResult & returnResult)528 PBoolean H450xDispatcher::OnReceivedReturnResult(X880_ReturnResult & returnResult)
529 {
530 unsigned invokeId = returnResult.m_invokeId.GetValue();
531
532 for (PINDEX i = 0; i < handlers.GetSize(); i++) {
533 if (handlers[i].GetInvokeId() == invokeId) {
534 handlers[i].OnReceivedReturnResult(returnResult);
535 break;
536 }
537 }
538 return TRUE;
539 }
540
541
OnReceivedReturnError(X880_ReturnError & returnError)542 PBoolean H450xDispatcher::OnReceivedReturnError(X880_ReturnError & returnError)
543 {
544 PBoolean result=TRUE;
545 unsigned invokeId = returnError.m_invokeId.GetValue();
546 int errorCode = 0;
547
548 if (returnError.m_errorCode.GetTag() == X880_Code::e_local)
549 errorCode = ((PASN_Integer&) returnError.m_errorCode).GetValue();
550
551 for (PINDEX i = 0; i < handlers.GetSize(); i++) {
552 if (handlers[i].GetInvokeId() == invokeId) {
553 result = handlers[i].OnReceivedReturnError(errorCode, returnError);
554 break;
555 }
556 }
557 return result;
558 }
559
560
OnReceivedReject(X880_Reject & reject)561 PBoolean H450xDispatcher::OnReceivedReject(X880_Reject & reject)
562 {
563 int problem = 0;
564
565 switch (reject.m_problem.GetTag()) {
566 case X880_Reject_problem::e_general:
567 {
568 X880_GeneralProblem & generalProblem = reject.m_problem;
569 problem = generalProblem.GetValue();
570 }
571 break;
572
573 case X880_Reject_problem::e_invoke:
574 {
575 X880_InvokeProblem & invokeProblem = reject.m_problem;
576 problem = invokeProblem.GetValue();
577 }
578 break;
579
580 case X880_Reject_problem::e_returnResult:
581 {
582 X880_ReturnResultProblem & returnResultProblem = reject.m_problem;
583 problem = returnResultProblem.GetValue();
584 }
585 break;
586
587 case X880_Reject_problem::e_returnError:
588 {
589 X880_ReturnErrorProblem & returnErrorProblem = reject.m_problem;
590 problem = returnErrorProblem.GetValue();
591 }
592 break;
593
594 default:
595 break;
596 }
597
598
599 unsigned invokeId = reject.m_invokeId;
600 for (PINDEX i = 0; i < handlers.GetSize(); i++) {
601 if (handlers[i].GetInvokeId() == invokeId) {
602 handlers[i].OnReceivedReject(reject.m_problem.GetTag(), problem);
603 break;
604 }
605 }
606 return TRUE;
607 }
608
609
SendReturnError(int invokeId,int returnError)610 void H450xDispatcher::SendReturnError(int invokeId, int returnError)
611 {
612 H450ServiceAPDU serviceAPDU;
613
614 serviceAPDU.BuildReturnError(invokeId, returnError);
615
616 serviceAPDU.WriteFacilityPDU(connection);
617 }
618
619
SendGeneralReject(int invokeId,int problem)620 void H450xDispatcher::SendGeneralReject(int invokeId, int problem)
621 {
622 H450ServiceAPDU serviceAPDU;
623
624 X880_Reject & reject = serviceAPDU.BuildReject(invokeId);
625 reject.m_problem.SetTag(X880_Reject_problem::e_general);
626 X880_GeneralProblem & generalProblem = (X880_GeneralProblem &) reject.m_problem;
627 generalProblem = problem;
628
629 serviceAPDU.WriteFacilityPDU(connection);
630 }
631
632
SendInvokeReject(int invokeId,int problem)633 void H450xDispatcher::SendInvokeReject(int invokeId, int problem)
634 {
635 H450ServiceAPDU serviceAPDU;
636
637 X880_Reject & reject = serviceAPDU.BuildReject(invokeId);
638 reject.m_problem.SetTag(X880_Reject_problem::e_invoke);
639 X880_InvokeProblem & invokeProblem = (X880_InvokeProblem &) reject.m_problem;
640 invokeProblem = problem;
641
642 serviceAPDU.WriteFacilityPDU(connection);
643 }
644
645
SendReturnResultReject(int invokeId,int problem)646 void H450xDispatcher::SendReturnResultReject(int invokeId, int problem)
647 {
648 H450ServiceAPDU serviceAPDU;
649
650 X880_Reject & reject = serviceAPDU.BuildReject(invokeId);
651 reject.m_problem.SetTag(X880_Reject_problem::e_returnResult);
652 X880_ReturnResultProblem & returnResultProblem = reject.m_problem;
653 returnResultProblem = problem;
654
655 serviceAPDU.WriteFacilityPDU(connection);
656 }
657
658
SendReturnErrorReject(int invokeId,int problem)659 void H450xDispatcher::SendReturnErrorReject(int invokeId, int problem)
660 {
661 H450ServiceAPDU serviceAPDU;
662
663 X880_Reject & reject = serviceAPDU.BuildReject(invokeId);
664 reject.m_problem.SetTag(X880_Reject_problem::e_returnError);
665 X880_ReturnErrorProblem & returnErrorProblem = reject.m_problem;
666 returnErrorProblem = problem;
667
668 serviceAPDU.WriteFacilityPDU(connection);
669 }
670
671
672 /////////////////////////////////////////////////////////////////////////////
673
H450xHandler(H323Connection & conn,H450xDispatcher & disp)674 H450xHandler::H450xHandler(H323Connection & conn, H450xDispatcher & disp)
675 : endpoint(conn.GetEndPoint()),
676 connection(conn),
677 dispatcher(disp)
678 {
679 currentInvokeId = 0;
680 }
681
682
AttachToSetup(H323SignalPDU &)683 void H450xHandler::AttachToSetup(H323SignalPDU &)
684 {
685 }
686
687
AttachToAlerting(H323SignalPDU &)688 void H450xHandler::AttachToAlerting(H323SignalPDU &)
689 {
690 }
691
692
AttachToConnect(H323SignalPDU &)693 void H450xHandler::AttachToConnect(H323SignalPDU &)
694 {
695 }
696
697
AttachToReleaseComplete(H323SignalPDU &)698 void H450xHandler::AttachToReleaseComplete(H323SignalPDU &)
699 {
700 }
701
702
OnReceivedReturnResult(X880_ReturnResult &)703 PBoolean H450xHandler::OnReceivedReturnResult(X880_ReturnResult & /*returnResult*/)
704 {
705 return TRUE;
706 }
707
708
OnReceivedReturnError(int,X880_ReturnError &)709 PBoolean H450xHandler::OnReceivedReturnError(int /*errorCode*/,
710 X880_ReturnError & /*returnError*/)
711 {
712 return TRUE;
713 }
714
715
OnReceivedReject(int,int)716 PBoolean H450xHandler::OnReceivedReject(int /*problemType*/,
717 int /*problemNumber*/)
718 {
719 return TRUE;
720 }
721
722
SendReturnError(int returnError)723 void H450xHandler::SendReturnError(int returnError)
724 {
725 dispatcher.SendReturnError(currentInvokeId, returnError);
726 currentInvokeId = 0;
727 }
728
729
SendGeneralReject(int problem)730 void H450xHandler::SendGeneralReject(int problem)
731 {
732 dispatcher.SendGeneralReject(currentInvokeId, problem);
733 currentInvokeId = 0;
734 }
735
736
SendInvokeReject(int problem)737 void H450xHandler::SendInvokeReject(int problem)
738 {
739 dispatcher.SendInvokeReject(currentInvokeId, problem);
740 currentInvokeId = 0;
741 }
742
743
SendReturnResultReject(int problem)744 void H450xHandler::SendReturnResultReject(int problem)
745 {
746 dispatcher.SendReturnResultReject(currentInvokeId, problem);
747 currentInvokeId = 0;
748 }
749
750
SendReturnErrorReject(int problem)751 void H450xHandler::SendReturnErrorReject(int problem)
752 {
753 dispatcher.SendReturnErrorReject(currentInvokeId, problem);
754 currentInvokeId = 0;
755 }
756
757
DecodeArguments(PASN_OctetString * argString,PASN_Object & argObject,int absentErrorCode)758 PBoolean H450xHandler::DecodeArguments(PASN_OctetString * argString,
759 PASN_Object & argObject,
760 int absentErrorCode)
761 {
762 if (argString == NULL) {
763 if (absentErrorCode >= 0)
764 SendReturnError(absentErrorCode);
765 return FALSE;
766 }
767
768 PPER_Stream argStream(*argString);
769 if (argObject.Decode(argStream)) {
770 PTRACE(4, "H4501\tSupplementary service argument:\n "
771 << setprecision(2) << argObject);
772 return TRUE;
773 }
774
775 PTRACE(1, "H4501\tInvalid supplementary service argument:\n "
776 << setprecision(2) << argObject);
777 return FALSE;
778 }
779
780
781 /////////////////////////////////////////////////////////////////////////////
782
H4502Handler(H323Connection & conn,H450xDispatcher & disp)783 H4502Handler::H4502Handler(H323Connection & conn, H450xDispatcher & disp)
784 : H450xHandler(conn, disp)
785 {
786 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferIdentify, this);
787 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferAbandon, this);
788 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferInitiate, this);
789 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferSetup, this);
790 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferUpdate, this);
791 dispatcher.AddOpCode(H4502_CallTransferOperation::e_subaddressTransfer, this);
792 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferComplete, this);
793 dispatcher.AddOpCode(H4502_CallTransferOperation::e_callTransferActive, this);
794
795 transferringCallToken = "";
796 ctState = e_ctIdle;
797 ctResponseSent = FALSE;
798 CallToken = PString();
799 consultationTransfer = FALSE;
800
801 ctTimer.SetNotifier(PCREATE_NOTIFIER(OnCallTransferTimeOut));
802 }
803
804
AttachToSetup(H323SignalPDU & pdu)805 void H4502Handler::AttachToSetup(H323SignalPDU & pdu)
806 {
807 // Do we need to attach a call transfer setup invoke APDU?
808 if (ctState != e_ctAwaitSetupResponse)
809 return;
810
811 H450ServiceAPDU serviceAPDU;
812
813 // Store the outstanding invokeID associated with this connection
814 currentInvokeId = dispatcher.GetNextInvokeId();
815
816 // Use the call identity from the ctInitiateArg
817 serviceAPDU.BuildCallTransferSetup(currentInvokeId, transferringCallIdentity);
818
819 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
820 }
821
822
AttachToAlerting(H323SignalPDU & pdu)823 void H4502Handler::AttachToAlerting(H323SignalPDU & pdu)
824 {
825 // Do we need to send a callTransferSetup return result APDU?
826 if (currentInvokeId == 0 || ctResponseSent)
827 return;
828
829 H450ServiceAPDU serviceAPDU;
830 serviceAPDU.BuildReturnResult(currentInvokeId);
831 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
832 ctResponseSent = TRUE;
833 currentInvokeId = 0;
834 }
835
836
AttachToConnect(H323SignalPDU & pdu)837 void H4502Handler::AttachToConnect(H323SignalPDU & pdu)
838 {
839 // Do we need to include a ctInitiateReturnResult APDU in our Release Complete Message?
840 if (currentInvokeId == 0 || ctResponseSent)
841 return;
842
843 H450ServiceAPDU serviceAPDU;
844 serviceAPDU.BuildReturnResult(currentInvokeId);
845 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
846 ctResponseSent = TRUE;
847 currentInvokeId = 0;
848 }
849
850
AttachToReleaseComplete(H323SignalPDU & pdu)851 void H4502Handler::AttachToReleaseComplete(H323SignalPDU & pdu)
852 {
853 // Do we need to include a ctInitiateReturnResult APDU in our Release Complete Message?
854 if (currentInvokeId == 0)
855 return;
856
857 // If the SETUP message we received from the other end had a callTransferSetup APDU
858 // in it, then we need to send back a RELEASE COMPLETE PDU with a callTransferSetup
859 // ReturnError.
860 // Else normal call - clear it down
861 H450ServiceAPDU serviceAPDU;
862
863 if (ctResponseSent) {
864 serviceAPDU.BuildReturnResult(currentInvokeId);
865 ctResponseSent = FALSE;
866 currentInvokeId = 0;
867 }
868 else {
869 serviceAPDU.BuildReturnError(currentInvokeId, H4501_GeneralErrorList::e_notAvailable);
870 ctResponseSent = TRUE;
871 currentInvokeId = 0;
872 }
873
874 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
875 }
876
877
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString * argument)878 PBoolean H4502Handler::OnReceivedInvoke(int opcode,
879 int invokeId,
880 int linkedId,
881 PASN_OctetString * argument)
882 {
883 currentInvokeId = invokeId;
884
885 switch (opcode) {
886 case H4502_CallTransferOperation::e_callTransferIdentify:
887 OnReceivedCallTransferIdentify(linkedId);
888 break;
889
890 case H4502_CallTransferOperation::e_callTransferAbandon:
891 OnReceivedCallTransferAbandon(linkedId);
892 break;
893
894 case H4502_CallTransferOperation::e_callTransferInitiate:
895 OnReceivedCallTransferInitiate(linkedId, argument);
896 break;
897
898 case H4502_CallTransferOperation::e_callTransferSetup:
899 OnReceivedCallTransferSetup(linkedId, argument);
900 break;
901
902 case H4502_CallTransferOperation::e_callTransferUpdate:
903 OnReceivedCallTransferUpdate(linkedId, argument);
904 break;
905
906 case H4502_CallTransferOperation::e_subaddressTransfer:
907 OnReceivedSubaddressTransfer(linkedId, argument);
908 break;
909
910 case H4502_CallTransferOperation::e_callTransferComplete:
911 OnReceivedCallTransferComplete(linkedId, argument);
912 break;
913
914 case H4502_CallTransferOperation::e_callTransferActive:
915 OnReceivedCallTransferActive(linkedId, argument);
916 break;
917
918 default:
919 currentInvokeId = 0;
920 return FALSE;
921 }
922
923 return TRUE;
924 }
925
926
OnReceivedCallTransferIdentify(int)927 void H4502Handler::OnReceivedCallTransferIdentify(int /*linkedId*/)
928 {
929 if (!endpoint.OnCallTransferIdentify(connection)) {
930 SendReturnError(H4501_GeneralErrorList::e_notAvailable);
931 return;
932 }
933
934 // Send a FACILITY message with a callTransferIdentify return result
935 // Supplementary Service PDU to the transferring endpoint.
936 H450ServiceAPDU serviceAPDU;
937
938 X880_ReturnResult& result = serviceAPDU.BuildReturnResult(currentInvokeId);
939 result.IncludeOptionalField(X880_ReturnResult::e_result);
940 result.m_result.m_opcode.SetTag(X880_Code::e_local);
941 PASN_Integer& operation = (PASN_Integer&) result.m_result.m_opcode;
942 operation.SetValue(H4502_CallTransferOperation::e_callTransferIdentify);
943
944 H4502_CTIdentifyRes ctIdentifyResult;
945
946 // Restrict the generated value to 4 digits (13 bits)
947 unsigned int id = endpoint.GetNextH450CallIdentityValue() & 0x1FFF;
948 PString pstrId(PString::Unsigned, id);
949 ctIdentifyResult.m_callIdentity = pstrId;
950
951 // Store the callIdentity of this connection in the dictionary
952 endpoint.GetCallIdentityDictionary().SetAt(pstrId, &connection);
953
954 H4501_ArrayOf_AliasAddress& aliasAddress = ctIdentifyResult.m_reroutingNumber.m_destinationAddress;
955
956 PString localName = connection.GetLocalPartyName();
957 if (localName.IsEmpty())
958 aliasAddress.SetSize(1);
959 else {
960 aliasAddress.SetSize(2);
961 aliasAddress[1].SetTag(H225_AliasAddress::e_dialedDigits);
962 H323SetAliasAddress(localName, aliasAddress[1]); // Will encode as h323-Id if not E.164
963 }
964
965 H323TransportAddress address;
966 address = connection.GetSignallingChannel()->GetLocalAddress();
967
968 aliasAddress[0].SetTag(H225_AliasAddress::e_transportID);
969 H225_TransportAddress& cPartyTransport = (H225_TransportAddress&) aliasAddress[0];
970 address.SetPDU(cPartyTransport);
971
972 PPER_Stream resultStream;
973 ctIdentifyResult.Encode(resultStream);
974 resultStream.CompleteEncoding();
975 result.m_result.m_result.SetValue(resultStream);
976
977 serviceAPDU.WriteFacilityPDU(connection);
978
979 ctState = e_ctAwaitSetup;
980
981 // start timer CT-T2
982 PTRACE(4, "H450.2\tStarting timer CT-T2");
983 StartctTimer(endpoint.GetCallTransferT2());
984 }
985
986
OnReceivedCallTransferAbandon(int)987 void H4502Handler::OnReceivedCallTransferAbandon(int /*linkedId*/)
988 {
989 switch (ctState) {
990 case e_ctAwaitSetup:
991 {
992 // Stop Timer CT-T2 and enter state e_ctIdle
993 StopctTimer();
994 PTRACE(4, "H4502\tStopping timer CT-T2");
995
996 currentInvokeId = 0;
997 ctState = e_ctIdle;
998 }
999 break;
1000
1001 default:
1002 break;
1003 }
1004 }
1005
1006
OnReceivedCallTransferInitiate(int,PASN_OctetString * argument)1007 void H4502Handler::OnReceivedCallTransferInitiate(int /*linkedId*/,
1008 PASN_OctetString * argument)
1009 {
1010 // TBD: Check Call Hold status. If call is held, it must first be
1011 // retrieved before being transferred. -- dcassel 4/01
1012
1013 H4502_CTInitiateArg ctInitiateArg;
1014 if (!DecodeArguments(argument, ctInitiateArg,
1015 H4502_CallTransferErrors::e_invalidReroutingNumber))
1016 return;
1017
1018 ctResponseSent = TRUE;
1019
1020 PString remoteParty;
1021 H450ServiceAPDU::ParseEndpointAddress(ctInitiateArg.m_reroutingNumber, remoteParty);
1022
1023 PString newToken;
1024 if (!endpoint.OnCallTransferInitiate(connection, remoteParty) ||
1025 endpoint.SetupTransfer(connection.GetCallToken(),
1026 ctInitiateArg.m_callIdentity.GetValue(),
1027 remoteParty, newToken) == NULL)
1028 SendReturnError(H4502_CallTransferErrors::e_establishmentFailure);
1029 }
1030
1031
OnReceivedCallTransferSetup(int,PASN_OctetString * argument)1032 void H4502Handler::OnReceivedCallTransferSetup(int /*linkedId*/,
1033 PASN_OctetString * argument)
1034 {
1035 H4502_CTSetupArg ctSetupArg;
1036 if (!DecodeArguments(argument, ctSetupArg,
1037 H4502_CallTransferErrors::e_unrecognizedCallIdentity))
1038 return;
1039
1040 // Get the Transferring User's details if present
1041 PString transferringParty;
1042 if (ctSetupArg.HasOptionalField(H4502_CTSetupArg::e_transferringNumber)) {
1043 H450ServiceAPDU::ParseEndpointAddress(ctSetupArg.m_transferringNumber, transferringParty);
1044 }
1045
1046 PString callIdentity;
1047 callIdentity = ctSetupArg.m_callIdentity;
1048
1049 if (callIdentity.IsEmpty()) { // Blind Transfer
1050 switch (ctState) {
1051 case e_ctIdle:
1052 ctState = e_ctAwaitSetupResponse;
1053 break;
1054
1055 // Wrong State
1056 default :
1057 break;
1058 }
1059 }
1060 else { // Transfer through Consultation
1061
1062 // We need to check that the call identity and destination address information match those in the
1063 // second call. For the time being we just check that the call identities match as there does not
1064 // appear to be an elegant solution to compare the destination address information.
1065
1066 // Get this callIdentity from our dictionary (if present)
1067 H323Connection *secondaryCall = endpoint.GetCallIdentityDictionary().GetAt(callIdentity);
1068
1069 if (secondaryCall != NULL)
1070 secondaryCall->HandleConsultationTransfer(callIdentity, connection);
1071 else // Mismatched callIdentity
1072 SendReturnError(H4502_CallTransferErrors::e_unrecognizedCallIdentity);
1073 }
1074 }
1075
1076
OnReceivedCallTransferUpdate(int,PASN_OctetString * argument)1077 void H4502Handler::OnReceivedCallTransferUpdate(int /*linkedId*/,
1078 PASN_OctetString * argument)
1079 {
1080 H4502_CTUpdateArg ctUpdateArg;
1081 if (!DecodeArguments(argument, ctUpdateArg, -1))
1082 return;
1083
1084 }
1085
1086
OnReceivedSubaddressTransfer(int,PASN_OctetString * argument)1087 void H4502Handler::OnReceivedSubaddressTransfer(int /*linkedId*/,
1088 PASN_OctetString * argument)
1089 {
1090 H4502_SubaddressTransferArg subaddressTransferArg;
1091 if (!DecodeArguments(argument, subaddressTransferArg, -1))
1092 return;
1093
1094 }
1095
1096
OnReceivedCallTransferComplete(int,PASN_OctetString * argument)1097 void H4502Handler::OnReceivedCallTransferComplete(int /*linkedId*/,
1098 PASN_OctetString * argument)
1099 {
1100 H4502_CTCompleteArg ctCompleteArg;
1101 if (!DecodeArguments(argument, ctCompleteArg, -1))
1102 return;
1103
1104 }
1105
1106
OnReceivedCallTransferActive(int,PASN_OctetString * argument)1107 void H4502Handler::OnReceivedCallTransferActive(int /*linkedId*/,
1108 PASN_OctetString * argument)
1109 {
1110 H4502_CTActiveArg ctActiveArg;
1111 if (!DecodeArguments(argument, ctActiveArg, -1))
1112 return;
1113
1114 }
1115
1116
OnReceivedReturnResult(X880_ReturnResult & returnResult)1117 PBoolean H4502Handler::OnReceivedReturnResult(X880_ReturnResult & returnResult)
1118 {
1119 if (currentInvokeId == returnResult.m_invokeId.GetValue()) {
1120 switch (ctState) {
1121 case e_ctAwaitInitiateResponse:
1122 OnReceivedInitiateReturnResult();
1123 break;
1124
1125 case e_ctAwaitSetupResponse:
1126 OnReceivedSetupReturnResult();
1127 break;
1128
1129 case e_ctAwaitIdentifyResponse:
1130 OnReceivedIdentifyReturnResult(returnResult);
1131 break;
1132
1133 default :
1134 break;
1135 }
1136 }
1137 return TRUE;
1138 }
1139
1140
OnReceivedInitiateReturnResult()1141 void H4502Handler::OnReceivedInitiateReturnResult()
1142 {
1143 // stop timer CT-T3
1144 StopctTimer();
1145 PTRACE(4, "H4502\tStopping timer CT-T3");
1146 ctState = e_ctIdle;
1147 currentInvokeId = 0;
1148
1149 // clear the primary and secondary call if not already cleared,
1150 }
1151
1152
OnReceivedSetupReturnResult()1153 void H4502Handler::OnReceivedSetupReturnResult()
1154 {
1155 // stop timer CT-T4
1156 StopctTimer();
1157 PTRACE(4, "H4502\tStopping timer CT-T4");
1158 ctState = e_ctIdle;
1159 currentInvokeId = 0;
1160
1161 // Clear the primary call
1162 endpoint.ClearCall(transferringCallToken, H323Connection::EndedByCallForwarded);
1163 }
1164
1165
OnReceivedIdentifyReturnResult(X880_ReturnResult & returnResult)1166 void H4502Handler::OnReceivedIdentifyReturnResult(X880_ReturnResult &returnResult)
1167 {
1168 // stop timer CT-T1
1169 StopctTimer();
1170 PTRACE(4, "H4502\tStopping timer CT-T1");
1171
1172 // Have received response.
1173 ctState = e_ctIdle;
1174
1175 // Get the return result if present
1176 PASN_OctetString * result = NULL;
1177 if (returnResult.HasOptionalField(X880_ReturnResult::e_result)) {
1178 result = &returnResult.m_result.m_result;
1179
1180 // Extract the C Party Details
1181 H4502_CTIdentifyRes ctIdentifyResult;
1182
1183 PPER_Stream resultStream(*result);
1184 ctIdentifyResult.Decode(resultStream);
1185 PString callIdentity = ctIdentifyResult.m_callIdentity.GetValue();
1186
1187 PString remoteParty;
1188 H450ServiceAPDU::ParseEndpointAddress(ctIdentifyResult.m_reroutingNumber, remoteParty);
1189
1190 // Store the secondary call token on the primary connection so we can send a
1191 // callTransferAbandon invoke APDU on the secondary call at a later stage if we
1192 // get back a callTransferInitiateReturnError
1193 H323Connection* primaryConnection = endpoint.FindConnectionWithLock(CallToken);
1194 if (primaryConnection != NULL) {
1195 primaryConnection->SetAssociatedCallToken(connection.GetCallToken());
1196
1197 // Send a callTransferInitiate invoke APDU in a FACILITY message
1198 // to the transferred endpoint on the primary call
1199 endpoint.TransferCall(primaryConnection->GetCallToken(), remoteParty, callIdentity);
1200
1201 primaryConnection->Unlock();
1202 }
1203 }
1204 }
1205
1206
OnReceivedReturnError(int errorCode,X880_ReturnError & returnError)1207 PBoolean H4502Handler::OnReceivedReturnError(int errorCode, X880_ReturnError &returnError)
1208 {
1209 if (currentInvokeId == returnError.m_invokeId.GetValue()) {
1210 switch (ctState) {
1211 case e_ctAwaitInitiateResponse:
1212 OnReceivedInitiateReturnError();
1213 break;
1214
1215 case e_ctAwaitSetupResponse:
1216 OnReceivedSetupReturnError(errorCode);
1217 break;
1218
1219 case e_ctAwaitIdentifyResponse:
1220 OnReceivedIdentifyReturnError();
1221 break;
1222
1223 default :
1224 break;
1225 }
1226 }
1227 return TRUE;
1228 }
1229
1230
OnReceivedInitiateReturnError(const bool timerExpiry)1231 void H4502Handler::OnReceivedInitiateReturnError(const bool timerExpiry)
1232 {
1233 if (!timerExpiry) {
1234 // stop timer CT-T3
1235 StopctTimer();
1236 PTRACE(4, "H4502\tStopping timer CT-T3 on Error");
1237 }
1238 else
1239 PTRACE(4, "H4502\tTimer CT-T3 has expired on the Transferring Endpoint awaiting a response to a callTransferInitiate APDU.");
1240
1241 currentInvokeId = 0;
1242 ctState = e_ctIdle;
1243
1244
1245 // Send a callTransferAbandon invoke APDU in a FACILITY message on the secondary call
1246 // (if it exists) and enter state CT-Idle.
1247 H323Connection* secondaryConnection = endpoint.FindConnectionWithLock(CallToken);
1248
1249 if (secondaryConnection != NULL) {
1250 H450ServiceAPDU serviceAPDU;
1251
1252 serviceAPDU.BuildCallTransferAbandon(dispatcher.GetNextInvokeId());
1253 serviceAPDU.WriteFacilityPDU(*secondaryConnection);
1254 secondaryConnection->Unlock();
1255 }
1256
1257 if (!transferringCallToken) {
1258 H323Connection* primaryConnection = endpoint.FindConnectionWithLock(transferringCallToken);
1259 primaryConnection->OnReceivedInitiateReturnError();
1260 primaryConnection->Unlock();
1261 } else {
1262 endpoint.OnReceivedInitiateReturnError();
1263 }
1264 }
1265
1266
OnReceivedSetupReturnError(int errorCode,const bool timerExpiry)1267 void H4502Handler::OnReceivedSetupReturnError(int errorCode,
1268 const bool timerExpiry)
1269 {
1270 ctState = e_ctIdle;
1271 currentInvokeId = 0;
1272
1273 if (!timerExpiry) {
1274 // stop timer CT-T4 if it is running
1275 StopctTimer();
1276 PTRACE(4, "H4502\tStopping timer CT-T4");
1277 }
1278 else {
1279 PTRACE(3, "H4502\tTimer CT-T4 has expired on the Transferred Endpoint awaiting a response to a callTransferSetup APDU.");
1280
1281 // Clear the transferred call.
1282 endpoint.ClearCall(connection.GetCallToken());
1283 }
1284
1285 // Send a facility message to the transferring endpoint
1286 // containing a call transfer initiate return error
1287 H323Connection* primaryConnection = endpoint.FindConnectionWithLock(transferringCallToken);
1288
1289 if (primaryConnection != NULL) {
1290 primaryConnection->HandleCallTransferFailure(errorCode);
1291 primaryConnection->Unlock();
1292 }
1293 }
1294
1295
OnReceivedIdentifyReturnError(const bool timerExpiry)1296 void H4502Handler::OnReceivedIdentifyReturnError(const bool timerExpiry)
1297 {
1298 // The transferred-to user cannot participate in our transfer request
1299 ctState = e_ctIdle;
1300 currentInvokeId = 0;
1301
1302 if (!timerExpiry) {
1303 // stop timer CT-T1
1304 StopctTimer();
1305 PTRACE(4, "H4502\tStopping timer CT-T1");
1306 }
1307 else {
1308 PTRACE(4, "H4502\tTimer CT-T1 has expired on the Transferring Endpoint awaiting a response to a callTransferIdentify APDU.");
1309
1310 // send a callTransferAbandon invoke APDU in a FACILITY message on the secondary call
1311 // and enter state CT-Idle.
1312 connection.Lock();
1313
1314 H450ServiceAPDU serviceAPDU;
1315
1316 serviceAPDU.BuildCallTransferAbandon(dispatcher.GetNextInvokeId());
1317 serviceAPDU.WriteFacilityPDU(connection);
1318
1319 connection.Unlock();
1320 }
1321 }
1322
TransferCall(const PString & remoteParty,const PString & callIdentity)1323 void H4502Handler::TransferCall(const PString & remoteParty,
1324 const PString & callIdentity)
1325 {
1326 currentInvokeId = dispatcher.GetNextInvokeId();
1327
1328 // Send a FACILITY message with a callTransferInitiate Invoke
1329 // Supplementary Service PDU to the transferred endpoint.
1330 H450ServiceAPDU serviceAPDU;
1331
1332 PString alias;
1333 H323TransportAddress address;
1334
1335 PStringList Addresses;
1336 if (!endpoint.ResolveCallParty(remoteParty, Addresses) || (Addresses.GetSize() == 0)) {
1337 PTRACE(1, "H4502\tCould not resolve call party " << remoteParty);
1338 return;
1339 }
1340
1341 if (!endpoint.ParsePartyName(Addresses[0], alias, address)) {
1342 PTRACE(1, "H4502\tCould not resolve transfer party address " << remoteParty);
1343 return;
1344 }
1345
1346 serviceAPDU.BuildCallTransferInitiate(currentInvokeId, callIdentity, alias, address);
1347 serviceAPDU.WriteFacilityPDU(connection);
1348
1349 ctState = e_ctAwaitInitiateResponse;
1350
1351 // start timer CT-T3
1352 PTRACE(4, "H4502\tStarting timer CT-T3");
1353 StartctTimer(connection.GetEndPoint().GetCallTransferT3());
1354 }
1355
1356
ConsultationTransfer(const PString & primaryCallToken)1357 void H4502Handler::ConsultationTransfer(const PString & primaryCallToken)
1358 {
1359 currentInvokeId = dispatcher.GetNextInvokeId();
1360
1361 // Store the call token of the primary call on the secondary call.
1362 SetAssociatedCallToken(primaryCallToken);
1363
1364 // Send a FACILITY message with a callTransferIdentify Invoke
1365 // Supplementary Service PDU to the transferred-to endpoint.
1366 H450ServiceAPDU serviceAPDU;
1367
1368 serviceAPDU.BuildCallTransferIdentify(currentInvokeId);
1369 serviceAPDU.WriteFacilityPDU(connection);
1370
1371 ctState = e_ctAwaitIdentifyResponse;
1372
1373 // start timer CT-T1
1374 PTRACE(4, "H4502\tStarting timer CT-T1");
1375 StartctTimer(endpoint.GetCallTransferT1());
1376 }
1377
1378
HandleConsultationTransfer(const PString & callIdentity,H323Connection & incoming)1379 void H4502Handler::HandleConsultationTransfer(const PString & callIdentity,
1380 H323Connection& incoming)
1381 {
1382 switch (ctState) {
1383 case e_ctAwaitSetup:
1384 {
1385 // Remove this callIdentity, connection pair from our dictionary as we no longer need it
1386 endpoint.GetCallIdentityDictionary().RemoveAt(callIdentity);
1387
1388 // Stop timer CT-T2
1389 StopctTimer();
1390 PTRACE(4, "H4502\tStopping timer CT-T2");
1391
1392 PTRACE(4, "H450.2\tConsultation Transfer successful, clearing secondary call");
1393
1394 incoming.OnConsultationTransferSuccess(connection);
1395
1396 currentInvokeId = 0;
1397 ctState = e_ctIdle;
1398
1399 endpoint.ClearCall(connection.GetCallToken());
1400 }
1401 break;
1402
1403 // Wrong Call Transfer State
1404 default :
1405 break;
1406
1407 }
1408 }
1409
1410
AwaitSetupResponse(const PString & token,const PString & identity)1411 void H4502Handler::AwaitSetupResponse(const PString & token,
1412 const PString & identity)
1413 {
1414 transferringCallToken = token;
1415 transferringCallIdentity = identity;
1416 ctState = e_ctAwaitSetupResponse;
1417
1418 // start timer CT-T4
1419 PTRACE(4, "H450.2\tStarting timer CT-T4");
1420 StartctTimer(connection.GetEndPoint().GetCallTransferT4());
1421 }
1422
1423
onReceivedAdmissionReject(const int returnError)1424 void H4502Handler::onReceivedAdmissionReject(const int returnError)
1425 {
1426 if (ctState == e_ctAwaitSetupResponse) {
1427 ctState = e_ctIdle;
1428
1429 // Stop timer CT-T4 if it is running
1430 StopctTimer();
1431 PTRACE(3, "H4502\tStopping timer CT-T4");
1432
1433 // Send a FACILITY message back to the transferring party on the primary connection
1434 H323Connection * primaryConnection = endpoint.FindConnectionWithLock(transferringCallToken);
1435
1436 if (primaryConnection != NULL) {
1437 PTRACE(3, "H4502\tReceived an Admission Reject at the Transferred Endpoint - aborting the transfer.");
1438 primaryConnection->HandleCallTransferFailure(returnError);
1439 primaryConnection->Unlock();
1440 }
1441 }
1442 }
1443
1444
HandleCallTransferFailure(const int returnError)1445 void H4502Handler::HandleCallTransferFailure(const int returnError)
1446 {
1447 SendReturnError(returnError);
1448 }
1449
1450
StopctTimer()1451 void H4502Handler::StopctTimer()
1452 {
1453 if (ctTimer.IsRunning())
1454 ctTimer.Stop();
1455 }
1456
1457
OnCallTransferTimeOut(PTimer &,H323_INT)1458 void H4502Handler::OnCallTransferTimeOut(PTimer &, H323_INT)
1459 {
1460 switch (ctState) {
1461 // CT-T3 Timeout
1462 case e_ctAwaitInitiateResponse:
1463 OnReceivedInitiateReturnError(true);
1464 break;
1465
1466 // CT-T1 Timeout
1467 case e_ctAwaitIdentifyResponse:
1468 OnReceivedIdentifyReturnError(true);
1469 break;
1470
1471 // CT-T2 Timeout
1472 case e_ctAwaitSetup:
1473 {
1474 // Abort the call transfer
1475 ctState = e_ctIdle;
1476 currentInvokeId = 0;
1477 PTRACE(4, "H450.2\tTimer CT-T2 has expired on the Transferred-to endpoint awaiting a callTransferSetup APDU.");
1478 }
1479 break;
1480
1481 // CT-T4 Timeout
1482 case e_ctAwaitSetupResponse:
1483 OnReceivedSetupReturnError(H4502_CallTransferErrors::e_establishmentFailure, true);
1484 break;
1485
1486 default:
1487 break;
1488 }
1489 }
1490
1491 /////////////////////////////////////////////////////////////////////////////
1492
H4503Handler(H323Connection & conn,H450xDispatcher & disp)1493 H4503Handler::H4503Handler(H323Connection & conn, H450xDispatcher & disp)
1494 : H450xHandler(conn, disp), m_diversionCounter(0), m_origdiversionReason(0), m_diversionReason(0)
1495 {
1496 dispatcher.AddOpCode(H4503_H323CallDiversionOperations::e_divertingLegInformation2, this);
1497
1498 }
1499
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString * argument)1500 PBoolean H4503Handler::OnReceivedInvoke(int opcode,
1501 int invokeId,
1502 int linkedId,
1503 PASN_OctetString *argument)
1504 {
1505 currentInvokeId = invokeId;
1506 switch (opcode) {
1507 case H4503_H323CallDiversionOperations::e_divertingLegInformation2:
1508 OnReceivedDivertingLegInfo2(linkedId, argument);
1509 break;
1510
1511 default:
1512 currentInvokeId = 0;
1513 return FALSE;
1514 }
1515
1516 return TRUE;
1517 }
1518
OnReceivedDivertingLegInfo2(int,PASN_OctetString * argument)1519 void H4503Handler::OnReceivedDivertingLegInfo2(int /* linkedId*/, PASN_OctetString * argument)
1520 {
1521 PTRACE(4, "H4503\tReceived a DivertingLegInfo2 Invoke APDU from the remote endpoint.");
1522 H4503_DivertingLegInfo2Arg divertingLegInfo2Arg;
1523 if (!DecodeArguments(argument, divertingLegInfo2Arg, -1))
1524 return;
1525
1526 if(divertingLegInfo2Arg.HasOptionalField(H4503_DivertingLegInfo2Arg::e_originalCalledNr)) {
1527 //m_originalCalledNr = divertingLegInfo2Arg.m_originalCalledNr.GetTypeAsString();
1528 H450ServiceAPDU::ParseEndpointAddress(divertingLegInfo2Arg.m_originalCalledNr, m_originalCalledNr);
1529 }
1530
1531 if(divertingLegInfo2Arg.HasOptionalField(H4503_DivertingLegInfo2Arg::e_divertingNr))
1532 m_lastDivertingNr = divertingLegInfo2Arg.m_divertingNr.GetTypeAsString();
1533
1534 m_diversionCounter = divertingLegInfo2Arg.m_diversionCounter.GetValue();
1535 m_diversionReason = divertingLegInfo2Arg.m_diversionReason.GetValue();
1536
1537 PTRACE(4, "H450.3\tOnReceivedDivertingLegInfo2 redirNUm=" << m_originalCalledNr);
1538
1539
1540 }
1541
GetRedirectingNumber(PString & originalCalledNr,PString & lastDivertingNr,int & divCounter,int & origdivReason,int & divReason)1542 PBoolean H4503Handler::GetRedirectingNumber(PString &originalCalledNr, PString &lastDivertingNr, int &divCounter, int &origdivReason, int &divReason)
1543 {
1544 PBoolean bRedirAvail=false;
1545
1546 if(!m_originalCalledNr.IsEmpty()) {
1547 originalCalledNr = m_originalCalledNr;
1548 bRedirAvail = true;
1549 }
1550 if(!m_lastDivertingNr.IsEmpty()) {
1551 lastDivertingNr = m_lastDivertingNr;
1552 bRedirAvail = true;
1553 }
1554
1555 divCounter = m_diversionCounter;
1556 divReason = m_diversionReason;
1557 origdivReason = m_origdiversionReason;
1558
1559 return bRedirAvail;
1560
1561 }
1562
1563
1564 /////////////////////////////////////////////////////////////////////////////
1565
H4504Handler(H323Connection & conn,H450xDispatcher & disp)1566 H4504Handler::H4504Handler(H323Connection & conn, H450xDispatcher & disp)
1567 : H450xHandler(conn, disp)
1568 {
1569 dispatcher.AddOpCode(H4504_CallHoldOperation::e_holdNotific, this);
1570 dispatcher.AddOpCode(H4504_CallHoldOperation::e_retrieveNotific, this);
1571 dispatcher.AddOpCode(H4504_CallHoldOperation::e_remoteHold, this);
1572 dispatcher.AddOpCode(H4504_CallHoldOperation::e_remoteRetrieve, this);
1573
1574 holdState = e_ch_Idle;
1575 }
1576
1577
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString *)1578 PBoolean H4504Handler::OnReceivedInvoke(int opcode,
1579 int invokeId,
1580 int linkedId,
1581 PASN_OctetString *)
1582 {
1583 currentInvokeId = invokeId;
1584
1585 switch (opcode) {
1586 case H4504_CallHoldOperation::e_holdNotific:
1587 OnReceivedLocalCallHold(linkedId);
1588 break;
1589
1590 case H4504_CallHoldOperation::e_retrieveNotific:
1591 OnReceivedLocalCallRetrieve(linkedId);
1592 break;
1593
1594 case H4504_CallHoldOperation::e_remoteHold:
1595 OnReceivedRemoteCallHold(linkedId);
1596 break;
1597
1598 case H4504_CallHoldOperation::e_remoteRetrieve:
1599 OnReceivedRemoteCallRetrieve(linkedId);
1600 break;
1601
1602 default:
1603 currentInvokeId = 0;
1604 return FALSE;
1605 }
1606
1607 return TRUE;
1608 }
1609
1610
OnReceivedLocalCallHold(int)1611 void H4504Handler::OnReceivedLocalCallHold(int /*linkedId*/)
1612 {
1613 PTRACE(4, "H4504\tReceived a holdNotific Invoke APDU from the remote endpoint.");
1614 // Optionally close our transmit channel.
1615 }
1616
1617
OnReceivedLocalCallRetrieve(int)1618 void H4504Handler::OnReceivedLocalCallRetrieve(int /*linkedId*/)
1619 {
1620 PTRACE(4, "H4504\tReceived a retrieveNotific Invoke APDU from the remote endpoint.");
1621 // Re-open our transmit channel if we previously closed it.
1622 }
1623
1624
OnReceivedRemoteCallHold(int)1625 void H4504Handler::OnReceivedRemoteCallHold(int /*linkedId*/)
1626 {
1627 // TBD
1628 }
1629
1630
OnReceivedRemoteCallRetrieve(int)1631 void H4504Handler::OnReceivedRemoteCallRetrieve(int /*linkedId*/)
1632 {
1633 // TBD
1634 }
1635
1636
HoldCall(PBoolean localHold)1637 void H4504Handler::HoldCall(PBoolean localHold)
1638 {
1639 // TBD: Implement Remote Hold. This implementation only does
1640 // local hold. -- dcassel 4/01.
1641 if (!localHold)
1642 return;
1643
1644 // Send a FACILITY message with a callNotific Invoke
1645 // Supplementary Service PDU to the held endpoint.
1646 PTRACE(4, "H4504\tTransmitting a holdNotific Invoke APDU to the remote endpoint.");
1647
1648 H450ServiceAPDU serviceAPDU;
1649
1650 currentInvokeId = dispatcher.GetNextInvokeId();
1651 serviceAPDU.BuildInvoke(currentInvokeId, H4504_CallHoldOperation::e_holdNotific);
1652 serviceAPDU.WriteFacilityPDU(connection);
1653
1654 // Update hold state
1655 holdState = e_ch_NE_Held;
1656 }
1657
1658
RetrieveCall()1659 void H4504Handler::RetrieveCall()
1660 {
1661 // TBD: Implement Remote Hold. This implementation only does
1662
1663 // Send a FACILITY message with a retrieveNotific Invoke
1664 // Supplementary Service PDU to the held endpoint.
1665 PTRACE(4, "H4504\tTransmitting a retrieveNotific Invoke APDU to the remote endpoint.");
1666
1667 H450ServiceAPDU serviceAPDU;
1668
1669 currentInvokeId = dispatcher.GetNextInvokeId();
1670 serviceAPDU.BuildInvoke(currentInvokeId, H4504_CallHoldOperation::e_retrieveNotific);
1671 serviceAPDU.WriteFacilityPDU(connection);
1672
1673 // Update hold state
1674 holdState = e_ch_Idle;
1675 }
1676
1677
1678 /////////////////////////////////////////////////////////////////////////////
1679
H4506Handler(H323Connection & conn,H450xDispatcher & disp)1680 H4506Handler::H4506Handler(H323Connection & conn, H450xDispatcher & disp)
1681 : H450xHandler(conn, disp)
1682 {
1683 dispatcher.AddOpCode(H4506_CallWaitingOperations::e_callWaiting, this);
1684
1685 cwState = e_cw_Idle;
1686 }
1687
1688
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString * argument)1689 PBoolean H4506Handler::OnReceivedInvoke(int opcode,
1690 int invokeId,
1691 int linkedId,
1692 PASN_OctetString *argument)
1693 {
1694 currentInvokeId = invokeId;
1695
1696 switch (opcode) {
1697 case H4506_CallWaitingOperations::e_callWaiting:
1698 OnReceivedCallWaitingIndication(linkedId, argument);
1699 break;
1700
1701 default:
1702 currentInvokeId = 0;
1703 return FALSE;
1704 }
1705
1706 return TRUE;
1707 }
1708
1709
OnReceivedCallWaitingIndication(int,PASN_OctetString * argument)1710 void H4506Handler::OnReceivedCallWaitingIndication(int /*linkedId*/,
1711 PASN_OctetString *argument)
1712 {
1713 H4506_CallWaitingArg cwArg;
1714
1715 if(!DecodeArguments(argument, cwArg, -1))
1716 return;
1717
1718 connection.SetRemoteCallWaiting(cwArg.m_nbOfAddWaitingCalls.GetValue());
1719 return;
1720 }
1721
1722
AttachToAlerting(H323SignalPDU & pdu,unsigned numberOfCallsWaiting)1723 void H4506Handler::AttachToAlerting(H323SignalPDU & pdu,
1724 unsigned numberOfCallsWaiting)
1725 {
1726 PTRACE(4, "H450.6\tAttaching a Call Waiting Invoke PDU to this Alerting message.");
1727
1728 H450ServiceAPDU serviceAPDU;
1729
1730 // Store the call waiting invokeID associated with this connection
1731 currentInvokeId = dispatcher.GetNextInvokeId();
1732
1733 serviceAPDU.BuildCallWaiting(currentInvokeId, numberOfCallsWaiting);
1734 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
1735
1736 cwState = e_cw_Invoked;
1737 }
1738
1739
1740 /////////////////////////////////////////////////////////////////////////////
1741
1742 // MWI functions
1743
BuildMWIActivate(H4507_MWIActivateArg & argument,const H323Connection::MWIInformation & mwiInfo)1744 void BuildMWIActivate(H4507_MWIActivateArg & argument, const H323Connection::MWIInformation & mwiInfo)
1745 {
1746 H4501_ArrayOf_AliasAddress & user = argument.m_servedUserNr.m_destinationAddress;
1747 user.SetSize(1);
1748 H323SetAliasAddress(mwiInfo.mwiUser,user[0]);
1749
1750 argument.m_basicService = H4507_BasicService::e_unrestrictedDigitalInformation;
1751
1752 if (!mwiInfo.mwiCtrId) {
1753 argument.IncludeOptionalField(H4507_MWIActivateArg::e_msgCentreId);
1754 argument.m_msgCentreId.SetTag(H4507_MsgCentreId::e_partyNumber);
1755 H225_AliasAddress & msgId = (H225_AliasAddress &)argument.m_msgCentreId;
1756 H323SetAliasAddress(mwiInfo.mwiCtrId, msgId);
1757 }
1758
1759 if (mwiInfo.mwiCalls > 0) {
1760 argument.IncludeOptionalField(H4507_MWIActivateArg::e_nbOfMessages);
1761 argument.m_nbOfMessages = mwiInfo.mwiCalls;
1762 }
1763
1764 // TODO Add message details here.
1765 }
1766
BuildMWIDeactivate(H4507_MWIDeactivateArg & argument,const H323Connection::MWIInformation & mwiInfo)1767 void BuildMWIDeactivate(H4507_MWIDeactivateArg & argument, const H323Connection::MWIInformation & mwiInfo)
1768 {
1769 H4501_ArrayOf_AliasAddress & user = argument.m_servedUserNr.m_destinationAddress;
1770 user.SetSize(1);
1771 H323SetAliasAddress(mwiInfo.mwiUser,user[0]);
1772
1773 argument.m_basicService = H4507_BasicService::e_unrestrictedDigitalInformation;
1774 }
1775
BuildMWIInterrogate(H4507_MWIInterrogateArg & argument,const H323Connection::MWIInformation & mwiInfo)1776 void BuildMWIInterrogate(H4507_MWIInterrogateArg & argument, const H323Connection::MWIInformation & mwiInfo)
1777 {
1778 H4501_ArrayOf_AliasAddress & user = argument.m_servedUserNr.m_destinationAddress;
1779 user.SetSize(1);
1780 H323SetAliasAddress(mwiInfo.mwiUser,user[0]);
1781
1782 argument.m_basicService = H4507_BasicService::e_unrestrictedDigitalInformation;
1783 }
1784
1785
BuildMWIInterrogateResult(H4507_MWIInterrogateRes & response,const H323Connection::MWIInformation & mwiInfo)1786 void BuildMWIInterrogateResult(H4507_MWIInterrogateRes & response, const H323Connection::MWIInformation & mwiInfo)
1787 {
1788 response.SetSize(1);
1789 H4507_MWIInterrogateResElt & argument = response[0];
1790 argument.m_basicService = H4507_BasicService::e_unrestrictedDigitalInformation;
1791
1792 if (!mwiInfo.mwiCtrId) {
1793 argument.IncludeOptionalField(H4507_MWIInterrogateResElt::e_msgCentreId);
1794 argument.m_msgCentreId.SetTag(H4507_MsgCentreId::e_partyNumber);
1795 H225_AliasAddress & msgId = (H225_AliasAddress &)argument.m_msgCentreId;
1796 H323SetAliasAddress(mwiInfo.mwiCtrId, msgId);
1797 }
1798
1799 if (mwiInfo.mwiCalls > 0) {
1800 argument.IncludeOptionalField(H4507_MWIInterrogateResElt::e_nbOfMessages);
1801 argument.m_nbOfMessages = mwiInfo.mwiCalls;
1802 }
1803
1804 // TODO Add message details here.
1805 }
1806
1807 ///////////////////////////////////////////////////////////////////////////////
1808
1809
H4507Handler(H323Connection & conn,H450xDispatcher & disp)1810 H4507Handler::H4507Handler(H323Connection & conn, H450xDispatcher & disp)
1811 : H450xHandler(conn, disp)
1812 {
1813
1814 dispatcher.AddOpCode(H4507_H323_MWI_Operations::e_mwiActivate, this);
1815 dispatcher.AddOpCode(H4507_H323_MWI_Operations::e_mwiDeactivate, this);
1816 dispatcher.AddOpCode(H4507_H323_MWI_Operations::e_mwiInterrogate, this);
1817
1818 mwiState = e_mwi_Idle; // default value;
1819 mwiType = e_mwi_typeNone; // default value;
1820 mwiTimer.SetNotifier(PCREATE_NOTIFIER(OnMWITimeOut));
1821
1822 }
1823
AttachToSetup(H323SignalPDU & pdu)1824 void H4507Handler::AttachToSetup(H323SignalPDU & pdu)
1825 {
1826 // Is a non call Supplementary Service
1827 if (!connection.IsNonCallConnection())
1828 return;
1829
1830 // Do we need to attach a MWI APDU?
1831 H323Connection::MWIInformation mwiInfo;
1832 mwiInfo = connection.GetMWINonCallParameters();
1833
1834 mwiType = (Type)mwiInfo.mwitype;
1835 if (mwiType == e_mwi_typeNone)
1836 return;
1837
1838 H450ServiceAPDU serviceAPDU;
1839
1840 // Store the outstanding invokeID associated with this connection
1841 currentInvokeId = dispatcher.GetNextInvokeId();
1842
1843 switch (mwiType) {
1844 case e_mwi_typeNone:
1845 // ignore
1846 break;
1847 case e_mwi_activate:
1848 {
1849 X880_Invoke & invoke = serviceAPDU.BuildMessageWaitIndicationActivate(currentInvokeId);
1850 H4507_MWIActivateArg arg;
1851 BuildMWIActivate(arg, mwiInfo);
1852 PTRACE(6,"H4507\tActivate Invoke\n" << arg);
1853 invoke.m_argument.EncodeSubType(arg);
1854 }
1855 break;
1856 case e_mwi_deactivate:
1857 {
1858 X880_Invoke & invoke = serviceAPDU.BuildMessageWaitIndicationDeactivate(currentInvokeId);
1859 H4507_MWIDeactivateArg arg;
1860 BuildMWIDeactivate(arg, mwiInfo);
1861 PTRACE(6,"H4507\tDectivate Invoke\n" << arg);
1862 invoke.m_argument.EncodeSubType(arg);
1863 }
1864 break;
1865 case e_mwi_interrogate:
1866 {
1867 X880_Invoke & invoke = serviceAPDU.BuildMessageWaitIndicationInterrogate(currentInvokeId);
1868 H4507_MWIInterrogateArg arg;
1869 BuildMWIInterrogate(arg, mwiInfo);
1870 PTRACE(6,"H4507\tInterrogate Invoke\n" << arg);
1871 invoke.m_argument.EncodeSubType(arg);
1872 }
1873 break;
1874 }
1875 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
1876
1877 mwiState = e_mwi_Wait;
1878 }
1879
AttachToConnect(H323SignalPDU & pdu)1880 void H4507Handler::AttachToConnect(H323SignalPDU & pdu)
1881 {
1882 // Is a non call Supplementary Service
1883 if (!connection.IsNonCallConnection())
1884 return;
1885
1886 // Do we need to attach a MWI APDU?
1887 if (mwiState != e_mwi_Wait)
1888 return;
1889
1890 H450ServiceAPDU serviceAPDU;
1891 PPER_Stream resultStream;
1892
1893 H323Connection::MWIInformation mwiInfo;
1894 mwiInfo = connection.GetMWINonCallParameters();
1895
1896 switch (mwiType) {
1897 case e_mwi_typeNone:
1898 // ignore
1899 case e_mwi_activate:
1900 serviceAPDU.BuildMessageWaitIndicationResult(currentInvokeId, H4507_H323_MWI_Operations::e_mwiActivate);
1901 break;
1902 case e_mwi_deactivate:
1903 serviceAPDU.BuildMessageWaitIndicationResult(currentInvokeId, H4507_H323_MWI_Operations::e_mwiDeactivate);
1904 break;
1905 case e_mwi_interrogate:
1906 {
1907 X880_ReturnResult & result = serviceAPDU.BuildMessageWaitIndicationResult(currentInvokeId, H4507_H323_MWI_Operations::e_mwiInterrogate);
1908 H4507_MWIInterrogateRes mwiIntRes;
1909 BuildMWIInterrogateResult(mwiIntRes, mwiInfo);
1910 PTRACE(6,"H4507\tInterrogate result\n" << mwiIntRes);
1911 mwiIntRes.Encode(resultStream);
1912 resultStream.CompleteEncoding();
1913 result.m_result.m_result.SetValue(resultStream);
1914 }
1915 break;
1916 }
1917
1918 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
1919
1920 mwiState = e_mwi_Idle;
1921 mwiTimer.Stop();
1922 }
1923
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString * argument)1924 PBoolean H4507Handler::OnReceivedInvoke(int opcode,
1925 int invokeId,
1926 int linkedId,
1927 PASN_OctetString *argument)
1928 {
1929 currentInvokeId = invokeId;
1930
1931 PBoolean success = false;
1932 switch (opcode) {
1933 case H4507_H323_MWI_Operations::e_mwiActivate:
1934 success = OnReceiveMWIActivate(argument);
1935 break;
1936
1937 case H4507_H323_MWI_Operations::e_mwiDeactivate:
1938 success = OnReceiveMWIDeactivate(argument);
1939 break;
1940
1941 case H4507_H323_MWI_Operations::e_mwiInterrogate:
1942 success = OnReceiveMWIInterrogate(argument);
1943 break;
1944
1945 default:
1946 currentInvokeId = 0;
1947 return false;
1948 }
1949
1950 if (!success)
1951 SendReturnError(H4507_MessageWaitingIndicationErrors::e_undefined);
1952
1953 return true;
1954 }
1955
OnReceivedReturnResult(X880_ReturnResult & returnResult)1956 PBoolean H4507Handler::OnReceivedReturnResult(X880_ReturnResult & returnResult)
1957 {
1958 if (mwiState != e_mwi_Wait) {
1959 PTRACE(4, "H4507\tERROR Received Return Result when not waiting on one.");
1960 return false;
1961 }
1962
1963 if (currentInvokeId != returnResult.m_invokeId.GetValue()) {
1964 PTRACE(4, "H4507\tERROR Received Return Result for " << returnResult.m_invokeId.GetValue()
1965 << " when waiting on " << currentInvokeId);
1966 return false;
1967 }
1968
1969 if (!returnResult.HasOptionalField(X880_ReturnResult::e_result) ||
1970 returnResult.m_result.m_opcode.GetTag() != X880_Code::e_local) {
1971 PTRACE(4, "H4507\tERROR Received Return Result not processed.");
1972 return false;
1973 }
1974
1975 PASN_Integer & operation = (PASN_Integer&)returnResult.m_result.m_opcode;
1976 int opcode = operation.GetValue();
1977
1978 if (opcode != mwiType) {
1979 PTRACE(4, "H4507\tERROR Received Return Result wrong message. Wanted " << mwiType << " got " << opcode);
1980 return false;
1981 }
1982
1983 switch (opcode) {
1984 case H4507_H323_MWI_Operations::e_mwiActivate:
1985 break;
1986
1987 case H4507_H323_MWI_Operations::e_mwiDeactivate:
1988 break;
1989
1990 case H4507_H323_MWI_Operations::e_mwiInterrogate:
1991 if (!OnReceiveMWIInterrogateResult(&returnResult.m_result.m_result)) {
1992 PTRACE(4, "H4507\tERROR Interrogate Response Rejected");
1993 return false;
1994 }
1995 break;
1996 }
1997 currentInvokeId = 0;
1998 mwiState = e_mwi_Idle;
1999 mwiTimer.Stop();
2000 return true;
2001
2002 }
2003
2004
OnReceiveMWIActivate(PASN_OctetString * argument)2005 PBoolean H4507Handler::OnReceiveMWIActivate(PASN_OctetString * argument)
2006 {
2007 H4507_MWIActivateArg mwiArg;
2008 if (!DecodeArguments(argument, mwiArg, -1))
2009 return false;
2010
2011 H323Connection::MWIInformation mwiInfo;
2012
2013 H4501_ArrayOf_AliasAddress & user = mwiArg.m_servedUserNr.m_destinationAddress;
2014 if (user.GetSize() > 0)
2015 mwiInfo.mwiUser = H323GetAliasAddressString(user[0]);
2016
2017 PString msgCtr = PString();
2018 if (mwiArg.HasOptionalField(H4507_MWIActivateArg::e_msgCentreId) &&
2019 mwiArg.m_msgCentreId.GetTag() == H4507_MsgCentreId::e_partyNumber) {
2020 H225_AliasAddress & msgId = (H225_AliasAddress &)mwiArg.m_msgCentreId;
2021 mwiInfo.mwiCtrId = H323GetAliasAddressString(msgId);
2022 }
2023
2024 if (mwiArg.HasOptionalField(H4507_MWIActivateArg::e_nbOfMessages))
2025 mwiInfo.mwiCalls = mwiArg.m_nbOfMessages;
2026
2027 return connection.OnReceivedMWI(mwiInfo);
2028 }
2029
OnReceiveMWIDeactivate(PASN_OctetString * argument)2030 PBoolean H4507Handler::OnReceiveMWIDeactivate(PASN_OctetString * argument)
2031 {
2032 H4507_MWIDeactivateArg mwiArg;
2033 if (!DecodeArguments(argument, mwiArg, -1))
2034 return false;
2035
2036 PString servedUser = PString();
2037 H4501_ArrayOf_AliasAddress & user = mwiArg.m_servedUserNr.m_destinationAddress;
2038 if (user.GetSize() > 0)
2039 servedUser = H323GetAliasAddressString(user[0]);
2040
2041 return connection.OnReceivedMWIClear(servedUser);
2042 }
2043
OnReceiveMWIInterrogate(PASN_OctetString * argument)2044 PBoolean H4507Handler::OnReceiveMWIInterrogate(PASN_OctetString * argument)
2045 {
2046 H4507_MWIInterrogateArg mwiArg;
2047 if (!DecodeArguments(argument, mwiArg, -1))
2048 return false;
2049
2050 PString servedUser = PString();
2051 H4501_ArrayOf_AliasAddress & user = mwiArg.m_servedUserNr.m_destinationAddress;
2052 if (user.GetSize() > 0)
2053 servedUser = H323GetAliasAddressString(user[0]);
2054
2055 return connection.OnReceivedMWIRequest(servedUser);
2056 }
2057
OnReceiveMWIInterrogateResult(PASN_OctetString * argument)2058 PBoolean H4507Handler::OnReceiveMWIInterrogateResult( PASN_OctetString * argument)
2059 {
2060 H4507_MWIInterrogateRes response;
2061
2062 PPER_Stream resultStream(*argument);
2063 if (!response.Decode(resultStream))
2064 return false;
2065
2066 if (response.GetSize() == 0)
2067 return false;
2068
2069 PTRACE(6,"H4507\tInterrogate result\n" << response);
2070
2071 H323Connection::MWIInformation mwiInfo;
2072
2073 const H4507_MWIInterrogateResElt & mwiArg = response[0];
2074 if (mwiArg.HasOptionalField(H4507_MWIInterrogateResElt::e_msgCentreId) &&
2075 mwiArg.m_msgCentreId.GetTag() == H4507_MsgCentreId::e_partyNumber) {
2076 H225_AliasAddress & msgId = (H225_AliasAddress &)mwiArg.m_msgCentreId;
2077 mwiInfo.mwiCtrId = H323GetAliasAddressString(msgId);
2078 }
2079
2080 if (mwiArg.HasOptionalField(H4507_MWIInterrogateResElt::e_nbOfMessages))
2081 mwiInfo.mwiCalls = mwiArg.m_nbOfMessages;
2082
2083 return connection.OnReceivedMWI(mwiInfo);
2084 }
2085
2086
OnReceivedReturnError(int errorCode,X880_ReturnError &)2087 PBoolean H4507Handler::OnReceivedReturnError(int errorCode, X880_ReturnError &/*returnError*/)
2088 {
2089 PTRACE(4, "H4507\tERROR Code " << errorCode << " response received.");
2090 mwiState = e_mwi_Idle;
2091 mwiTimer.Stop();
2092 return true;
2093 }
2094
OnMWITimeOut(PTimer &,H323_INT)2095 void H4507Handler::OnMWITimeOut(PTimer &, H323_INT)
2096 {
2097 switch (mwiState) {
2098 case e_mwi_Wait:
2099 connection.ClearCall();
2100 break;
2101 case e_mwi_Idle:
2102 default:
2103 break;
2104 }
2105 }
2106
StopmwiTimer()2107 void H4507Handler::StopmwiTimer()
2108 {
2109 if (mwiTimer.IsRunning()){
2110 mwiTimer.Stop();
2111 PTRACE(4, "H4507\tStopping timer MWI-TX");
2112 }
2113 }
2114
2115 /////////////////////////////////////////////////////////////////////////////
2116
H45011Handler(H323Connection & conn,H450xDispatcher & disp)2117 H45011Handler::H45011Handler(H323Connection & conn, H450xDispatcher & disp)
2118 : H450xHandler(conn, disp), ciGenerateState(e_ci_gIdle), ciCICL(0), intrudingCallCICL(0)
2119 {
2120 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionRequest, this);
2121 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL, this);
2122 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionIsolate, this);
2123 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease, this);
2124 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionWOBRequest, this);
2125 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionSilentMonitor, this);
2126 dispatcher.AddOpCode(H45011_H323CallIntrusionOperations::e_callIntrusionNotification, this);
2127
2128 dispatcher.AddOpCode(H45010_H323CallOfferOperations::e_cfbOverride, this);
2129 dispatcher.AddOpCode(H45010_H323CallOfferOperations::e_remoteUserAlerting, this);
2130
2131 dispatcher.AddOpCode(H4506_CallWaitingOperations::e_callWaiting, this);
2132
2133 ciState = e_ci_Idle;
2134 ciSendState = e_ci_sIdle;
2135 ciReturnState = e_ci_rIdle;
2136 ciTimer.SetNotifier(PCREATE_NOTIFIER(OnCallIntrudeTimeOut));
2137 }
2138
2139
OnReceivedInvoke(int opcode,int invokeId,int linkedId,PASN_OctetString * argument)2140 PBoolean H45011Handler::OnReceivedInvoke(int opcode,
2141 int invokeId,
2142 int linkedId,
2143 PASN_OctetString * argument)
2144 {
2145 PBoolean result = TRUE;
2146 currentInvokeId = invokeId;
2147
2148 switch (opcode) {
2149 case H45011_H323CallIntrusionOperations::e_callIntrusionRequest:
2150 OnReceivedCallIntrusionRequest(linkedId, argument);
2151 break;
2152
2153 case H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL:
2154 OnReceivedCallIntrusionGetCIPL(linkedId, argument);
2155 break;
2156
2157 case H45011_H323CallIntrusionOperations::e_callIntrusionIsolate:
2158 OnReceivedCallIntrusionIsolate(linkedId, argument);
2159 break;
2160
2161 case H45011_H323CallIntrusionOperations::e_callIntrusionForcedRelease:
2162 result = OnReceivedCallIntrusionForcedRelease(linkedId, argument);
2163 break;
2164
2165 case H45011_H323CallIntrusionOperations::e_callIntrusionWOBRequest:
2166 OnReceivedCallIntrusionWOBRequest(linkedId, argument);
2167 break;
2168
2169 case H45011_H323CallIntrusionOperations::e_callIntrusionSilentMonitor:
2170 OnReceivedCallIntrusionSilentMonitor(linkedId, argument);
2171 break;
2172
2173 case H45011_H323CallIntrusionOperations::e_callIntrusionNotification:
2174 OnReceivedCallIntrusionNotification(linkedId, argument);
2175 break;
2176
2177 case H45010_H323CallOfferOperations::e_cfbOverride:
2178 OnReceivedCfbOverride(linkedId, argument);
2179 break;
2180
2181 case H45010_H323CallOfferOperations::e_remoteUserAlerting:
2182 OnReceivedRemoteUserAlerting(linkedId, argument);
2183 break;
2184
2185 case H4506_CallWaitingOperations::e_callWaiting:
2186 OnReceivedCallWaiting(linkedId, argument);
2187 break;
2188
2189 default:
2190 currentInvokeId = 0;
2191 return FALSE;
2192 }
2193
2194 return result;
2195 }
2196
2197
AttachToSetup(H323SignalPDU & pdu)2198 void H45011Handler::AttachToSetup(H323SignalPDU & pdu)
2199 {
2200 // Do we need to attach a call transfer setup invoke APDU?
2201 if (ciSendState != e_ci_sAttachToSetup)
2202 return;
2203
2204 H450ServiceAPDU serviceAPDU;
2205
2206 // Store the outstanding invokeID associated with this connection
2207 currentInvokeId = dispatcher.GetNextInvokeId();
2208 PTRACE(4, "H450.11\tAttachToSetup Invoke ID=" << currentInvokeId);
2209
2210 switch (ciGenerateState){
2211 case e_ci_gConferenceRequest:
2212 break;
2213 case e_ci_gHeldRequest:
2214 break;
2215 case e_ci_gSilentMonitorRequest:
2216 break;
2217 case e_ci_gIsolationRequest:
2218 break;
2219 case e_ci_gForcedReleaseRequest:
2220 serviceAPDU.BuildCallIntrusionForcedRelease(currentInvokeId, ciCICL);
2221 break;
2222 case e_ci_gWOBRequest:
2223 break;
2224 default:
2225 break;
2226 }
2227
2228 if(ciGenerateState != e_ci_gIdle){
2229 // Use the call identity from the ctInitiateArg
2230 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
2231 // start timer CT-T1
2232 PTRACE(4, "H450.11\tStarting timer CI-T1");
2233 StartciTimer(connection.GetEndPoint().GetCallIntrusionT1());
2234 ciState = e_ci_WaitAck;
2235 }
2236
2237 ciSendState = e_ci_sIdle;
2238 ciGenerateState = e_ci_gIdle;
2239 }
2240
2241
AttachToAlerting(H323SignalPDU & pdu)2242 void H45011Handler::AttachToAlerting(H323SignalPDU & pdu)
2243 {
2244 if (ciSendState != e_ci_sAttachToAlerting)
2245 return;
2246
2247 PTRACE(4, "H450.11\tAttachToAlerting Invoke ID=" << currentInvokeId);
2248
2249 // Store the outstanding invokeID associated with this connection
2250 currentInvokeId = dispatcher.GetNextInvokeId();
2251 PTRACE(4, "H450.11\tAttachToAlerting Invoke ID=" << currentInvokeId);
2252 if(ciReturnState!=e_ci_rIdle){
2253 H450ServiceAPDU serviceAPDU;
2254 switch (ciReturnState){
2255 case e_ci_rCallIntrusionImpending:
2256 serviceAPDU.BuildCallIntrusionImpending(currentInvokeId);
2257 PTRACE(4, "H450.11\tReturned e_ci_rCallIntrusionImpending");
2258 break;
2259 case e_ci_rCallIntruded:
2260 break;
2261 case e_ci_rCallIsolated:
2262 break;
2263 case e_ci_rCallForceReleased:
2264 break;
2265 case e_ci_rCallForceReleaseResult:
2266 serviceAPDU.BuildCallIntrusionForcedReleaseResult(currentInvokeId);
2267 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
2268 break;
2269 case e_ci_rCallIntrusionComplete:
2270 break;
2271 case e_ci_rCallIntrusionEnd:
2272 break;
2273 case e_ci_rNotBusy:
2274 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
2275 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2276 break;
2277 case e_ci_rTempUnavailable:
2278 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2279 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
2280 break;
2281 case e_ci_rNotAuthorized:
2282 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2283 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
2284 break;
2285 default :
2286 break;
2287 }
2288 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
2289 }
2290
2291 ciState = e_ci_Idle;
2292 ciSendState = e_ci_sIdle;
2293 ciReturnState = e_ci_rIdle;
2294 }
2295
2296
AttachToConnect(H323SignalPDU & pdu)2297 void H45011Handler::AttachToConnect(H323SignalPDU & pdu)
2298 {
2299 if ((currentInvokeId == 0) || (ciSendState != e_ci_sAttachToConnect))
2300 return;
2301
2302 currentInvokeId = dispatcher.GetNextInvokeId();
2303 PTRACE(4, "H450.11\tAttachToConnect Invoke ID=" << currentInvokeId);
2304 if(ciReturnState!=e_ci_rIdle){
2305 H450ServiceAPDU serviceAPDU;
2306 switch (ciReturnState){
2307 case e_ci_rCallIntrusionImpending:
2308 break;
2309 case e_ci_rCallIntruded:
2310 break;
2311 case e_ci_rCallIsolated:
2312 break;
2313 case e_ci_rCallForceReleased:
2314 break;
2315 case e_ci_rCallForceReleaseResult:
2316 serviceAPDU.BuildCallIntrusionForcedReleaseResult(currentInvokeId);
2317 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForced Release Result");
2318 break;
2319 case e_ci_rCallIntrusionComplete:
2320 break;
2321 case e_ci_rCallIntrusionEnd:
2322 break;
2323 case e_ci_rNotBusy:
2324 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
2325 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2326 break;
2327 case e_ci_rTempUnavailable:
2328 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2329 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
2330 break;
2331 case e_ci_rNotAuthorized:
2332 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2333 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
2334 break;
2335 default :
2336 break;
2337 }
2338
2339 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
2340 }
2341
2342
2343 ciState = e_ci_Idle;
2344 ciSendState = e_ci_sIdle;
2345 ciReturnState = e_ci_rIdle;
2346 currentInvokeId = 0;
2347 }
2348
2349
2350
AttachToReleaseComplete(H323SignalPDU & pdu)2351 void H45011Handler::AttachToReleaseComplete(H323SignalPDU & pdu)
2352 {
2353 // Do we need to attach a call transfer setup invoke APDU?
2354 if (ciSendState != e_ci_sAttachToReleseComplete)
2355 return;
2356
2357 PTRACE(4, "H450.11\tAttachToSetup Invoke ID=" << currentInvokeId);
2358 if(ciReturnState!=e_ci_rIdle){
2359 H450ServiceAPDU serviceAPDU;
2360 switch (ciReturnState){
2361 case e_ci_rNotBusy:
2362 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notBusy);
2363 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notBusy");
2364 break;
2365 case e_ci_rTempUnavailable:
2366 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_temporarilyUnavailable");
2367 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_temporarilyUnavailable);
2368 break;
2369 case e_ci_rNotAuthorized:
2370 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionErrors::e_notAuthorized");
2371 serviceAPDU.BuildReturnError(currentInvokeId, H45011_CallIntrusionErrors::e_notAuthorized);
2372 break;
2373 case e_ci_rCallForceReleased:
2374 PTRACE(4, "H450.11\tReturned H45011_CallIntrusionForceRelease::e_ci_rCallForceReleased");
2375 serviceAPDU.BuildCallIntrusionForceRelesed(currentInvokeId);
2376 break;
2377 default :
2378 break;
2379 }
2380 serviceAPDU.AttachSupplementaryServiceAPDU(pdu);
2381 }
2382
2383 ciState = e_ci_Idle;
2384 ciSendState = e_ci_sIdle;
2385 ciReturnState = e_ci_rIdle;
2386 }
2387
2388
OnReceivedCallIntrusionRequest(int,PASN_OctetString * argument)2389 void H45011Handler::OnReceivedCallIntrusionRequest(int /*linkedId*/,
2390 PASN_OctetString *argument)
2391 {
2392
2393 H45011_CIRequestArg ciArg;
2394
2395 if(!DecodeArguments(argument, ciArg, -1))
2396 return;
2397 /*
2398 TBD
2399 */
2400 return;
2401 }
2402
2403
OnReceivedCallIntrusionGetCIPL(int,PASN_OctetString * argument)2404 void H45011Handler::OnReceivedCallIntrusionGetCIPL(int /*linkedId*/,
2405 PASN_OctetString *argument)
2406 {
2407 PTRACE(4, "H450.11\tReceived GetCIPL Invoke");
2408
2409 H45011_CIGetCIPLOptArg ciArg;
2410
2411 if (!DecodeArguments(argument, ciArg, -1))
2412 return;
2413
2414 // Send a FACILITY message with a callTransferIdentify return result
2415 // Supplementary Service PDU to the transferring endpoint.
2416 H450ServiceAPDU serviceAPDU;
2417
2418 X880_ReturnResult& result = serviceAPDU.BuildReturnResult(currentInvokeId);
2419 result.IncludeOptionalField(X880_ReturnResult::e_result);
2420 result.m_result.m_opcode.SetTag(X880_Code::e_local);
2421 PASN_Integer& operation = (PASN_Integer&) result.m_result.m_opcode;
2422 operation.SetValue(H45011_H323CallIntrusionOperations::e_callIntrusionGetCIPL);
2423
2424 H45011_CIGetCIPLRes ciCIPLRes;
2425
2426 ciCIPLRes.m_ciProtectionLevel = endpoint.GetCallIntrusionProtectionLevel();
2427 ciCIPLRes.IncludeOptionalField(H45011_CIGetCIPLRes::e_silentMonitoringPermitted);
2428
2429 PPER_Stream resultStream;
2430 ciCIPLRes.Encode(resultStream);
2431 resultStream.CompleteEncoding();
2432 result.m_result.m_result.SetValue(resultStream);
2433
2434 serviceAPDU.WriteFacilityPDU(connection);
2435 PTRACE(4, "H450.11\tSent GetCIPL Result CIPL=" << ciCIPLRes.m_ciProtectionLevel);
2436 /*
2437 TBD
2438 */
2439 return;
2440 }
2441
2442
OnReceivedCallIntrusionIsolate(int,PASN_OctetString * argument)2443 void H45011Handler::OnReceivedCallIntrusionIsolate(int /*linkedId*/,
2444 PASN_OctetString *argument)
2445 {
2446
2447 H45011_CIIsOptArg ciArg;
2448
2449 if(!DecodeArguments(argument, ciArg, -1))
2450 return;
2451 /*
2452 TBD
2453 */
2454 return;
2455 }
2456
2457
OnReceivedCallIntrusionForcedRelease(int,PASN_OctetString * argument)2458 PBoolean H45011Handler::OnReceivedCallIntrusionForcedRelease(int /*linkedId*/,
2459 PASN_OctetString *argument)
2460 {
2461 PBoolean result = TRUE;
2462 PTRACE(4, "H450.11\tReceived ForcedRelease Invoke");
2463
2464 H45011_CIFrcRelArg ciArg;
2465
2466 if(!DecodeArguments(argument, ciArg, -1))
2467 return FALSE;
2468
2469 PStringList tokens = endpoint.GetAllConnections();
2470
2471 if(tokens.GetSize() >1) {
2472 for (PINDEX i = 0; i < tokens.GetSize(); i++) {
2473 if(endpoint.HasConnection(tokens[i])){
2474 H323Connection* conn = endpoint.FindConnectionWithLock(tokens[i]);
2475 if (conn != NULL){
2476 if (conn->IsEstablished()){
2477 if((conn->GetLocalCallIntrusionProtectionLevel() < ciArg.m_ciCapabilityLevel)){
2478 activeCallToken = conn->GetCallToken();
2479 intrudingCallToken = connection.GetCallToken();
2480 conn->GetRemoteCallIntrusionProtectionLevel(connection.GetCallToken (), (unsigned)ciArg.m_ciCapabilityLevel);
2481 result = TRUE;
2482 conn->Unlock ();
2483 break;
2484 }
2485 else
2486 result = FALSE;
2487 }
2488 conn->Unlock ();
2489 }
2490 }
2491 }
2492 if(result){
2493 ciSendState = e_ci_sAttachToConnect;
2494 ciReturnState = e_ci_rCallForceReleaseResult;
2495 connection.SetCallIntrusion ();
2496 }
2497 else {
2498 ciSendState = e_ci_sAttachToReleseComplete;
2499 ciReturnState = e_ci_rNotAuthorized;
2500 connection.ClearCall(H323Connection::EndedByLocalBusy);
2501 }
2502 }
2503 else{
2504 ciSendState = e_ci_sAttachToAlerting;
2505 ciReturnState = e_ci_rNotBusy;
2506 }
2507
2508 return result;
2509 }
2510
2511
OnReceivedCallIntrusionWOBRequest(int,PASN_OctetString * argument)2512 void H45011Handler::OnReceivedCallIntrusionWOBRequest(int /*linkedId*/,
2513 PASN_OctetString *argument)
2514 {
2515
2516 H45011_CIWobOptArg ciArg;
2517
2518 if(!DecodeArguments(argument, ciArg, -1))
2519 return;
2520 /*
2521 TBD
2522 */
2523 return;
2524 }
2525
2526
OnReceivedCallIntrusionSilentMonitor(int,PASN_OctetString * argument)2527 void H45011Handler::OnReceivedCallIntrusionSilentMonitor(int /*linkedId*/,
2528 PASN_OctetString *argument)
2529 {
2530
2531 H45011_CISilentArg ciArg;
2532
2533 if(!DecodeArguments(argument, ciArg, -1))
2534 return;
2535 /*
2536 TBD
2537 */
2538 return;
2539 }
2540
2541
OnReceivedCallIntrusionNotification(int,PASN_OctetString * argument)2542 void H45011Handler::OnReceivedCallIntrusionNotification(int /*linkedId*/,
2543 PASN_OctetString *argument)
2544 {
2545
2546 H45011_CINotificationArg ciArg;
2547
2548 if(!DecodeArguments(argument, ciArg, -1))
2549 return;
2550 /*
2551 TBD
2552 */
2553 return;
2554 }
2555
2556
OnReceivedCfbOverride(int,PASN_OctetString * argument)2557 void H45011Handler::OnReceivedCfbOverride(int /*linkedId*/,
2558 PASN_OctetString *argument)
2559 {
2560
2561 H45010_CfbOvrOptArg ciArg;
2562
2563 if(!DecodeArguments(argument, ciArg, -1))
2564 return;
2565 /*
2566 TBD
2567 */
2568 return;
2569 }
2570
2571
OnReceivedRemoteUserAlerting(int,PASN_OctetString * argument)2572 void H45011Handler::OnReceivedRemoteUserAlerting(int /*linkedId*/,
2573 PASN_OctetString *argument)
2574 {
2575
2576 H45010_RUAlertOptArg ciArg;
2577
2578 if(!DecodeArguments(argument, ciArg, -1))
2579 return;
2580 /*
2581 TBD
2582 */
2583 return;
2584 }
2585
2586
OnReceivedCallWaiting(int,PASN_OctetString * argument)2587 void H45011Handler::OnReceivedCallWaiting(int /*linkedId*/,
2588 PASN_OctetString *argument)
2589 {
2590
2591 H4506_CallWaitingArg ciArg;
2592
2593 if(!DecodeArguments(argument, ciArg, -1))
2594 return;
2595 /*
2596 TBD
2597 */
2598 return;
2599 }
2600
2601
OnReceivedReturnResult(X880_ReturnResult & returnResult)2602 PBoolean H45011Handler::OnReceivedReturnResult(X880_ReturnResult & returnResult)
2603 {
2604 PTRACE(4, "H450.11\tReceived Return Result");
2605 if (currentInvokeId == returnResult.m_invokeId.GetValue()) {
2606 PTRACE(4, "H450.11\tReceived Return Result Invoke ID=" << currentInvokeId);
2607 switch (ciState) {
2608 case e_ci_WaitAck:
2609 OnReceivedCIRequestResult();
2610 break;
2611 case e_ci_GetCIPL:
2612 OnReceivedCIGetCIPLResult(returnResult);
2613 break;
2614 default :
2615 break;
2616 }
2617 }
2618 return TRUE;
2619 }
2620
2621
OnReceivedCIRequestResult()2622 void H45011Handler::OnReceivedCIRequestResult()
2623 {
2624 PTRACE(4, "H450.11\tOnReceivedCIRequestResult");
2625 // stop timer CI-T1
2626 PTRACE(4, "H450.11\tTrying to stop timer CI-T1");
2627 StopciTimer();
2628 }
2629
2630
OnReceivedCIGetCIPLResult(X880_ReturnResult & returnResult)2631 void H45011Handler::OnReceivedCIGetCIPLResult(X880_ReturnResult & returnResult)
2632 {
2633 PTRACE(4, "H450.11\tOnReceivedCIRequestResult");
2634 // Get the return result if present
2635 PASN_OctetString * result = NULL;
2636 if (returnResult.HasOptionalField(X880_ReturnResult::e_result)) {
2637 result = &returnResult.m_result.m_result;
2638
2639 // Extract the C Party Details
2640 H45011_CIGetCIPLRes ciGetCIPLResult;
2641
2642 PPER_Stream resultStream(*result);
2643 ciGetCIPLResult.Decode(resultStream);
2644
2645 PTRACE(4 ,"H450.11\tReceived CIPL=" << ciGetCIPLResult.m_ciProtectionLevel );
2646
2647 if (intrudingCallCICL > ciGetCIPLResult.m_ciProtectionLevel){
2648
2649 // Send ciNotification.inv (ciImpending) To C
2650 connection.Lock();
2651 H450ServiceAPDU serviceAPDU;
2652 currentInvokeId = dispatcher.GetNextInvokeId();
2653 serviceAPDU.BuildCallIntrusionImpending(currentInvokeId);
2654 serviceAPDU.WriteFacilityPDU(connection);
2655 connection.Unlock();
2656
2657 // Send ciNotification.inv (ciImpending) to intruding (A)
2658 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2659 conn->SetIntrusionImpending ();
2660
2661 //Send Ringing to intruding (A)
2662 conn->AnsweringCall (conn->AnswerCallPending);
2663
2664 // MUST RETURN ciNotification.inv (callForceRelesed) to active call (C) when releasing call !!!!!!
2665 ciSendState = e_ci_sAttachToReleseComplete;
2666 ciReturnState = e_ci_rCallForceReleased;
2667
2668 //Send Forced Release Accepted when Answering call to intruding (A)
2669 conn->SetForcedReleaseAccepted();
2670 conn->Unlock ();
2671 }
2672 else {
2673 PTRACE(4 ,"H450.11\tCICL<CIPL -> Clear Call");
2674 // Clear Call with intruding (A)
2675 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2676 conn->SetIntrusionNotAuthorized();
2677 conn->Unlock();
2678 endpoint.ClearCall (intrudingCallToken);
2679 }
2680 }
2681
2682 // stop timer CI-T5
2683 PTRACE(4, "H450.11\tTrying to stop timer CI-T5");
2684 StopciTimer();
2685 }
2686
2687
OnReceivedReturnError(int errorCode,X880_ReturnError & returnError)2688 PBoolean H45011Handler::OnReceivedReturnError(int errorCode, X880_ReturnError &returnError)
2689 {
2690 PBoolean result = TRUE;
2691 PTRACE(4, "H450.11\tReceived Return Error CODE=" <<errorCode << ", InvokeId=" <<returnError.m_invokeId.GetValue());
2692 if (currentInvokeId == returnError.m_invokeId.GetValue()) {
2693 switch (ciState) {
2694 case e_ci_WaitAck:
2695 result = OnReceivedInvokeReturnError(errorCode);
2696 break;
2697 case e_ci_GetCIPL:
2698 result = OnReceivedGetCIPLReturnError(errorCode);
2699 break;
2700 default :
2701 break;
2702 }
2703 }
2704 return result;
2705 }
2706
2707
OnReceivedInvokeReturnError(int errorCode,const bool timerExpiry)2708 PBoolean H45011Handler::OnReceivedInvokeReturnError(int errorCode, const bool timerExpiry)
2709 {
2710 PBoolean result = FALSE;
2711 PTRACE(4, "H450.11\tOnReceivedInvokeReturnError CODE =" << errorCode);
2712 if (!timerExpiry) {
2713 // stop timer CI-T1
2714 StopciTimer();
2715 PTRACE(4, "H450.11\tStopping timer CI-T1");
2716 }
2717 else
2718 PTRACE(4, "H450.11\tTimer CI-T1 has expired awaiting a response to a callIntrusionInvoke return result.");
2719
2720 currentInvokeId = 0;
2721 ciState = e_ci_Idle;
2722 ciSendState = e_ci_sIdle;
2723
2724 switch(errorCode){
2725 case H45011_CallIntrusionErrors::e_notBusy :
2726 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notBusy");
2727 result = TRUE;
2728 break;
2729 case H45011_CallIntrusionErrors::e_temporarilyUnavailable :
2730 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_temporarilyUnavailable");
2731 break;
2732 case H45011_CallIntrusionErrors::e_notAuthorized :
2733 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::e_notAuthorized");
2734 result = TRUE;
2735 break;
2736 default:
2737 PTRACE(4, "H450.11\tH45011_CallIntrusionErrors::DEFAULT");
2738 break;
2739 }
2740 return result;
2741 }
2742
2743
OnReceivedGetCIPLReturnError(int PTRACE_PARAM (errorCode),const bool timerExpiry)2744 PBoolean H45011Handler::OnReceivedGetCIPLReturnError(int PTRACE_PARAM(errorCode),
2745 const bool timerExpiry)
2746 {
2747 PTRACE(4, "H450.11\tOnReceivedGetCIPLReturnError ErrorCode=" << errorCode);
2748 if(!timerExpiry){
2749 if (ciTimer.IsRunning()){
2750 ciTimer.Stop();
2751 PTRACE(4, "H450.11\tStopping timer CI-TX");
2752 }
2753 }
2754
2755 // Send ciNotification.inv (ciImpending) to active call (C)
2756 connection.Lock();
2757 H450ServiceAPDU serviceAPDU;
2758 currentInvokeId = dispatcher.GetNextInvokeId();
2759 serviceAPDU.BuildCallIntrusionImpending(currentInvokeId);
2760 serviceAPDU.WriteFacilityPDU(connection);
2761 connection.Unlock();
2762
2763 // Send ciNotification.inv (ciImpending) to intruding (A)
2764 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2765 conn->SetIntrusionImpending ();
2766
2767 //Send Ringing to intruding (A)
2768 conn->AnsweringCall (conn->AnswerCallPending);
2769
2770 ciSendState = e_ci_sAttachToReleseComplete;
2771 ciReturnState = e_ci_rCallForceReleased;
2772
2773 //Forced Release Accepted to send when Answering call to intruding (A)
2774 conn->SetForcedReleaseAccepted();
2775 conn->Unlock ();
2776
2777 return FALSE;
2778 }
2779
2780
IntrudeCall(int CICL)2781 void H45011Handler::IntrudeCall(int CICL)
2782 {
2783 ciSendState = e_ci_sAttachToSetup;
2784 ciGenerateState = e_ci_gForcedReleaseRequest;
2785 ciCICL = CICL;
2786 }
2787
2788
AwaitSetupResponse(const PString & token,const PString & identity)2789 void H45011Handler::AwaitSetupResponse(const PString & token,
2790 const PString & identity)
2791 {
2792 intrudingCallToken = token;
2793 intrudingCallIdentity = identity;
2794 ciState = e_ci_WaitAck;
2795
2796 }
2797
2798
GetRemoteCallIntrusionProtectionLevel(const PString & token,unsigned intrusionCICL)2799 PBoolean H45011Handler::GetRemoteCallIntrusionProtectionLevel(const PString & token,
2800 unsigned intrusionCICL)
2801 {
2802 if (!connection.Lock())
2803 return FALSE;
2804
2805 intrudingCallToken = token;
2806 intrudingCallCICL = intrusionCICL;
2807
2808 H450ServiceAPDU serviceAPDU;
2809
2810 currentInvokeId = dispatcher.GetNextInvokeId();
2811
2812 serviceAPDU.BuildCallIntrusionGetCIPL(currentInvokeId);
2813
2814 connection.Unlock();
2815
2816 if (!serviceAPDU.WriteFacilityPDU(connection))
2817 return FALSE;
2818
2819 PTRACE(4, "H450.11\tStarting timer CI-T5");
2820 StartciTimer(connection.GetEndPoint().GetCallIntrusionT5());
2821 ciState = e_ci_GetCIPL;
2822 return TRUE;
2823 }
2824
2825
SetIntrusionNotAuthorized()2826 void H45011Handler::SetIntrusionNotAuthorized()
2827 {
2828 ciSendState = e_ci_sAttachToReleseComplete;
2829 ciReturnState = e_ci_rNotAuthorized;
2830 }
2831
2832
SetIntrusionImpending()2833 void H45011Handler::SetIntrusionImpending()
2834 {
2835 ciSendState = e_ci_sAttachToAlerting;
2836 ciReturnState = e_ci_rCallIntrusionImpending;
2837 }
2838
2839
SetForcedReleaseAccepted()2840 void H45011Handler::SetForcedReleaseAccepted()
2841 {
2842 ciSendState = e_ci_sAttachToConnect;
2843 ciReturnState = e_ci_rCallForceReleaseResult;
2844 ciState = e_ci_DestNotify;
2845
2846 StartciTimer(connection.GetEndPoint().GetCallIntrusionT6());
2847 }
2848
2849
StopciTimer()2850 void H45011Handler::StopciTimer()
2851 {
2852 if (ciTimer.IsRunning()){
2853 ciTimer.Stop();
2854 PTRACE(4, "H450.11\tStopping timer CI-TX");
2855 }
2856 }
2857
2858
OnCallIntrudeTimeOut(PTimer &,H323_INT)2859 void H45011Handler::OnCallIntrudeTimeOut(PTimer &, H323_INT)
2860 {
2861 switch (ciState) {
2862 // CI-T1 Timeout
2863 case e_ci_WaitAck:
2864 PTRACE(4, "H450.11\tTimer CI-T1 has expired");
2865 OnReceivedInvokeReturnError(0,true);
2866 break;
2867 case e_ci_GetCIPL:
2868 PTRACE(4, "H450.11\tTimer CI-T5 has expired");
2869 OnReceivedGetCIPLReturnError(0,true);
2870 break;
2871 case e_ci_DestNotify:
2872 {
2873 PTRACE(4, "H450.11\tOnCallIntrudeTimeOut Timer CI-T6 has expired");
2874 // Clear the active call (call with C)
2875 PSyncPoint sync;
2876 endpoint.ClearCallSynchronous(activeCallToken, H323Connection::EndedByLocalUser, &sync);
2877 // Answer intruding call (call with A)
2878 PTRACE(4, "H450.11\tOnCallIntrudeTimeOut Trying to answer Call");
2879 if(endpoint.HasConnection(intrudingCallToken)){
2880 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2881 conn->AnsweringCall (conn->AnswerCallNow);
2882 conn->Unlock ();
2883 }
2884 }
2885 break;
2886 default:
2887 break;
2888 }
2889 }
2890
2891
OnReceivedReject(int PTRACE_PARAM (problemType),int PTRACE_PARAM (problemNumber))2892 PBoolean H45011Handler::OnReceivedReject(int PTRACE_PARAM(problemType), int PTRACE_PARAM(problemNumber))
2893 {
2894 PTRACE(4, "H450.11\tH45011Handler::OnReceivedReject - problemType= "
2895 << problemType << ", problemNumber= " << problemNumber);
2896
2897 if (ciTimer.IsRunning()){
2898 ciTimer.Stop();
2899 PTRACE(4, "H450.11\tStopping timer CI-TX");
2900 }
2901
2902 switch (ciState) {
2903 case e_ci_GetCIPL:
2904 {
2905 H323Connection* conn = endpoint.FindConnectionWithLock(intrudingCallToken);
2906 conn->SetIntrusionImpending ();
2907
2908 //Send Ringing to intruding (A)
2909 conn->AnsweringCall (conn->AnswerCallPending);
2910 conn->SetForcedReleaseAccepted();
2911 conn->Unlock ();
2912 break;
2913 }
2914
2915 default:
2916 break;
2917 }
2918 ciState = e_ci_Idle;
2919 return TRUE;
2920 };
2921