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