home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / q931.cxx < prev    next >
C/C++ Source or Header  |  2003-03-18  |  37KB  |  1,285 lines

  1. /*
  2.  * q931.cxx
  3.  *
  4.  * Q.931 protocol handler
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1998-2000 Equivalence 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.  * Portions of this code were written with the assisance of funding from
  25.  * Vovida Networks, Inc. http://www.vovida.com.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: q931.cxx,v $
  30.  * Revision 1.58  2003/03/18 05:54:18  robertj
  31.  * Added ChannelIdentifier IE support, thanks Eize Slange
  32.  *
  33.  * Revision 1.57  2003/02/12 02:23:01  robertj
  34.  * Fixed printing of cause codes that are impossible as opposed to merely
  35.  *   unlikely or unallocated.
  36.  *
  37.  * Revision 1.56  2003/02/12 00:02:23  robertj
  38.  * Added more Q.931 cause codes.
  39.  * Added ability to trace text version of cause codes and IE codes.
  40.  *
  41.  * Revision 1.55  2002/11/19 06:19:25  robertj
  42.  * Added extra "congested" Q.931 codes.
  43.  *
  44.  * Revision 1.54  2002/08/06 02:27:39  robertj
  45.  * GNU C++ v3 compatibility.
  46.  *
  47.  * Revision 1.53  2002/08/05 10:03:48  robertj
  48.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  49.  *
  50.  * Revision 1.52  2002/07/25 10:55:44  robertj
  51.  * Changes to allow more granularity in PDU dumps, hex output increasing
  52.  *   with increasing trace level.
  53.  *
  54.  * Revision 1.51  2002/07/05 03:13:38  robertj
  55.  * Added copy constructor for Q.931 so makes duplicate instead of reference to IE's.
  56.  *
  57.  * Revision 1.50  2002/07/03 10:26:05  robertj
  58.  * Fixed bearer capabilities for H,450.1 needing non ITU standard, thanks Florian Winterstein
  59.  *
  60.  * Revision 1.49  2002/05/22 23:12:03  robertj
  61.  * Enhanced the display of Release-Complete cause codes.
  62.  *
  63.  * Revision 1.48  2002/05/07 23:49:35  craigs
  64.  * Changed comment on length of userUserIE field thanks to Paul Long
  65.  *
  66.  * Revision 1.47  2002/05/03 05:38:19  robertj
  67.  * Added Q.931 Keypad IE mechanism for user indications (DTMF).
  68.  *
  69.  * Revision 1.46  2002/04/22 07:32:16  craigs
  70.  * Changed GetProgressIndicator to be const
  71.  *
  72.  * Revision 1.45  2002/04/19 04:49:14  robertj
  73.  * Fixed currect bit shift for CallState IE standard bits.
  74.  *
  75.  * Revision 1.44  2002/04/19 02:16:47  robertj
  76.  * Added CallState IE processing.
  77.  *
  78.  * Revision 1.43  2002/04/18 06:16:32  craigs
  79.  * Extra robustness in handling of strange UserUserIE lengths
  80.  *
  81.  * Revision 1.42  2002/01/07 04:25:21  robertj
  82.  * Added support for Connected-Number Information Element, thanks Hans Verbeek
  83.  *
  84.  * Revision 1.41  2002/01/06 05:28:41  robertj
  85.  * Fixed crash if given bad data in number field, thanks Chih-Wei Huang.
  86.  *
  87.  * Revision 1.40  2001/09/17 02:06:40  robertj
  88.  * Added Redirecting Number IE to Q.931, thanks Frank Derks
  89.  *
  90.  * Revision 1.39  2001/09/13 02:41:21  robertj
  91.  * Fixed call reference generation to use full range and common code, thanks Carlo Kielstra
  92.  *
  93.  * Revision 1.38  2001/08/27 03:45:59  robertj
  94.  * Added automatic setting of bearer capability transfer mode from H.323
  95.  *    capabilities on connection at time of SETUP PDU.
  96.  *
  97.  * Revision 1.37  2001/08/20 06:48:28  robertj
  98.  * Added Q.931 function for setting bearer capabilities, allowing
  99.  *    applications to set the data rate as they require.
  100.  *
  101.  * Revision 1.36  2001/08/07 02:57:09  robertj
  102.  * Fixed incorrect Q.931 bearer capability, thanks Carlo Kielstra.
  103.  *
  104.  * Revision 1.35  2001/07/24 23:40:15  craigs
  105.  * Added ability to remove Q931 IE
  106.  *
  107.  * Revision 1.34  2001/06/14 06:25:16  robertj
  108.  * Added further H.225 PDU build functions.
  109.  * Moved some functionality from connection to PDU class.
  110.  *
  111.  * Revision 1.33  2001/05/30 04:38:40  robertj
  112.  * Added BuildStatusEnquiry() Q.931 function, thanks Markus Storm
  113.  *
  114.  * Revision 1.32  2001/04/05 00:06:31  robertj
  115.  * Fixed some more encoding/decoding problems with little used bits of
  116.  *   the Q.931 protocol, thanks Hans Verbeek.
  117.  *
  118.  * Revision 1.31  2001/04/03 23:06:15  robertj
  119.  * Fixed correct encoding and decoding of Q.850 cause field, thanks Hans Verbeek.
  120.  *
  121.  * Revision 1.30  2001/02/09 05:13:56  craigs
  122.  * Added pragma implementation to (hopefully) reduce the executable image size
  123.  * under Linux
  124.  *
  125.  * Revision 1.29  2001/01/19 06:57:26  robertj
  126.  * Added Information message type.
  127.  *
  128.  * Revision 1.28  2000/10/13 02:16:04  robertj
  129.  * Added support for Progress Indicator Q.931/H.225 message.
  130.  *
  131.  * Revision 1.27  2000/07/11 11:17:01  robertj
  132.  * Improved trace log display of Q.931 PDU's (correct order and extra IE fields).
  133.  *
  134.  * Revision 1.26  2000/07/09 14:54:11  robertj
  135.  * Added facility IE to facility message.
  136.  * Changed reference to the word "field" to be more correct IE or "Information Element"
  137.  *
  138.  * Revision 1.25  2000/06/21 08:07:47  robertj
  139.  * Added cause/reason to release complete PDU, where relevent.
  140.  *
  141.  * Revision 1.24  2000/05/09 12:19:31  robertj
  142.  * Added ability to get and set "distinctive ring" Q.931 functionality.
  143.  *
  144.  * Revision 1.23  2000/05/08 14:07:35  robertj
  145.  * Improved the provision and detection of calling and caller numbers, aliases and hostnames.
  146.  *
  147.  * Revision 1.22  2000/05/06 02:18:26  robertj
  148.  * Changed the new CallingPartyNumber code so defaults for octet3a are application dependent.
  149.  *
  150.  * Revision 1.21  2000/05/05 00:44:05  robertj
  151.  * Added presentation and screening fields to Calling Party Number field, thanks Dean Anderson.
  152.  *
  153.  * Revision 1.20  2000/05/02 04:32:27  robertj
  154.  * Fixed copyright notice comment.
  155.  *
  156.  * Revision 1.19  2000/03/21 01:08:11  robertj
  157.  * Fixed incorrect call reference code being used in originated call.
  158.  *
  159.  * Revision 1.18  2000/02/17 12:07:43  robertj
  160.  * Used ne wPWLib random number generator after finding major problem in MSVC rand().
  161.  *
  162.  * Revision 1.17  1999/12/23 22:44:06  robertj
  163.  * Added calling party number field.
  164.  *
  165.  * Revision 1.16  1999/09/22 04:18:29  robertj
  166.  * Fixed missing "known" message types in debugging output.
  167.  *
  168.  * Revision 1.15  1999/09/10 03:36:48  robertj
  169.  * Added simple Q.931 Status response to Q.931 Status Enquiry
  170.  *
  171.  * Revision 1.14  1999/08/31 13:54:35  robertj
  172.  * Fixed problem with memory overrun building PDU's
  173.  *
  174.  * Revision 1.13  1999/08/31 12:34:19  robertj
  175.  * Added gatekeeper support.
  176.  *
  177.  * Revision 1.12  1999/08/13 06:34:38  robertj
  178.  * Fixed problem in CallPartyNumber Q.931 encoding.
  179.  * Added field name display to Q.931 protocol.
  180.  *
  181.  * Revision 1.11  1999/08/10 13:14:15  robertj
  182.  * Added Q.931 Called Number field if have "phone number" style destination addres.
  183.  *
  184.  * Revision 1.10  1999/07/16 02:15:30  robertj
  185.  * Fixed more tunneling problems.
  186.  *
  187.  * Revision 1.9  1999/07/09 14:59:59  robertj
  188.  * Fixed GNU C++ compatibility.
  189.  *
  190.  * Revision 1.8  1999/07/09 06:09:50  robertj
  191.  * Major implementation. An ENORMOUS amount of stuff added everywhere.
  192.  *
  193.  * Revision 1.7  1999/06/14 15:19:48  robertj
  194.  * GNU C compatibility
  195.  *
  196.  * Revision 1.6  1999/06/13 12:41:14  robertj
  197.  * Implement logical channel transmitter.
  198.  * Fixed H245 connect on receiving call.
  199.  *
  200.  * Revision 1.5  1999/06/09 05:26:20  robertj
  201.  * Major restructuring of classes.
  202.  *
  203.  * Revision 1.4  1999/02/23 11:04:29  robertj
  204.  * Added capability to make outgoing call.
  205.  *
  206.  * Revision 1.3  1999/01/16 01:31:38  robertj
  207.  * Major implementation.
  208.  *
  209.  * Revision 1.2  1999/01/02 04:00:52  robertj
  210.  * Added higher level protocol negotiations.
  211.  *
  212.  * Revision 1.1  1998/12/14 09:13:37  robertj
  213.  * Initial revision
  214.  *
  215.  */
  216.  
  217. #include <ptlib.h>
  218.  
  219. #ifdef __GNUC__
  220. #pragma implementation "q931.h"
  221. #endif
  222.  
  223. #include "q931.h"
  224.  
  225. #include <ptclib/random.h>
  226.  
  227.  
  228. #define new PNEW
  229.  
  230.  
  231. ostream & operator<<(ostream & strm, Q931::InformationElementCodes ie)
  232. {
  233.   static POrdinalToString::Initialiser IENamesInit[] = {
  234.     { Q931::BearerCapabilityIE,     "Bearer-Capability"     },
  235.     { Q931::CauseIE,                "Cause"                 },
  236.     { Q931::FacilityIE,             "Facility"              },
  237.     { Q931::ProgressIndicatorIE,    "Progress-Indicator"    },
  238.     { Q931::CallStateIE,            "Call-State"            },
  239.     { Q931::DisplayIE,              "Display"               },
  240.     { Q931::SignalIE,               "Signal"                },
  241.     { Q931::KeypadIE,               "Keypad"                },
  242.     { Q931::ConnectedNumberIE,      "Connected-Number"      },
  243.     { Q931::CallingPartyNumberIE,   "Calling-Party-Number"  },
  244.     { Q931::CalledPartyNumberIE,    "Called-Party-Number"   },
  245.     { Q931::RedirectingNumberIE,    "Redirecting-Number"    },
  246.     { Q931::ChannelIdentificationIE,"Channel-Identification"},
  247.     { Q931::UserUserIE,             "User-User"             } 
  248.   };
  249.   static const POrdinalToString IENames(PARRAYSIZE(IENamesInit), IENamesInit);
  250.  
  251.   if (IENames.Contains((PINDEX)ie))
  252.     strm << IENames[ie];
  253.   else
  254.     strm << "0x" << hex << (unsigned)ie << dec << " (" << (unsigned)ie << ')';
  255.  
  256.   return strm;
  257. }
  258.  
  259.  
  260. ostream & operator<<(ostream & strm, Q931::CauseValues cause)
  261. {
  262.   static POrdinalToString::Initialiser CauseNamesInit[] = {
  263.     { Q931::UnallocatedNumber,           "Unallocated number"              },
  264.     { Q931::NoRouteToNetwork,            "No route to network"             },
  265.     { Q931::NoRouteToDestination,        "No route to destination"         },
  266.     { Q931::SendSpecialTone,             "Send special tone"               },
  267.     { Q931::MisdialledTrunkPrefix,       "Misdialled trunk prefix"         },
  268.     { Q931::ChannelUnacceptable,         "Channel unacceptable"            },
  269.     { Q931::NormalCallClearing,          "Normal call clearing"            },
  270.     { Q931::UserBusy,                    "User busy"                       },
  271.     { Q931::NoResponse,                  "No response"                     },
  272.     { Q931::NoAnswer,                    "No answer"                       },
  273.     { Q931::SubscriberAbsent,            "Subscriber absent"               },
  274.     { Q931::CallRejected,                "Call rejected"                   },
  275.     { Q931::NumberChanged,               "Number changed"                  },
  276.     { Q931::Redirection,                 "Redirection"                     },
  277.     { Q931::ExchangeRoutingError,        "Exchange routing error"          },
  278.     { Q931::NonSelectedUserClearing,     "Non selected user clearing"      },
  279.     { Q931::DestinationOutOfOrder,       "Destination out of order"        },
  280.     { Q931::InvalidNumberFormat,         "Invalid number format"           },
  281.     { Q931::FacilityRejected,            "Facility rejected"               },
  282.     { Q931::StatusEnquiryResponse,       "Status enquiry response"         },
  283.     { Q931::NormalUnspecified,           "Normal unspecified"              },
  284.     { Q931::NoCircuitChannelAvailable,   "No circuit/channel available"    },
  285.     { Q931::NetworkOutOfOrder,           "Network out of order"            },
  286.     { Q931::TemporaryFailure,            "Temporary failure"               },
  287.     { Q931::Congestion,                  "Congestion"                      },
  288.     { Q931::RequestedCircuitNotAvailable,"RequestedCircuitNotAvailable"    },
  289.     { Q931::ResourceUnavailable,         "Resource unavailable"            },
  290.     { Q931::ServiceOptionNotAvailable,   "Service or option not available" },
  291.     { Q931::InvalidCallReference,        "Invalid call reference"          },
  292.     { Q931::IncompatibleDestination,     "Incompatible destination"        },
  293.     { Q931::IENonExistantOrNotImplemented,"IE non-existent or not implemented" },
  294.     { Q931::TimerExpiry,                 "Recovery from timer expiry"      },
  295.     { Q931::ProtocolErrorUnspecified,    "Protocol error, unspecified"     },
  296.     { Q931::InterworkingUnspecified,     "Interworking, unspecified"       }
  297.   };
  298.   static const POrdinalToString CauseNames(PARRAYSIZE(CauseNamesInit), CauseNamesInit);
  299.  
  300.   if (CauseNames.Contains((PINDEX)cause))
  301.     strm << CauseNames[cause];
  302.   else if (cause < Q931::ErrorInCauseIE)
  303.     strm << "0x" << hex << (unsigned)cause << dec << " (" << (unsigned)cause << ')';
  304.   else
  305.     strm << "N/A";
  306.  
  307.   return strm;
  308. }
  309.  
  310.  
  311. ///////////////////////////////////////////////////////////////////////////////
  312.  
  313. Q931::Q931()
  314. {
  315.   protocolDiscriminator = 8;  // Q931 always has 00001000
  316.   messageType = NationalEscapeMsg;
  317.   fromDestination = FALSE;
  318.   callReference = 0;
  319. }
  320.  
  321.  
  322. Q931::Q931(const Q931 & other)
  323. {
  324.   operator=(other);
  325. }
  326.  
  327.  
  328. Q931 & Q931::operator=(const Q931 & other)
  329. {
  330.   callReference = other.callReference;
  331.   fromDestination = other.fromDestination;
  332.   protocolDiscriminator = other.protocolDiscriminator;
  333.   messageType = other.messageType;
  334.  
  335.   informationElements.RemoveAll();
  336.   for (PINDEX i = 0; i < other.informationElements.GetSize(); i++)
  337.     informationElements.SetAt(other.informationElements.GetKeyAt(i), new PBYTEArray(other.informationElements.GetDataAt(i)));
  338.  
  339.   return *this;
  340. }
  341.  
  342.  
  343. void Q931::BuildFacility(int callRef, BOOL fromDest)
  344. {
  345.   messageType = FacilityMsg;
  346.   callReference = callRef;
  347.   fromDestination = fromDest;
  348.   informationElements.RemoveAll();
  349.   PBYTEArray data;
  350.   SetIE(FacilityIE, data);
  351. }
  352.  
  353.  
  354. void Q931::BuildInformation(int callRef, BOOL fromDest)
  355. {
  356.   messageType = InformationMsg;
  357.   callReference = callRef;
  358.   fromDestination = fromDest;
  359.   informationElements.RemoveAll();
  360. }
  361.  
  362.  
  363. void Q931::BuildProgress(int callRef,
  364.                          BOOL fromDest,
  365.                          unsigned description,
  366.                          unsigned codingStandard,
  367.                          unsigned location)
  368. {
  369.   messageType = ProgressMsg;
  370.   callReference = callRef;
  371.   fromDestination = fromDest;
  372.   informationElements.RemoveAll();
  373.   SetProgressIndicator(description, codingStandard, location);
  374. }
  375.  
  376.  
  377. void Q931::BuildNotify(int callRef, BOOL fromDest)
  378. {
  379.   messageType = NotifyMsg;
  380.   callReference = callRef;
  381.   fromDestination = fromDest;
  382.   informationElements.RemoveAll();
  383. }
  384.  
  385.  
  386. void Q931::BuildSetupAcknowledge(int callRef)
  387. {
  388.   messageType = SetupAckMsg;
  389.   callReference = callRef;
  390.   fromDestination = TRUE;
  391.   informationElements.RemoveAll();
  392. }
  393.  
  394.  
  395. void Q931::BuildCallProceeding(int callRef)
  396. {
  397.   messageType = CallProceedingMsg;
  398.   callReference = callRef;
  399.   fromDestination = TRUE;
  400.   informationElements.RemoveAll();
  401. }
  402.  
  403.  
  404. void Q931::BuildAlerting(int callRef)
  405. {
  406.   messageType = AlertingMsg;
  407.   callReference = callRef;
  408.   fromDestination = TRUE;
  409.   informationElements.RemoveAll();
  410. }
  411.  
  412.  
  413. void Q931::BuildSetup(int callRef)
  414. {
  415.   messageType = SetupMsg;
  416.   if (callRef < 0)
  417.     callReference = GenerateCallReference();
  418.   else
  419.     callReference = callRef;
  420.   fromDestination = FALSE;
  421.   informationElements.RemoveAll();
  422.   SetBearerCapabilities(TransferSpeech, 1);
  423. }
  424.  
  425.  
  426. void Q931::BuildConnect(int callRef)
  427. {
  428.   messageType = ConnectMsg;
  429.   callReference = callRef;
  430.   fromDestination = TRUE;
  431.   informationElements.RemoveAll();
  432.   SetBearerCapabilities(TransferSpeech, 1);
  433. }
  434.  
  435.  
  436. void Q931::BuildStatus(int callRef, BOOL fromDest)
  437. {
  438.   messageType = StatusMsg;
  439.   callReference = callRef;
  440.   fromDestination = fromDest;
  441.   informationElements.RemoveAll();
  442.   SetCallState(CallState_Active);
  443.   // Cause field as per Q.850
  444.   SetCause(StatusEnquiryResponse);
  445. }
  446.  
  447.  
  448. void Q931::BuildStatusEnquiry(int callRef, BOOL fromDest)
  449. {
  450.   messageType = StatusEnquiryMsg;
  451.   callReference = callRef;
  452.   fromDestination = fromDest;
  453.   informationElements.RemoveAll();
  454. }
  455.  
  456.  
  457. void Q931::BuildReleaseComplete(int callRef, BOOL fromDest)
  458. {
  459.   messageType = ReleaseCompleteMsg;
  460.   callReference = callRef;
  461.   fromDestination = fromDest;
  462.   informationElements.RemoveAll();
  463. }
  464.  
  465.  
  466. BOOL Q931::Decode(const PBYTEArray & data)
  467. {
  468.   // Clear all existing data before reading new
  469.   informationElements.RemoveAll();
  470.  
  471.   if (data.GetSize() < 5) // Packet too short
  472.     return FALSE;
  473.  
  474.   protocolDiscriminator = data[0];
  475.  
  476.   if (data[1] != 2) // Call reference must be 2 bytes long
  477.     return FALSE;
  478.  
  479.   callReference = ((data[2]&0x7f) << 8) | data[3];
  480.   fromDestination = (data[2]&0x80) != 0;
  481.  
  482.   messageType = (MsgTypes)data[4];
  483.  
  484.   // Have preamble, start getting the informationElements into buffers
  485.   PINDEX offset = 5;
  486.   while (offset < data.GetSize()) {
  487.     // Get field discriminator
  488.     int discriminator = data[offset++];
  489.  
  490.     PBYTEArray * item = new PBYTEArray;
  491.  
  492.     // For discriminator with high bit set there is no data
  493.     if ((discriminator&0x80) == 0) {
  494.       int len = data[offset++];
  495.  
  496.       if (discriminator == UserUserIE) {
  497.         // Special case of User-user field. See 7.2.2.31/H.225.0v4.
  498.         len <<= 8;
  499.         len |= data[offset++];
  500.  
  501.         // we also have a protocol discriminator, which we ignore
  502.         offset++;
  503.  
  504.     // before decrementing the length, make sure it is not zero
  505.     if (len == 0)
  506.           return FALSE;
  507.  
  508.         // adjust for protocol discriminator
  509.         len--;
  510.       }
  511.  
  512.       if (offset + len > data.GetSize())
  513.         return FALSE;
  514.  
  515.       memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
  516.       offset += len;
  517.     }
  518.  
  519.     informationElements.SetAt(discriminator, item);
  520.   }
  521.  
  522.   return TRUE;
  523. }
  524.  
  525.  
  526. BOOL Q931::Encode(PBYTEArray & data) const
  527. {
  528.   PINDEX totalBytes = 5;
  529.   unsigned discriminator;
  530.   for (discriminator = 0; discriminator < 256; discriminator++) {
  531.     if (informationElements.Contains(discriminator)) {
  532.       if (discriminator < 128)
  533.         totalBytes += informationElements[discriminator].GetSize() +
  534.                             (discriminator != UserUserIE ? 2 : 4);
  535.       else
  536.         totalBytes++;
  537.     }
  538.   }
  539.  
  540.   if (!data.SetMinSize(totalBytes))
  541.     return FALSE;
  542.  
  543.   // Put in Q931 header
  544.   PAssert(protocolDiscriminator < 256, PInvalidParameter);
  545.   data[0] = (BYTE)protocolDiscriminator;
  546.   data[1] = 2; // Length of call reference
  547.   data[2] = (BYTE)(callReference >> 8);
  548.   if (fromDestination)
  549.     data[2] |= 0x80;
  550.   data[3] = (BYTE)callReference;
  551.   PAssert(messageType < 256, PInvalidParameter);
  552.   data[4] = (BYTE)messageType;
  553.  
  554.   // The following assures disciminators are in ascending value order
  555.   // as required by Q931 specification
  556.   PINDEX offset = 5;
  557.   for (discriminator = 0; discriminator < 256; discriminator++) {
  558.     if (informationElements.Contains(discriminator)) {
  559.       if (discriminator < 128) {
  560.         int len = informationElements[discriminator].GetSize();
  561.  
  562.         if (discriminator != UserUserIE) {
  563.           data[offset++] = (BYTE)discriminator;
  564.           data[offset++] = (BYTE)len;
  565.         }
  566.         else {
  567.           len++; // Allow for protocol discriminator
  568.           data[offset++] = (BYTE)discriminator;
  569.           data[offset++] = (BYTE)(len >> 8);
  570.           data[offset++] = (BYTE)len;
  571.           len--; // Then put the length back again
  572.           // We shall assume that the user-user field is an ITU protocol block (5)
  573.           data[offset++] = 5;
  574.         }
  575.  
  576.         memcpy(&data[offset], (const BYTE *)informationElements[discriminator], len);
  577.         offset += len;
  578.       }
  579.       else
  580.         data[offset++] = (BYTE)discriminator;
  581.     }
  582.   }
  583.  
  584.   return data.SetSize(offset);
  585. }
  586.  
  587.  
  588. void Q931::PrintOn(ostream & strm) const
  589. {
  590.   int indent = strm.precision() + 2;
  591.   _Ios_Fmtflags flags = strm.flags();
  592.  
  593.   strm << "{\n"
  594.        << setw(indent+24) << "protocolDiscriminator = " << protocolDiscriminator << '\n'
  595.        << setw(indent+16) << "callReference = " << callReference << '\n'
  596.        << setw(indent+7)  << "from = " << (fromDestination ? "destination" : "originator") << '\n'
  597.        << setw(indent+14) << "messageType = " << GetMessageTypeName() << '\n';
  598.  
  599.   for (unsigned discriminator = 0; discriminator < 256; discriminator++) {
  600.     if (informationElements.Contains(discriminator)) {
  601.       strm << setw(indent+4) << "IE: " << (InformationElementCodes)discriminator;
  602.       if (discriminator == CauseIE) {
  603.         if (informationElements[discriminator].GetSize() > 1)
  604.           strm << " - " << (CauseValues)(informationElements[discriminator][1]&0x7f);
  605.       }
  606.       strm << " = {\n"
  607.            << hex << setfill('0') << resetiosflags(ios::floatfield)
  608.            << setprecision(indent+2) << setw(16);
  609.  
  610.       PBYTEArray value = informationElements[discriminator];
  611.       if (value.GetSize() <= 32 || (flags&ios::floatfield) != ios::fixed)
  612.         strm << value;
  613.       else {
  614.         PBYTEArray truncatedArray(value, 32);
  615.         strm << truncatedArray << '\n'
  616.              << setfill(' ')
  617.              << setw(indent+5) << "...";
  618.       }
  619.  
  620.       strm << dec << setfill(' ')
  621.            << '\n'
  622.            << setw(indent+2) << "}\n";
  623.     }
  624.   }
  625.  
  626.   strm << setw(indent-1) << "}";
  627.  
  628.   strm.flags(flags);
  629. }
  630.  
  631.  
  632. PString Q931::GetMessageTypeName() const
  633. {
  634.   switch (messageType) {
  635.     case AlertingMsg :
  636.       return "Alerting";
  637.     case CallProceedingMsg :
  638.       return "CallProceeding";
  639.     case ConnectMsg :
  640.       return "Connect";
  641.     case ConnectAckMsg :
  642.       return "ConnectAck";
  643.     case ProgressMsg :
  644.       return "Progress";
  645.     case SetupMsg :
  646.       return "Setup";
  647.     case SetupAckMsg :
  648.       return "SetupAck";
  649.     case FacilityMsg :
  650.       return "Facility";
  651.     case ReleaseCompleteMsg :
  652.       return "ReleaseComplete";
  653.     case StatusEnquiryMsg :
  654.       return "StatusEnquiry";
  655.     case StatusMsg :
  656.       return "Status";
  657.     case InformationMsg :
  658.       return "Information";
  659.     case NationalEscapeMsg :
  660.       return "Escape";
  661.     default :
  662.       break;
  663.   }
  664.  
  665.   return psprintf("<%u>", messageType);
  666. }
  667.  
  668.  
  669. unsigned Q931::GenerateCallReference()
  670. {
  671.   static unsigned LastCallReference;
  672.   static PMutex mutex;
  673.   PWaitAndSignal wait(mutex);
  674.  
  675.   if (LastCallReference == 0)
  676.     LastCallReference = PRandom::Number();
  677.   else
  678.     LastCallReference++;
  679.  
  680.   LastCallReference &= 0x7fff;
  681.  
  682.   if (LastCallReference == 0)
  683.     LastCallReference = 1;
  684.  
  685.   return LastCallReference;
  686. }
  687.  
  688.  
  689. BOOL Q931::HasIE(InformationElementCodes ie) const
  690. {
  691.   return informationElements.Contains(POrdinalKey(ie));
  692. }
  693.  
  694.  
  695. PBYTEArray Q931::GetIE(InformationElementCodes ie) const
  696. {
  697.   if (informationElements.Contains(POrdinalKey(ie)))
  698.     return informationElements[ie];
  699.  
  700.   return PBYTEArray();
  701. }
  702.  
  703.  
  704. void Q931::SetIE(InformationElementCodes ie, const PBYTEArray & userData)
  705. {
  706.   informationElements.SetAt(ie, new PBYTEArray(userData));
  707. }
  708.  
  709. void Q931::RemoveIE(InformationElementCodes ie)
  710. {
  711.   informationElements.RemoveAt(ie);
  712. }
  713.  
  714.  
  715. void Q931::SetBearerCapabilities(InformationTransferCapability capability,
  716.                                  unsigned transferRate,
  717.                                  unsigned codingStandard,
  718.                                  unsigned userInfoLayer1)
  719. {
  720.   BYTE data[4];
  721.   PINDEX size = 1;
  722.   data[0] = (BYTE)(0x80 | ((codingStandard&3) << 5) | (capability&31));
  723.  
  724.   switch (codingStandard) {
  725.     case 0 :  // ITU-T standardized coding
  726.       size = 3;
  727.  
  728.       // Note this is always "Circuit Mode"
  729.       switch (transferRate) {
  730.         case 1 :
  731.           data[1] = 0x90;
  732.           break;
  733.         case 2 :
  734.           data[1] = 0x91;
  735.           break;
  736.         case 6 :
  737.           data[1] = 0x93;
  738.           break;
  739.         case 24 :
  740.           data[1] = 0x95;
  741.           break;
  742.         case 30 :
  743.           data[1] = 0x97;
  744.           break;
  745.         default :
  746.           PAssert(transferRate > 0 && transferRate < 128, PInvalidParameter);
  747.           data[1] = 0x18;
  748.           data[2] = (BYTE)(0x80 | transferRate);
  749.           size = 4;
  750.       }
  751.  
  752.       PAssert(userInfoLayer1 >= 2 && userInfoLayer1 <= 5, PInvalidParameter);
  753.       data[size-1] = (BYTE)(0x80 | (1<<5) | userInfoLayer1);
  754.       break;
  755.  
  756.     case 1 : // Other international standard
  757.       size = 2;
  758.       data[1] = 0x80; // Call independent signalling connection
  759.       break;
  760.  
  761.     default :
  762.       break;
  763.   }
  764.  
  765.   SetIE(BearerCapabilityIE, PBYTEArray(data, size));
  766. }
  767.  
  768.  
  769. BOOL Q931::GetBearerCapabilities(InformationTransferCapability & capability,
  770.                                  unsigned & transferRate,
  771.                                  unsigned * codingStandard,
  772.                                  unsigned * userInfoLayer1)
  773. {
  774.   if (!HasIE(BearerCapabilityIE))
  775.     return FALSE;
  776.  
  777.   PBYTEArray data = GetIE(BearerCapabilityIE);
  778.   if (data.GetSize() < 3)
  779.     return FALSE;
  780.  
  781.   capability = (InformationTransferCapability)data[0];
  782.   if (codingStandard != NULL)
  783.     *codingStandard = (data[0] >> 5)&3;
  784.  
  785.   PINDEX nextByte = 2;
  786.   switch (data[1]) {
  787.     case 0x90 :
  788.       transferRate = 1;
  789.       break;
  790.     case 0x91 :
  791.       transferRate = 2;
  792.       break;
  793.     case 0x93 :
  794.       transferRate = 6;
  795.       break;
  796.     case 0x95 :
  797.       transferRate = 24;
  798.       break;
  799.     case 0x97 :
  800.       transferRate = 30;
  801.       break;
  802.     case 0x18 :
  803.       if (data.GetSize() < 4)
  804.         return FALSE;
  805.       transferRate = data[2]&0x7f;
  806.       nextByte = 3;
  807.       break;
  808.     default :
  809.       return FALSE;
  810.   }
  811.  
  812.   if (userInfoLayer1 != NULL && ((data[nextByte]>>5)&3) == 1)
  813.     *userInfoLayer1 = data[nextByte]&0x31;
  814.  
  815.   return TRUE;
  816. }
  817.  
  818.  
  819. void Q931::SetCause(CauseValues value, unsigned standard, unsigned location)
  820. {
  821.   PBYTEArray data(2);
  822.   data[0] = (BYTE)(0x80 | ((standard&3) << 5) | (location&15));
  823.   data[1] = (BYTE)(0x80 | value);
  824.   SetIE(CauseIE, data);
  825. }
  826.  
  827.  
  828. Q931::CauseValues Q931::GetCause(unsigned * standard, unsigned * location) const
  829. {
  830.   if (!HasIE(CauseIE))
  831.     return ErrorInCauseIE;
  832.  
  833.   PBYTEArray data = GetIE(CauseIE);
  834.   if (data.GetSize() < 2)
  835.     return ErrorInCauseIE;
  836.  
  837.   if (standard != NULL)
  838.     *standard = (data[0] >> 5)&3;
  839.   if (location != NULL)
  840.     *location = data[0]&15;
  841.  
  842.   if ((data[0]&0x80) != 0)
  843.     return (CauseValues)(data[1]&0x7f);
  844.  
  845.   // Allow for optional octet
  846.   if (data.GetSize() < 3)
  847.     return ErrorInCauseIE;
  848.  
  849.   return (CauseValues)(data[2]&0x7f);
  850. }
  851.  
  852.  
  853. void Q931::SetCallState(CallStates value, unsigned standard)
  854. {
  855.   if (value >= CallState_ErrorInIE)
  856.     return;
  857.  
  858.   // Call State as per Q.931 section 4.5.7
  859.   PBYTEArray data(1);
  860.   data[0] = (BYTE)(((standard&3) << 6) | value);
  861.   SetIE(CallStateIE, data);
  862. }
  863.  
  864.  
  865. Q931::CallStates Q931::GetCallState(unsigned * standard) const
  866. {
  867.   if (!HasIE(SignalIE))
  868.     return CallState_ErrorInIE;
  869.  
  870.   PBYTEArray data = GetIE(CallStateIE);
  871.   if (data.IsEmpty())
  872.     return CallState_ErrorInIE;
  873.  
  874.   if (standard != NULL)
  875.     *standard = (data[0] >> 6)&3;
  876.  
  877.   return (CallStates)(data[0]&0x3f);
  878. }
  879.  
  880.  
  881. void Q931::SetSignalInfo(SignalInfo value)
  882. {
  883.   PBYTEArray data(1);
  884.   data[0] = (BYTE)value;
  885.   SetIE(SignalIE, data);
  886. }
  887.  
  888.  
  889. Q931::SignalInfo Q931::GetSignalInfo() const
  890. {
  891.   if (!HasIE(SignalIE))
  892.     return SignalErrorInIE;
  893.  
  894.   PBYTEArray data = GetIE(SignalIE);
  895.   if (data.IsEmpty())
  896.     return SignalErrorInIE;
  897.  
  898.   return (SignalInfo)data[0];
  899. }
  900.  
  901.  
  902. void Q931::SetKeypad(const PString & digits)
  903. {
  904.   PBYTEArray bytes((const BYTE *)(const char *)digits, digits.GetLength()+1);
  905.   SetIE(KeypadIE, bytes);
  906. }
  907.  
  908.  
  909. PString Q931::GetKeypad() const
  910. {
  911.   if (!HasIE(Q931::KeypadIE))
  912.     return PString();
  913.  
  914.   PBYTEArray digits = GetIE(Q931::KeypadIE);
  915.   if (digits.IsEmpty())
  916.     return PString();
  917.  
  918.   return PString((const char *)(const BYTE *)digits, digits.GetSize());
  919. }
  920.  
  921.  
  922. void Q931::SetProgressIndicator(unsigned description,
  923.                                 unsigned codingStandard,
  924.                                 unsigned location)
  925. {
  926.   PBYTEArray data(2);
  927.   data[0] = (BYTE)(0x80+((codingStandard&0x03)<<5)+(location&0x0f));
  928.   data[1] = (BYTE)(0x80+(description&0x7f));
  929.   SetIE(ProgressIndicatorIE, data);
  930. }
  931.  
  932.  
  933. BOOL Q931::GetProgressIndicator(unsigned & description,
  934.                                 unsigned * codingStandard,
  935.                                 unsigned * location) const
  936. {
  937.   if (!HasIE(ProgressIndicatorIE))
  938.     return FALSE;
  939.  
  940.   PBYTEArray data = GetIE(ProgressIndicatorIE);
  941.   if (data.GetSize() < 2)
  942.     return FALSE;
  943.  
  944.   if (codingStandard != NULL)
  945.     *codingStandard = (data[0]>>5)&0x03;
  946.   if (location != NULL)
  947.     *location = data[0]&0x0f;
  948.   description = data[1]&0x7f;
  949.  
  950.   return TRUE;
  951. }
  952.  
  953.  
  954. void Q931::SetDisplayName(const PString & name)
  955. {
  956.   PBYTEArray bytes((const BYTE *)(const char *)name, name.GetLength()+1);
  957.   SetIE(DisplayIE, bytes);
  958. }
  959.  
  960.  
  961. PString Q931::GetDisplayName() const
  962. {
  963.   if (!HasIE(Q931::DisplayIE))
  964.     return PString();
  965.  
  966.   PBYTEArray display = GetIE(Q931::DisplayIE);
  967.   if (display.IsEmpty())
  968.     return PString();
  969.  
  970.   return PString((const char *)(const BYTE *)display, display.GetSize());
  971. }
  972.  
  973.  
  974. static PBYTEArray SetNumberIE(const PString & number,
  975.                               unsigned plan,
  976.                               unsigned type,
  977.                               int presentation,
  978.                               int screening,
  979.                               int reason)
  980. {
  981.   PBYTEArray bytes;
  982.  
  983.   PINDEX len = number.GetLength();
  984.  
  985.   if (reason == -1) {
  986.     if (presentation == -1 || screening == -1) {
  987.       bytes.SetSize(len+1);
  988.       bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
  989.       memcpy(bytes.GetPointer()+1, (const char *)number, len);
  990.     }
  991.     else {
  992.       bytes.SetSize(len+2);
  993.       bytes[0] = (BYTE)(((type&7)<<4)|(plan&15));
  994.       bytes[1] = (BYTE)(0x80|((presentation&3)<<5)|(screening&3));
  995.       memcpy(bytes.GetPointer()+2, (const char *)number, len);
  996.     }
  997.   } 
  998.   else {
  999.     // If octet 3b is present, then octet 3a must also be present!
  1000.     if (presentation == -1 || screening == -1) {
  1001.       // This situation should never occur!!!
  1002.       bytes.SetSize(len+1);
  1003.       bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
  1004.       memcpy(bytes.GetPointer()+1, (const char *)number, len);
  1005.     }
  1006.     else {
  1007.       bytes.SetSize(len+3);
  1008.       bytes[0] = (BYTE)(0x80|((type&7)<<4)|(plan&15));
  1009.       bytes[1] = (BYTE)(0x80|((presentation&3)<<5)|(screening&3));
  1010.       bytes[2] = (BYTE)(0x80|(reason&15));
  1011.       memcpy(bytes.GetPointer()+3, (const char *)number, len);
  1012.     }
  1013.   }
  1014.  
  1015.   return bytes;
  1016. }
  1017.  
  1018.  
  1019. static BOOL GetNumberIE(const PBYTEArray & bytes,
  1020.                         PString  & number,
  1021.                         unsigned * plan,
  1022.                         unsigned * type,
  1023.                         unsigned * presentation,
  1024.                         unsigned * screening,
  1025.                         unsigned * reason,
  1026.                         unsigned   defPresentation,
  1027.                         unsigned   defScreening,
  1028.                         unsigned   defReason)
  1029. {
  1030.   number = PString();
  1031.  
  1032.   if (bytes.IsEmpty())
  1033.     return FALSE;
  1034.  
  1035.   if (plan != NULL)
  1036.     *plan = bytes[0]&15;
  1037.  
  1038.   if (type != NULL)
  1039.     *type = (bytes[0]>>4)&7;
  1040.  
  1041.   PINDEX offset;
  1042.   if ((bytes[0] & 0x80) != 0) {  // Octet 3a not provided, set defaults
  1043.     if (presentation != NULL)
  1044.       *presentation = defPresentation;
  1045.  
  1046.     if (screening != NULL)
  1047.       *screening = defScreening;
  1048.  
  1049.     offset = 1;
  1050.   }
  1051.   else {
  1052.     if (bytes.GetSize() < 2)
  1053.       return FALSE;
  1054.  
  1055.     if (presentation != NULL)
  1056.       *presentation = (bytes[1]>>5)&3;
  1057.  
  1058.     if (screening != NULL)
  1059.       *screening = bytes[1]&3;
  1060.  
  1061.     if ((bytes[1] & 0x80) != 0) { // Octet 3b not provided, set defaults
  1062.       if (reason != NULL)
  1063.         *reason = defReason;
  1064.  
  1065.       offset = 2;
  1066.     }
  1067.     else {
  1068.       if (bytes.GetSize() < 3)
  1069.         return FALSE;
  1070.  
  1071.       if (reason != NULL)
  1072.         *reason = bytes[2]&15;
  1073.  
  1074.       offset = 3;
  1075.     }
  1076.   }
  1077.  
  1078.   if (bytes.GetSize() < offset)
  1079.     return FALSE;
  1080.  
  1081.   PINDEX len = bytes.GetSize()-offset;
  1082.  
  1083.   if (len > 0)
  1084.     memcpy(number.GetPointer(len+1), ((const BYTE *)bytes)+offset, len);
  1085.  
  1086.   return !number;
  1087. }
  1088.  
  1089.  
  1090. void Q931::SetCallingPartyNumber(const PString & number,
  1091.                                  unsigned plan,
  1092.                                  unsigned type,
  1093.                                  int presentation,
  1094.                                  int screening)
  1095. {
  1096.   SetIE(CallingPartyNumberIE,
  1097.         SetNumberIE(number, plan, type, presentation, screening, -1));
  1098. }
  1099.  
  1100.  
  1101. BOOL Q931::GetCallingPartyNumber(PString  & number,
  1102.                                  unsigned * plan,
  1103.                                  unsigned * type,
  1104.                                  unsigned * presentation,
  1105.                                  unsigned * screening,
  1106.                                  unsigned   defPresentation,
  1107.                                  unsigned   defScreening) const
  1108. {
  1109.   return GetNumberIE(GetIE(CallingPartyNumberIE), number,
  1110.                      plan, type, presentation, screening, NULL,
  1111.                      defPresentation, defScreening, 0);
  1112. }
  1113.  
  1114.  
  1115. void Q931::SetCalledPartyNumber(const PString & number, unsigned plan, unsigned type)
  1116. {
  1117.   SetIE(CalledPartyNumberIE,
  1118.         SetNumberIE(number, plan, type, -1, -1, -1));
  1119. }
  1120.  
  1121.  
  1122. BOOL Q931::GetCalledPartyNumber(PString & number, unsigned * plan, unsigned * type) const
  1123. {
  1124.   return GetNumberIE(GetIE(CalledPartyNumberIE),
  1125.                      number, plan, type, NULL, NULL, NULL, 0, 0, 0);
  1126. }
  1127.  
  1128.  
  1129. void Q931::SetRedirectingNumber(const PString & number,
  1130.                                 unsigned plan,
  1131.                                 unsigned type,
  1132.                                 int presentation,
  1133.                                 int screening,
  1134.                                 int reason)
  1135. {
  1136.   SetIE(RedirectingNumberIE,
  1137.         SetNumberIE(number, plan, type, presentation, screening, reason));
  1138. }
  1139.  
  1140.  
  1141. BOOL Q931::GetRedirectingNumber(PString  & number,
  1142.                                 unsigned * plan,
  1143.                                 unsigned * type,
  1144.                                 unsigned * presentation,
  1145.                                 unsigned * screening,
  1146.                                 unsigned * reason,
  1147.                                 unsigned   defPresentation,
  1148.                                 unsigned   defScreening,
  1149.                                 unsigned   defReason) const
  1150. {
  1151.   return GetNumberIE(GetIE(RedirectingNumberIE),
  1152.                      number, plan, type, presentation, screening, reason,
  1153.                      defPresentation, defScreening, defReason);
  1154. }
  1155.  
  1156.  
  1157. BOOL Q931::GetConnectedNumber(PString  & number,
  1158.                               unsigned * plan,
  1159.                               unsigned * type,
  1160.                               unsigned * presentation,
  1161.                               unsigned * screening,
  1162.                               unsigned * reason,
  1163.                               unsigned   defPresentation,
  1164.                               unsigned   defScreening,
  1165.                               unsigned   defReason) const
  1166. {
  1167.   return GetNumberIE(GetIE(ConnectedNumberIE), number,
  1168.                      plan, type, presentation, screening, reason,
  1169.                      defPresentation, defScreening, defReason);
  1170. }
  1171.  
  1172.  
  1173. void Q931::SetConnectedNumber(const PString & number,
  1174.                               unsigned plan,
  1175.                               unsigned type,
  1176.                               int presentation,
  1177.                               int screening,
  1178.                               int reason)
  1179. {
  1180.   SetIE(ConnectedNumberIE,
  1181.         SetNumberIE(number, plan, type, presentation, screening, reason));
  1182. }
  1183.  
  1184.  
  1185. void Q931::SetChannelIdentification(unsigned interfaceType,
  1186.                                     unsigned preferredOrExclusive,
  1187.                                     int      channelNumber)
  1188. {
  1189.   // Known limitations:
  1190.   //  - the interface identifier cannot be specified
  1191.   //  - channel in PRI can only be indicated by number and cannot be indicated by map
  1192.   //  - one and only one channel can be indicated
  1193.   //  - the coding standard is always ITU Q.931
  1194.  
  1195.   PBYTEArray bytes;
  1196.   bytes.SetSize(1);
  1197.  
  1198.   PAssert(interfaceType < 2, PInvalidParameter);
  1199.  
  1200.   if (interfaceType == 0) { // basic rate
  1201.     if (channelNumber == -1) { // any channel
  1202.       bytes[0] = 0x80 | 0x04 | 0x03;
  1203.     }
  1204.     if (channelNumber == 0) { // D channel
  1205.       bytes[0] = 0x80;
  1206.     }    
  1207.     if (channelNumber > 0) { // B channel
  1208.       bytes[0] = (BYTE)(0x80 | 0x04 | ((preferredOrExclusive & 0x01) << 3) | (channelNumber & 0x03));
  1209.     }
  1210.   }
  1211.  
  1212.   if (interfaceType == 1) { // primary rate
  1213.     if (channelNumber == -1) { // any channel
  1214.       bytes[0] = 0x80 | 0x20 | 0x04 | 0x03;
  1215.     }
  1216.     if (channelNumber == 0) { // D channel
  1217.       bytes[0] = 0x80 | 0x20;
  1218.     }    
  1219.     if (channelNumber > 0) { // B channel
  1220.       bytes.SetSize(3);
  1221.  
  1222.       bytes[0] = (BYTE)(0x80 | 0x20 | 0x04 | ((preferredOrExclusive & 0x01) << 3) | 0x01);
  1223.       bytes[1] = 0x80 | 0x03;
  1224.       bytes[2] = (BYTE)(0x80 | channelNumber);
  1225.     }
  1226.   }
  1227.  
  1228.   SetIE(ChannelIdentificationIE, bytes);
  1229. }
  1230.  
  1231.  
  1232. BOOL Q931::GetChannelIdentification(unsigned * interfaceType,
  1233.                                     unsigned * preferredOrExclusive,
  1234.                                     int      * channelNumber) const
  1235. {
  1236.   if (!HasIE(ChannelIdentificationIE))
  1237.     return FALSE;
  1238.  
  1239.   PBYTEArray bytes = GetIE(ChannelIdentificationIE);
  1240.   if (bytes.GetSize() < 1)
  1241.     return FALSE;
  1242.  
  1243.   *interfaceType        = (bytes[0]>>5) & 0x01;
  1244.   *preferredOrExclusive = (bytes[0]>>3) & 0x01;
  1245.  
  1246.   if (*interfaceType == 0) {  // basic rate
  1247.     if ( (bytes[0] & 0x04) == 0 ) {  // D Channel
  1248.       *channelNumber = 0;
  1249.     }
  1250.     else {
  1251.       if ( (bytes[0] & 0x03) == 0x03 ) {  // any channel
  1252.         *channelNumber = -1;
  1253.       }
  1254.       else { // B Channel
  1255.         *channelNumber = (bytes[0] & 0x03);
  1256.       }
  1257.     }
  1258.   }
  1259.  
  1260.   if (*interfaceType == 1) {  // primary rate
  1261.     if ( (bytes[0] & 0x04) == 0 ) {  // D Channel
  1262.       *channelNumber = 0;
  1263.     }
  1264.     else {
  1265.       if ( (bytes[0] & 0x03) == 0x03 ) {  // any channel
  1266.         *channelNumber = -1;
  1267.       }
  1268.       else { // B Channel
  1269.         if (bytes.GetSize() < 3)
  1270.           return FALSE;
  1271.  
  1272.         if (bytes[1] != 0x83)
  1273.           return FALSE;
  1274.  
  1275.         *channelNumber = bytes[2] & 0x7f;
  1276.       }
  1277.     }
  1278.   }
  1279.  
  1280.   return TRUE;
  1281. }
  1282.  
  1283.  
  1284. /////////////////////////////////////////////////////////////////////////////
  1285.