/**
 * @file capiutil.cc
 *
 * CapiUtil - Utility functions to handle CAPI messages.
 *
 * Copyright: 2000-2003 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: capiutil.cc,v 1.1.2.1 2006/02/28 21:35:39 thomas Exp $
 * Project  CAPI for BSD
 * Target   capitest - Test tool for the functionality of CAPI for BSD
 * @date    01.01.2000
 * @author  "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * </p>
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

/* system includes */

/* import includes */

#define __CAPIUTIL__

/* local includes */
#include "config.h"
#include "capiutil.h"





/* === public definitions ================================================ */





/* === private definitions =============================================== */





/// The translation table to convert CAPI B1 commands into strings.
static const char *g_apszCapiB1CmdNames [] =
   {
      NULL,
      "ALERT",          // C_ALERT
      "CONNECT",        // C_CONNECT
      "CONNECT ACTIVE", // C_CONNECT_ACTIVE
      "DISCONNECT",     // C_DISCONNECT
      "LISTEN",         // C_LISTEN
      NULL,
      NULL,
      "INFO"            // C_INFO_20
   };

/// The translation table to convert CAPI B3 commands into strings.
static const char *g_apszCapiB3CmdNames [] =
   {
      "FACILITY",               // C_FACILITY
      NULL,
      "CONNECT B3",             // C_CONNECT_B3
      "CONNECT B3 ACIVE",       // C_CONNECT_B3_ACTIVE
      "DISCONNECT B3",          // C_DISCONNECT_B3
      NULL,
      "DATA B3",                // C_DATA_B3
      "RESET B3",               // C_RESET_B3_20
      "CONNECT B3 T90 ACTIVE"   // C_CONNECT_B3_T90_ACTIVE
   };





/* === prototypes for private functions ================================== */





/* === definition of public functions ==================================== */





/**
 * Translate a CAPI message base command into a string.
 */

const char *CapiUt_GetCapiMsgCmdName
   (unsigned uCmd)
{
   uCmd &= CAPI_CMDMASK_COMMAND;
   if (uCmd < C_SELECT_B_PROTOCOL)
   {
      if (uCmd >= ARRAY_COUNT (g_apszCapiB1CmdNames) ||
          g_apszCapiB1CmdNames [uCmd] == NULL)
      {
         return ("Unknown-B1-Command");
      }
      return (g_apszCapiB1CmdNames [uCmd]);
   }
   else if (uCmd < C_FACILITY)
   {
      if (uCmd == C_SELECT_B_PROTOCOL)
      {
         return ("SELECT B PROTOCOL");
      }
      else
      {
         return ("Unknown-0x42-0x7F");
      }
   }
   else if (uCmd < C_MANUFACTURER)
   {
      uCmd -= C_FACILITY;
      if (uCmd >= ARRAY_COUNT (g_apszCapiB3CmdNames) ||
          g_apszCapiB3CmdNames [uCmd] == NULL)
      {
         return ("Unknown-B3-Command");
      }
      return (g_apszCapiB3CmdNames [uCmd]);
   }
   else
   {
      return ("MANUFACTURER");
   }
   
} // CapiUt_GetCapiMsgCmdName





/**
 * Translate a CAPI message sub command into a string.
 */

const char *CapiUt_GetCapiMsgSubCmdName
   (unsigned uCmd)
{
   switch (uCmd & CAPI_CMDMASK_SUBCMD)
   {
      case C_REQ:       return ("REQUEST");
      case C_CONF:      return ("CONFIRM");
      case C_IND:       return ("INDICATION");
      case C_RESP:      return ("RESPONSE");
      default:          return ("Invalid-sub-command");
   }
   
} // CapiUt_GetCapiMsgSubCmdName





/**
 * Store the called party number into a character array.
 */

unsigned char *CapiUt_ExtractCalledPartyNumber
   (unsigned char *pOrgPos,
    char          *pszCalledPartyNumber,
    size_t         nLenCalledPartyNumber)
{
   size_t  nLen = *pOrgPos;
   char   *pSrc = (char *) pOrgPos + 1;
   char   *pDst = pszCalledPartyNumber;
   
   /* if called party number is empty: ready */
   if (nLen == 0)
   {
      if (nLenCalledPartyNumber > 0)
      {
         pszCalledPartyNumber [0] = '\0';
      }
      return (pOrgPos + 1);
   }
   
   /* the first byte is the type of number and numbering plan */
   nLen--;
   pSrc++;
   
   /* copy the number bytes to the buffer specified */
   while (nLen > 0 && nLenCalledPartyNumber > 1)
   {
      *(pDst++) = *(pSrc++);
      nLen--;
      nLenCalledPartyNumber--;
   }
   if (nLenCalledPartyNumber > 0)
   {
      *pDst = '\0';
   }
   
   /* return the position behind the last byte of the number */
   return ((unsigned char *) pSrc + nLen);
} // CapiUt_ExtractCalledPartyNumber
    




/**
 * Store the called party number into an STL string.
 */

unsigned char *CapiUt_ExtractCalledPartyNumber
   (unsigned char *pOrgPos,
    std::string   &strCalledPartyNumber)
{
   size_t  nLen = *pOrgPos;
   char   *pSrc = (char *) pOrgPos + 1;
   
   /* if called party number is empty: ready */
   if (nLen == 0)
   {
      strCalledPartyNumber = "";
      return (pOrgPos + 1);
   }
   
   /* the first byte is the type of number and numbering plan */
   nLen--;
   pSrc++;
   
   /* copy the number bytes to the string specified */
   strCalledPartyNumber = std::string (pSrc, nLen);
   
   /* return the position behind the last byte of the number */
   return ((unsigned char *) pSrc + nLen);
} // CapiUt_ExtractCalledPartyNumber
    




/**
 * Store the calling party number into a character array.
 */

unsigned char *CapiUt_ExtractCallingPartyNumber
   (unsigned char *pOrgPos,
    char          *pszCallingPartyNumber,
    size_t         nLenCallingPartyNumber)
{
   size_t  nLen = *pOrgPos;
   char   *pSrc = (char *) pOrgPos + 1;
   char   *pDst = pszCallingPartyNumber;
   
   /* if called party number is empty: ready */
   if (nLen == 0)
   {
      if (nLenCallingPartyNumber > 0)
      {
         pszCallingPartyNumber [0] = '\0';
      }
      return (pOrgPos + 1);
   }
   
   /* the first byte is the type of number and numbering plan, the second is
    * the presentation and screening indicator
    */
   nLen--;
   if (nLen > 0 && (*pSrc & 0x80) == 0)
   {
      nLen--;
      pSrc += 2;
   }
   else
   {
      pSrc++;
   }
   
   /* copy the number bytes to the buffer specified */
   while (nLen > 0 && nLenCallingPartyNumber > 1)
   {
      *(pDst++) = *(pSrc++);
      nLen--;
      nLenCallingPartyNumber--;
   }
   if (nLenCallingPartyNumber > 0)
   {
      *pDst = '\0';
   }
   
   /* return the position behind the last byte of the number */
   return ((unsigned char *) pSrc + nLen);
} // CapiUt_ExtractCallingPartyNumber

    
    
    

/**
 * Store the calling party number into a character array.
 */

unsigned char *CapiUt_ExtractCallingPartyNumber
   (unsigned char *pOrgPos,
    std::string   &strCallingPartyNumber)
{
   size_t  nLen = *pOrgPos;
   char   *pSrc = (char *) pOrgPos + 1;
   
   /* if called party number is empty: ready */
   if (nLen == 0)
   {
      strCallingPartyNumber = "";
      return (pOrgPos + 1);
   }
   
   /* the first byte is the type of number and numbering plan, the second is
    * the presentation and screening indicator (if present)
    */
   nLen--;
   if (nLen > 0 && (*pSrc & 0x80) == 0)
   {
      nLen--;
      pSrc += 2;
   }
   else
   {
      pSrc++;
   }
   
   /* copy the number bytes to the string specified */
   strCallingPartyNumber = std::string (pSrc, nLen);
   
   /* return the position behind the last byte of the number */
   return ((unsigned char *) pSrc + nLen);
} // CapiUt_ExtractCallingPartyNumber





/*
        enter an empty CAPI structure at specified position
        ---------------------------------------------------
*/

unsigned char *CapiUt_EnterEmptyStruct
   (unsigned char *pOrgPos)
{
   *(pOrgPos++) = 0;
   return (pOrgPos);
} /* CapiUt_EnterEmptyStruct */
   




/*
        enter a string into a CAPI structure at specified position
        ----------------------------------------------------------
*/

unsigned char *CapiUt_EnterString
   (unsigned char *pOrgPos,
    const char    *pszString)
{
   char   *pDst = (char *) pOrgPos + 1;
   size_t  nLen = 0;
   
   if (! pszString)
   {
      return (CapiUt_EnterEmptyStruct (pOrgPos));
   }
   
   while (*pszString)
   {
      *(pDst++) = *(pszString++);
      nLen++;
   }
   
   *pOrgPos = (unsigned char) nLen;
   
   return ((unsigned char *) pDst);
} /* CapiUt_EnterString */
    




/*
        enter the called party number at specified position
        ---------------------------------------------------
*/

unsigned char *CapiUt_EnterCalledPartyNumber
   (unsigned char *pOrgPos,
    const char    *pszNumber)
{
   char   *pDst = (char *) pOrgPos + 1;
   size_t  nLen = 0;
   
   /* check if a number is really specified */
   if (! pszNumber || ! pszNumber [0])
   {
      return (CapiUt_EnterEmptyStruct (pOrgPos));
   }
   
   /* the first byte is the type of number and numbering plan */
   *(pDst++) = 0x80;
   nLen++;
   
   /* copy the number string */
   while (*pszNumber)
   {
      *(pDst++) = *(pszNumber++);
      nLen++;
   }
   
   /* set the total length of the CAPI structure */
   *pOrgPos = (unsigned char) nLen;
   
   return ((unsigned char *) pDst);
} /* CapiUt_EnterCalledPartyNumber */
    




/*
        enter the calling party number at specified position
        ----------------------------------------------------
*/

unsigned char *CapiUt_EnterCallingPartyNumber
   (unsigned char *pOrgPos,
    const char    *pszNumber)
{
   char   *pDst = (char *) pOrgPos + 1;
   size_t  nLen = 0;
   
   /* check if a number is really specified */
   if (! pszNumber || ! pszNumber [0])
   {
      return (CapiUt_EnterEmptyStruct (pOrgPos));
   }
   
   /* the first byte is the type of number and numbering plan, the second is
    * the presentation and screening indicator
    */
   *(pDst++) = 0x0;
   *(pDst++) = 0x80;
   nLen += 2;
   
   /* copy the number string */
   while (*pszNumber)
   {
      *(pDst++) = *(pszNumber++);
      nLen++;
   }
   
   /* set the total length of the CAPI structure */
   *pOrgPos = (unsigned char) nLen;
   
   return ((unsigned char *) pDst);
} /* CapiUt_EnterCallingPartyNumber */





/* === definition of private functions =================================== */





