Ethereal-dev: Re: [Ethereal-dev] packet-skinny.c modifications

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Paul E. Erkkila" <pee@xxxxxxxxxxx>
Date: Tue, 19 Mar 2002 03:18:20 -0500

Thanks, I've integrated what i could quickly into my current working
version (attached).

I think i finally grok the add_item/add_* versions :p, i'll fix
those soon hehehe

automake 1.5 wasn't able to deal with the cvs repository, 1.6
had no problems.

-pee

Guy Harris wrote:
I've checked in changes to do desegmentation of SCCP messages; if TCP
desegmentation and SCCP desegmentation are both enabled (TCP
desegmentation is off by default; SCCP desegmentation is on by default),
SCCP packets split across TCP segment boundaries will be reassembled.

I also made it put items into the protocol tree as soon as they are
fetched, so that if some of those items are past the end of the tvbuff,
earlier items still get put into the protocol tree.

It appears that, in at least one capture I have, a RegisterMessage has
only 40 bytes of data, so the last two fields in the message don't exist
(the desegmentation code constructs a tvbuff for each PDU, so if the
dissector runs past the end of the length in the header, an exception is
thrown and a "Malformed Packet" item is put in the tree).

_______________________________________________
Ethereal-dev mailing list
Ethereal-dev@xxxxxxxxxxxx
http://www.ethereal.com/mailman/listinfo/ethereal-dev


/* packet-skinny.c
 *
 *
 *
 * Dissector for the Skinny Client Control Protocol
 *   (The "D-Channel"-Protocol for Cisco Systems' IP-Phones)
 * Copyright 2001, Joerg Mayer (email: see AUTHORS file)
 *
 *
 * Further decode work by pee@xxxxxxxxxxxxxxx Paul E. Erkkila
 *
 * This file is based on packet-aim.c, which is
 * Copyright 2000, Ralf Hoelzer <ralf@xxxxxxxx>
 *
 * $Id: packet-skinny.c,v 1.9 2002/01/21 23:35:32 guy Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* This implementation is based on a draft version of the 3.0
 * specification
 */


#include "packet-skinny.h"


/* Dissect a single SCCP PDU (skinny) */
static void dissect_skinny_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{

  /* Header fields */
  guint32 hdr_data_length;
  guint32 hdr_reserved;
  guint32 data_messageid;
  gchar   *messageid_str;
  gchar   *deviceTypeStr;

  guint32 offset = 0;

  guint32 callIdentifier = 0;
  guint32 timeStamp = 0;
  guint32 ipSrc = 0;
  guint32 ipDest = 0;
  guint32 destPort = 0;
  guint32 srcPort = 0;
  guint32 softKeyNumber = 0;
  guint32 line = 0;
  guint32 dialedDigit = 0;

  guint32 unknown1 = 0;
  guint32 unknown2 = 0;
  guint32 unknown3 = 0;
  guint32 unknown4 = 0;
  guint32 unknown5 = 0;
  guint32 unknown6 = 0;
  guint32 unknown7 = 0;
  guint32 unknown8 = 0;
  guint32 unknown9 = 0;
  guint32 unknown10 = 0;
  guint32 unknown11 = 0;

  int extensionLength = 10;
  int displayLength   = 100;
  char extension[extensionLength];
  char displayMessage[displayLength];
  int i = 0;
  int j = 0;

  /* Structs used to decode messages , 1 per message */
  struct StationRegisterMessage stationRegisterM;
  struct StationIpPortMessage stationIpPortM;
  struct StationKeypadButtonMessage stationKeypadButtonM;
  struct StationEnblocCallMessage stationEnblocCallM;
  struct StationStimulusMessage stationStimulusM;
  struct StationForwardStatReqMessage stationForwardStatReqM;
  struct StationSpeedDialStatReqMessage stationSpeedDialStatReqM;
  struct StationLineStatReqMessage stationLineStatReqM;
  struct StationCapabilitiesRes stationCapabilitiesRes;
  struct StationAlarmMessage stationAlarmM;
  struct StationMulticastMediaReceptionAckMessage stationMcastMediaReceptionAckM;
  struct StationOpenReceiveChannelAckMessage stationORCAckM;
  struct StationConnectionStatisticsResMessage stationConnectionStatisticsResM;
  struct StationSoftKeyEventMessage stationSKEM;
  struct StationRegisterAckMessage stationRAM;
  struct StationButtonTemplateMessage stationBTM;
  struct StationSoftKeyTemplateResMessage stationSKTRM;
  struct StationSoftKeySetResMessage stationSKSRM;
  struct StationSelectSoftKeysMessage stationSSKM;
  struct StationSetLampMessage stationSLM;
  struct StationDisplayPromptStatusMessage stationDPSM;
  struct StationLineStatMessage stationLSM;
  struct StationSpeedDialStatMessage stationSDSM;
  struct StationDefineTimeDateMessage stationDTDM;

  /* Set up structures we will need to add the protocol subtree and manage it */
  proto_item *ti;
  proto_tree *skinny_tree = NULL;
  
  proto_item *skm = NULL;
  proto_item *skm_tree = NULL;
  
  
  hdr_data_length = tvb_get_letohl(tvb, offset);
  hdr_reserved    = tvb_get_letohl(tvb, offset+4);
  data_messageid  = tvb_get_letohl(tvb, offset+8);
  
  /* In the interest of speed, if "tree" is NULL, don't do any work not
   * necessary to generate protocol tree items. */
  if (tree) {
    ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, FALSE); 
    skinny_tree = proto_item_add_subtree(ti, ett_skinny);
    proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset, 4, hdr_data_length);  
    proto_tree_add_uint(skinny_tree, hf_skinny_reserved, tvb, offset+4, 4, hdr_reserved);
  }
  
  messageid_str = val_to_str(data_messageid, message_id, "0x%08X (Unknown)");
  
  if (check_col(pinfo->cinfo, COL_INFO)) {
    col_add_str(pinfo->cinfo, COL_INFO, messageid_str);
  }
  
  if (tree) {
    proto_tree_add_uint(skinny_tree, hf_skinny_messageid, tvb,offset+8, 4, data_messageid );
  }
  
  if (tree) {
    switch(data_messageid) {
      
      /* cases that do not need to be decoded */
    case 0x0 :    /* keepAlive */
      break;
      
    case 0x6 :    /* offHook */
      break;
      
    case 0x7 :    /* onHook    */
      break;
      
    case 0x8 :    /* hookFlash */
      break;
      
    case 0xc :    /* configStateReqMessage */
      break;
      
    case 0xd :    /* timeDateReqMessage */
      break;
      
    case 0xe :    /* buttoneTemplateReqMessage */
      break;
      
    case 0xf :    /* stationVersionReqMessage */
      break;
      
    case 0x12 :   /* stationServerReqMessage */
      break;
      
    case 0x25 :   /* softKeySetReqMessage */
      break;
      
    case 0x27 :   /* unregisterMessage */
      break;
      
    case 0x28 :   /* softKeyTemplateRequest */
      break;
      
    case 0x83 :   /* stopTone */
      break;
      
    case 0x9b :   /* capabilitiesReqMessage */
      break;
      
    case 0x100 :    /* keepAliveAck */
      break;
      
      /*
      ** cases that need decode
      **
      */
      
      
    case 0x1 :   /* register message */
      
      memset(&stationRegisterM,0,sizeof(struct StationRegisterMessage));
      tvb_memcpy(tvb,(guint8 *)&stationRegisterM,offset+8,sizeof(struct StationRegisterMessage));
      
      proto_tree_add_string(skinny_tree, hf_skinny_deviceName, tvb, offset+12, StationMaxDeviceNameSize, stationRegisterM.sid.DeviceName );
      proto_tree_add_uint(skinny_tree, hf_skinny_stationUserId, tvb, offset+28, 4, stationRegisterM.sid.reserved_for_future_use );
      proto_tree_add_uint(skinny_tree, hf_skinny_stationInstance, tvb, offset+32, 4, stationRegisterM.sid.instance );
      proto_tree_add_ipv4(skinny_tree, hf_skinny_ipSrc, tvb, offset+36, 4, stationRegisterM.stationIpAddr );
      proto_tree_add_uint(skinny_tree, hf_skinny_deviceType, tvb, offset+40, 4, stationRegisterM.deviceType );
      proto_tree_add_uint(skinny_tree, hf_skinny_maxStreams, tvb, offset+44, 4, stationRegisterM.maxStreams );
      break;
      
    case 0x2 :  /* ipPortMessage */
      
      memset(&stationIpPortM,0,sizeof(struct StationIpPortMessage));
      tvb_memcpy(tvb, (guint8 *)&stationIpPortM, offset+8, sizeof(struct StationIpPortMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_stationIpPort, tvb, offset+12, 4, pntohs(&stationIpPortM.stationIpPort));
      break;
      
    case 0x3 :  /* keyPadButtonMessage */
      
      memset(&stationKeypadButtonM,0,sizeof(struct StationKeypadButtonMessage));
      tvb_memcpy(tvb, (guint8 *)&stationKeypadButtonM, offset+8, sizeof(struct StationKeypadButtonMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_stationKeypadButton, tvb, offset+12, 4, stationKeypadButtonM.kpButton);
      break;
      
    case 0x4 :  /* stationEnblocCallMessage -- This decode NOT verified*/
      
      memset(&stationEnblocCallM,0,sizeof(struct StationEnblocCallMessage));
      tvb_memcpy(tvb, (guint8 *)&stationEnblocCallM, offset+8, sizeof(struct StationEnblocCallMessage));
      
      proto_tree_add_string(skinny_tree, hf_skinny_calledParty, tvb, offset+12, StationMaxDirnumSize, stationEnblocCallM.calledParty);
      break;
      
    case 0x5 : /* stationStimulusMessage */
      
      memset(&stationStimulusM,0,sizeof(struct StationStimulusMessage));
      tvb_memcpy(tvb, (guint8 *)&stationStimulusM, offset+8, sizeof(struct StationStimulusMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_stimulus, tvb, offset+12, 4, stationStimulusM.stimulus);
      proto_tree_add_uint(skinny_tree, hf_skinny_stimulusInstance, tvb, offset+16, 4, stationStimulusM.stimulusInstance);
      break;
      
    case 0x9  : /* stationForwardStatReqMessage */
      
      memset(&stationForwardStatReqM, 0, sizeof(struct StationForwardStatReqMessage));
      tvb_memcpy(tvb, (guint8 *)&stationForwardStatReqM, offset+8, sizeof(struct StationForwardStatReqMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_lineNumber, tvb, offset+12, 4, stationForwardStatReqM.lineNumber);
      break;
      
    case 0xa :  /* speedDialStatReqMessage */
      memset(&stationSpeedDialStatReqM, 0, sizeof(struct StationSpeedDialStatReqMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSpeedDialStatReqM, offset+8, sizeof(struct StationSpeedDialStatReqMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_speedDialNumber, tvb, offset+12, 4, stationSpeedDialStatReqM.speedDialNumber);
      break;
      
    case 0xb :  /* LineStatReqMessage */
      
      memset(&stationLineStatReqM, 0, sizeof(struct StationLineStatReqMessage));
      tvb_memcpy(tvb, (guint8 *)&stationLineStatReqM, offset+8, sizeof(struct StationLineStatReqMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_lineNumber, tvb, offset+12, 4, stationLineStatReqM.lineNumber);
      break;
      
      
      
    case 0x10 :  /* capabilitiesResMessage  - VERIFIED AS IS*/
      /* FIXME -- we are only going to decode the first 7 protocol fields for now cuz that's all it sent me
       * on the phone i was working with. I should probably skip the struct decode and use a more piece
       * type method using the capCount definition to control the decode loop
       *
       * basically changing StationMaxCapabilities definition
       *
       */	
      memset(&stationCapabilitiesRes, 0, sizeof(struct StationCapabilitiesRes));
      tvb_memcpy(tvb, (guint8 *)&stationCapabilitiesRes, offset+8, sizeof(struct StationCapabilitiesRes));
      
      
      /* printf("%d\n",sizeof(struct StationCapabilitiesRes));
       * printf("CapCount was %d\n", stationCapabilitiesRes.capCount);
       */
      proto_tree_add_uint(skinny_tree, hf_skinny_capCount, tvb, offset+12, 4, stationCapabilitiesRes.capCount);
      for (i = 0; i < stationCapabilitiesRes.capCount; i++) {
	proto_tree_add_item(skinny_tree, hf_skinny_payloadCapability, tvb, offset+(i*16)+16, 4, stationCapabilitiesRes.caps[i].payloadCapability);
	proto_tree_add_item(skinny_tree, hf_skinny_maxFramesPerPacket, tvb, offset+(i*16)+20, 4, stationCapabilitiesRes.caps[i].maxFramesPerPacket);
	/* FIXME -- decode the union under here as required, is always 0 on my equipment */
      }
      break;
      
      
    case 0x20 :   /* stationAlarmMessage */
      
      memset(&stationAlarmM, 0, sizeof(struct StationAlarmMessage));
      tvb_memcpy(tvb, (guint8 *)&stationAlarmM, offset+8, sizeof(struct StationAlarmMessage));
      
      proto_tree_add_item(skinny_tree, hf_skinny_alarmSeverity, tvb, offset+12, 4, stationAlarmM.alarmSeverity);
      proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, 80, stationAlarmM.text);
      proto_tree_add_uint(skinny_tree, hf_skinny_alarmParam1, tvb, offset+96, 4, stationAlarmM.parm1);
      proto_tree_add_ipv4(skinny_tree, hf_skinny_alarmParam2, tvb, offset+100, 4, stationAlarmM.parm2);
      break;
      
    case 0x21 : /* stationMulticastMediaReceptionAck - This decode NOT verified*/
      
      memset(&stationMcastMediaReceptionAckM, 0, sizeof(struct StationMulticastMediaReceptionAckMessage));
      tvb_memcpy(tvb, (guint8 *)&stationMcastMediaReceptionAckM, offset+8, sizeof(struct StationMulticastMediaReceptionAckMessage));
      
      proto_tree_add_item(skinny_tree, hf_skinny_receptionStatus, tvb, offset+12, 4, stationMcastMediaReceptionAckM.receptionStatus);
      proto_tree_add_uint(skinny_tree, hf_skinny_passThruPartyID, tvb, offset+16, 4, stationMcastMediaReceptionAckM.passThruPartyID);
      break;
      
    case 0x22 : /* stationOpenReceiveChannelAck */
      
      memset(&stationORCAckM, 0, sizeof(struct StationOpenReceiveChannelAckMessage));
      tvb_memcpy(tvb, (guint8 *)&stationORCAckM, offset+8, sizeof(struct StationOpenReceiveChannelAckMessage));
      
      proto_tree_add_item(skinny_tree, hf_skinny_ORCStatus, tvb, offset+12, 4, stationORCAckM.orcStatus);
      proto_tree_add_ipv4(skinny_tree, hf_skinny_ipAddress,   tvb, offset+16, 4, stationORCAckM.ipAddr);
      proto_tree_add_uint(skinny_tree, hf_skinny_portNumber, tvb, offset+20, 4, stationORCAckM.portNumber);
      proto_tree_add_uint(skinny_tree, hf_skinny_passThruPartyID, tvb, offset+24, 4, stationORCAckM.passThruPartyID);
      break;	
      
    case 0x23    :  /* stationConnectionStatisticsRes */
      
      memset(&stationConnectionStatisticsResM, 0, sizeof(struct StationConnectionStatisticsResMessage));
      tvb_memcpy(tvb, (guint8 *)&stationConnectionStatisticsResM, offset+8, sizeof(struct StationConnectionStatisticsResMessage));
      
      proto_tree_add_string(skinny_tree, hf_skinny_directoryNumber, tvb, offset+12, StationMaxDirnumSize, stationConnectionStatisticsResM.directoryNum);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+36, 4, stationConnectionStatisticsResM.callIdentifier);
      proto_tree_add_item(skinny_tree, hf_skinny_statsProcessingType, tvb, offset+40, 4, stationConnectionStatisticsResM.statsProcessingMode);
      proto_tree_add_uint(skinny_tree, hf_skinny_packetsSent, tvb, offset+44, 4, stationConnectionStatisticsResM.numberPacketsSent);
      proto_tree_add_uint(skinny_tree, hf_skinny_octetsSent, tvb, offset+48, 4, stationConnectionStatisticsResM.numberOctetsSent);
      proto_tree_add_uint(skinny_tree, hf_skinny_packetsRecv, tvb, offset+52, 4, stationConnectionStatisticsResM.numberPacketsReceived);
      proto_tree_add_uint(skinny_tree, hf_skinny_octetsRecv, tvb, offset+56, 4, stationConnectionStatisticsResM.numberOctetsReceived);
      proto_tree_add_uint(skinny_tree, hf_skinny_packetsLost, tvb, offset+60, 4, stationConnectionStatisticsResM.numberPacketsLost);
      proto_tree_add_uint(skinny_tree, hf_skinny_jitter, tvb, offset+64, 4, stationConnectionStatisticsResM.jitter);
      proto_tree_add_uint(skinny_tree, hf_skinny_latency, tvb, offset+68, 4, stationConnectionStatisticsResM.latency);
      break;
      
    case 0x26 :  /* softKeyEventMessage */
      
      memset(&stationSKEM, 0, sizeof(struct StationSoftKeyEventMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSKEM, offset+8, sizeof(struct StationSoftKeyEventMessage));
      
      proto_tree_add_item(skinny_tree, hf_skinny_softKeyEvent, tvb, offset+12, 4, stationSKEM.softKeyEvent);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, stationSKEM.lineInstance);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+20, 4, stationSKEM.callReference);
      break;
      
      /*
       *
       * message not in the spec
       *
       */
    case 0x2b :  /* unknownClientMessage1 */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
    case 0x2d :  /* unknownClientMessage2 */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
      /* 
       *
       *  Call manager -> client messages start here(ish)
       *
       */
    case 0x81 :  /* registerAck */
      
      memset(&stationRAM, 0, sizeof(struct StationRegisterAckMessage));
      tvb_memcpy(tvb, (guint8 *)&stationRAM, offset+8, sizeof(struct StationRegisterAckMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_keepAliveInterval, tvb, offset+12, 4, stationRAM.keepAliveInterval);
      proto_tree_add_string(skinny_tree, hf_skinny_dateTemplate, tvb, offset+16, StationDateTemplateSize, stationRAM.dateTemplate);
      proto_tree_add_uint(skinny_tree, hf_skinny_secondaryKeepAliveInterval, tvb, offset+24, 4, stationRAM.secondaryKeepAliveInterval);
      break;
      
    case 0x82 :  /* startTone */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
    case 0x85 : /* setRingerMessage */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
    case 0x86 : /* setLampMessage */
      
      memset(&stationSLM, 0, sizeof(struct StationSetLampMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSLM, offset+8, sizeof(struct StationSetLampMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_stimulus, tvb, offset+12, 4, stationSLM.stimulus);
      proto_tree_add_uint(skinny_tree, hf_skinny_stimulusInstance, tvb, offset+16, 4, stationSLM.stimulusInstance);
      proto_tree_add_uint(skinny_tree, hf_skinny_lampMode, tvb, offset+20, 4, stationSLM.lampMode);
      break;
      
    case 0x88 : /* setSpeakerModeMessage */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
    case 0x8a :
      unknown1  = tvb_get_letohl(tvb, offset+12);
      unknown2  = tvb_get_letohl(tvb, offset+16);
      tvb_memcpy(tvb, (guint8 *)&ipDest, offset+20,4);
      destPort  = tvb_get_letohl(tvb, offset+24);
      unknown5  = tvb_get_letohl(tvb, offset+28);
      unknown6  = tvb_get_letohl(tvb, offset+32);
      unknown7  = tvb_get_letohl(tvb, offset+36);
      unknown8  = tvb_get_letohl(tvb, offset+40);
      unknown9  = tvb_get_letohl(tvb, offset+44);
      unknown10 = tvb_get_letohl(tvb, offset+48);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
      proto_tree_add_ipv4(skinny_tree, hf_skinny_ipDest,   tvb, offset+20, 4, ipDest);
      proto_tree_add_uint(skinny_tree, hf_skinny_destPort,tvb, offset+24, 4, destPort);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+28, 4, unknown5);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown6);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown7);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+40, 4, unknown8);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown9);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+48, 4, unknown10);
      break;
      
    case 0x8b :  /* stopMediaTransmission */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      unknown2 = tvb_get_letohl(tvb, offset+16);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
      break;
      
    case 0x91 : /* speedDialStatMessage */
      
      memset(&stationSDSM, 0, sizeof(struct StationSpeedDialStatMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSDSM, offset+8, sizeof(struct StationSpeedDialStatMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_speedDialNumber, tvb, offset+12, 4, stationSDSM.speedDialNumber);
      proto_tree_add_string(skinny_tree, hf_skinny_speedDialDirNumber, tvb, offset+16, StationMaxDirnumSize, stationSDSM.speedDialDirNumber);
      proto_tree_add_string(skinny_tree, hf_skinny_speedDialDisplayName, tvb, offset+16, StationMaxNameSize, stationSDSM.speedDialDisplayName);
      break;
      
    case 0x92 : /* lineStatMessage */
      memset(&stationLSM, 0, sizeof(struct StationLineStatMessage));
      tvb_memcpy(tvb, (guint8 *)&stationLSM, offset+8, sizeof(struct StationLineStatMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_lineNumber, tvb, offset+12, 4, stationLSM.lineNumber);
      proto_tree_add_string(skinny_tree, hf_skinny_lineDirNumber, tvb, offset+16, StationMaxDirnumSize, stationLSM.lineDirNumber);
      proto_tree_add_string(skinny_tree, hf_skinny_lineFullyQualifiedDisplayName, tvb, offset+16+StationMaxDirnumSize, StationMaxNameSize, stationLSM.lineFullyQualifiedDisplayName);
      break;
      
    case 0x94 : /* stationDefineTimeDate */
      
      memset(&stationDTDM, 0, sizeof(struct StationDefineTimeDateMessage));
      tvb_memcpy(tvb, (guint8 *)&stationDTDM, offset+8, sizeof(struct StationDefineTimeDateMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_dateYear,  tvb, offset+12, 4, stationDTDM.year);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateMonth, tvb, offset+16, 4, stationDTDM.month);
      proto_tree_add_uint(skinny_tree, hf_skinny_dayOfWeek,   tvb, offset+20, 4, stationDTDM.dayOfWeek);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateDay,   tvb, offset+24, 4, stationDTDM.day);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateHour,  tvb, offset+28, 4, stationDTDM.hour);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateMinute,tvb, offset+32, 4, stationDTDM.minute);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateSeconds,   tvb, offset+36, 4, stationDTDM.seconds);
      proto_tree_add_uint(skinny_tree, hf_skinny_dateMilliseconds,   tvb, offset+40, 4, stationDTDM.milliseconds);
      proto_tree_add_uint(skinny_tree, hf_skinny_timeStamp, tvb, offset+44, 4, stationDTDM.systemTime);
      break;
      
      
    case 0x97 :  /* buttonTemplateMessage  */
      /*
       * FIXME
       * This decode prints out oogly subtree maybe? or something besides the VALS...
       * note to self: uint8 != 4 kk thx info ^_^
       *
       */
      memset(&stationBTM, 0, sizeof(struct StationButtonTemplateMessage));
      tvb_memcpy(tvb, (guint8 *)&stationBTM, offset+8, sizeof(struct StationButtonTemplateMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_buttonOffset, tvb, offset+12, 4, stationBTM.buttonTemplate.buttonOffset);
      proto_tree_add_uint(skinny_tree, hf_skinny_buttonCount,  tvb, offset+16, 4, stationBTM.buttonTemplate.buttonCount);
      proto_tree_add_uint(skinny_tree, hf_skinny_totalButtonCount, tvb, offset+20, 4, stationBTM.buttonTemplate.totalButtonCount);
      for (i = 0; i < StationMaxButtonTemplateSize; i++) {
	proto_tree_add_item(skinny_tree, hf_skinny_buttonInstanceNumber, tvb, offset+(i*2)+24, 1, stationBTM.buttonTemplate.definition[i].instanceNumber);
	proto_tree_add_item(skinny_tree, hf_skinny_buttonDefinition, tvb, offset+(i*2)+25, 1, stationBTM.buttonTemplate.definition[i].buttonDefinition);
      }
      break;
      
    case 0x99 :  /* displayTextMessage */
      memset(displayMessage, '\0', displayLength);
      tvb_memcpy(tvb, displayMessage, offset+12, 32);
      unknown1  = tvb_get_letohl(tvb, offset+44);
      
      proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+12, strlen(displayMessage), displayMessage);	  
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown1);
      break;
      
    case 0x9d : /* stationRegisterReject */
      break;
      
    case 0x9f :   /* reset */
      unknown1  = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
      
    case 0x105 : /* open receive channel */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      unknown2 = tvb_get_letohl(tvb, offset+16);
      unknown3 = tvb_get_letohl(tvb, offset+20);
      unknown4 = tvb_get_letohl(tvb, offset+24);
      unknown5 = tvb_get_letohl(tvb, offset+28);
      unknown6 = tvb_get_letohl(tvb, offset+32);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+24, 4, unknown4);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+28, 4, unknown5);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown6);
      break;

    case 0x106 :  /* closeReceiveChannel */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      unknown2 = tvb_get_letohl(tvb, offset+16);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
      break;      

    case 0x107 :	
      memset(extension, '\0', extensionLength);
      tvb_get_nstringz0(tvb, offset+12, extensionLength, extension);
      callIdentifier = tvb_get_letohl(tvb, offset+36);
      
      proto_tree_add_string(skinny_tree, hf_skinny_extension, tvb, offset+12, strlen(extension), extension);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+36, 4, callIdentifier);
      break;
      
    case 0x108 :   /* softkeyTemplateResMessage */
      
      memset(&stationSKTRM, 0, sizeof(struct StationSoftKeyTemplateResMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSKTRM, offset+8, sizeof(struct StationSoftKeyTemplateResMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_softKeyOffset, tvb, offset+12, 4, stationSKTRM.softKeyTemplate.softKeyOffset);
      proto_tree_add_uint(skinny_tree, hf_skinny_softKeyCount, tvb, offset+16, 4, stationSKTRM.softKeyTemplate.softKeyCount);
      proto_tree_add_uint(skinny_tree, hf_skinny_totalSoftKeyCount, tvb, offset+20, 4, stationSKTRM.softKeyTemplate.totalSoftKeyCount);
      for (i = 0; ((i < StationMaxSoftKeyDefinition) && (i < stationSKTRM.softKeyTemplate.softKeyCount)); i++){
	proto_tree_add_string(skinny_tree, hf_skinny_softKeyLabel, tvb, offset+(i*20)+24, StationMaxSoftKeyLabelSize, stationSKTRM.softKeyTemplate.definition[i].softKeyLabel);
	proto_tree_add_uint(skinny_tree, hf_skinny_softKeyEvent, tvb, offset+(i*20)+40, 4, stationSKTRM.softKeyTemplate.definition[i].softKeyEvent);
      }
      /* there is more data here, but it doesn't make a whole lot of sense, I imagine
       * it's just some not zero'd out stuff in the packet or... 
       */
      break;
      
    case 0x109 : /* softkeysetres */
      memset(&stationSKSRM, 0, sizeof(struct StationSoftKeySetResMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSKSRM, offset+8, sizeof(struct StationSoftKeySetResMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_softKeySetOffset, tvb, offset+12, 4, stationSKSRM.softKeySets.softKeySetOffset);
      proto_tree_add_uint(skinny_tree, hf_skinny_softKeySetCount, tvb, offset+16, 4, stationSKSRM.softKeySets.softKeySetCount);
      proto_tree_add_uint(skinny_tree, hf_skinny_totalSoftKeySetCount, tvb, offset+20, 4, stationSKSRM.softKeySets.totalSoftKeySetCount);
      for (i = 0; ((i < StationMaxSoftKeySetDefinition) && (i < stationSKSRM.softKeySets.softKeySetCount)); i++) {
	proto_tree_add_uint(skinny_tree, hf_skinny_softKeySetDescription, tvb, offset+(i*20)+24+j,1,i);
	for (j = 0; j < StationMaxSoftKeyIndex; j++) {
	  proto_tree_add_uint(skinny_tree, hf_skinny_softKeyTemplateIndex, tvb, offset+(i*20)+24+j, 1, stationSKSRM.softKeySets.definition[i].softKeyTemplateIndex[j]);
	}
	for (j = 0; j < StationMaxSoftKeyIndex; j++) {
	  proto_tree_add_uint(skinny_tree, hf_skinny_softKeyInfoIndex, tvb, offset+(i*20)+25+(j*2), 2, stationSKSRM.softKeySets.definition[i].softKeyInfoIndex[j]);
	}
      }
      break;
      
    case 0x110 : /* selectSoftKeys */
      
      memset(&stationSSKM, 0, sizeof(struct StationSelectSoftKeysMessage));
      tvb_memcpy(tvb, (guint8 *)&stationSSKM, offset+8, sizeof(struct StationSelectSoftKeysMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_lineInstance, tvb, offset+12, 4, stationSSKM.instance);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+16, 4, stationSSKM.reference);
      proto_tree_add_uint(skinny_tree, hf_skinny_softKeySetDescription, tvb, offset+20, 4, stationSSKM.softKeySetIndex);
      skm = proto_tree_add_uint_format(skinny_tree, hf_skinny_softKeyMap, tvb, offset + 24, 1, stationSSKM.validKeyMask, "SoftKeyMap: 0x%04x",stationSSKM.validKeyMask);
      skm_tree = proto_item_add_subtree(skm, ett_skinny_softKeyMap);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey0,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey1,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey2,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey3,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey4,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey5,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey6,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey7,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey8,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey9,  tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey10, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey11, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey12, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey13, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey14, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      proto_tree_add_boolean(skm_tree, hf_skinny_softKey15, tvb, offset + 24, 1, stationSSKM.validKeyMask);
      
      break;
      
    case 0x111 : /* callState */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      unknown2 = tvb_get_letohl(tvb, offset+16);
      callIdentifier = tvb_get_letohl(tvb, offset+20);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+20, 4, callIdentifier);
      break;
      
    case 0x112 :
      
      memset(&stationDPSM, 0, sizeof(struct StationDisplayPromptStatusMessage));
      tvb_memcpy(tvb, (guint8 *)&stationDPSM, offset+8, sizeof(struct StationDisplayPromptStatusMessage));
      
      proto_tree_add_uint(skinny_tree, hf_skinny_messageTimeOutValue, tvb, offset+12, 4, stationDPSM.timeOutValue);
      proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, StationMaxDisplayPromptStatusSize , stationDPSM.promptStatus);
      proto_tree_add_uint(skinny_tree, hf_skinny_lineInstance, tvb, offset+48, 4, stationDPSM.lineInstance);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+52, 4, stationDPSM.callReference);
      break;
      
    case 0x113:
      callIdentifier = tvb_get_letohl(tvb, offset+16);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+16, 4, callIdentifier);
      break;
      
    case 0x114 :
      
      unknown1 = tvb_get_letohl(tvb, offset+12);
      memset(displayMessage,'\0',displayLength);
      tvb_memcpy(tvb, displayMessage, offset+16, 16);
      unknown2 = tvb_get_letohl(tvb, offset+32);
      unknown3 = tvb_get_letohl(tvb, offset+36);
      unknown4 = tvb_get_letohl(tvb, offset+40);
      unknown5 = tvb_get_letohl(tvb, offset+44);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, strlen(displayMessage), displayMessage);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown2);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown3);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+40, 4, unknown4);
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown5);
      break;
      
    case 0x116 :
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
    case 0x118 :    /* unregisterAckMessage */
      unknown1 = tvb_get_letohl(tvb, offset+12);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
      break;
      
      
      
    case 0x11D :
      unknown1       = tvb_get_letohl(tvb, offset+36);
      callIdentifier = tvb_get_letohl(tvb, offset+40);
      
      proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown1);
      proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+40, 4, callIdentifier);
      break;
      
      
    default:
      break;
    }
  }
}
/* Code to actually dissect the packets */
static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
  /* The general structure of a packet: {IP-Header|TCP-Header|n*SKINNY}
   * SKINNY-Packet: {Header(Size, Reserved)|Data(MessageID, Message-Data)}
   */
  
  volatile int offset = 0;
  int length_remaining;
  int length;
  tvbuff_t *next_tvb;

  /* Header fields */
  volatile guint32 hdr_data_length;
  guint32 hdr_reserved;

  /* check, if this is really an SKINNY packet, they start with a length + 0 */
  
  /* get relevant header information */
  hdr_data_length = tvb_get_letohl(tvb, 0);
  hdr_reserved    = tvb_get_letohl(tvb, 4);

  /*  data_size       = MIN(8+hdr_data_length, tvb_length(tvb)) - 0xC; */
  
  /* hdr_data_length > 1024 is just a heuristic. Better values/checks welcome */
  if (hdr_data_length < 4 || hdr_data_length > 1024 || hdr_reserved != 0) {
    /* Not an SKINNY packet, just happened to use the same port */
    call_dissector(data_handle,tvb, pinfo, tree);
    return;
  }
  
  /* Make entries in Protocol column and Info column on summary display */
  if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY");
  }
  
  if (check_col(pinfo->cinfo, COL_INFO)) {
    col_set_str(pinfo->cinfo, COL_INFO, "Skinny Client Control Protocol");
  }
  
  while (tvb_reported_length_remaining(tvb, offset) != 0) {
    length_remaining = tvb_length_remaining(tvb, offset);

    /*
     * Can we do reassembly?
     */
    if (skinny_desegment && pinfo->can_desegment) {
      /*
       * Yes - is the length field in the SCCP header split across
       * segment boundaries?
       */
      if (length_remaining < 4) {
	/*
	 * Yes.  Tell the TCP dissector where the data for this message
	 * starts in the data it handed us, and how many more bytes we
	 * need, and return.
	 */
	pinfo->desegment_offset = offset;
	pinfo->desegment_len = 4 - length_remaining;
	return;
      }
    }

    /*
     * Get the length of the SCCP packet.
     */
    hdr_data_length = tvb_get_letohl(tvb, offset);

    /*
     * Can we do reassembly?
     */
    if (skinny_desegment && pinfo->can_desegment) {
      /*
       * Yes - is the SCCP packet split across segment boundaries?
       */
      if ((guint32)length_remaining < hdr_data_length + 8) {
	/*
	 * Yes.  Tell the TCP dissector where the data for this message
	 * starts in the data it handed us, and how many more bytes we
	 * need, and return.
	 */
	pinfo->desegment_offset = offset;
	pinfo->desegment_len = (hdr_data_length + 8) - length_remaining;
	return;
      }
    }

    /*
     * Construct a tvbuff containing the amount of the payload we have
     * available.  Make its reported length the amount of data in the
     * SCCP packet.
     *
     * XXX - if reassembly isn't enabled. the subdissector will throw a
     * BoundsError exception, rather than a ReportedBoundsError exception.
     * We really want a tvbuff where the length is "length", the reported
     * length is "hdr_data_length + 8", and the "if the snapshot length
     * were infinite" length is the minimum of the reported length of
     * the tvbuff handed to us and "hdr_data_length + 8", with a new type
     * of exception thrown if the offset is within the reported length but
     * beyond that third length, with that exception getting the
     * "Unreassembled Packet" error.
     */
    length = length_remaining;
    if ((guint32)length > hdr_data_length + 8)
      length = hdr_data_length + 8;
    next_tvb = tvb_new_subset(tvb, offset, length, hdr_data_length + 8);

    /*
     * Dissect the SCCP packet.
     *
     * Catch the ReportedBoundsError exception; if this particular message
     * happens to get a ReportedBoundsError exception, that doesn't mean
     * that we should stop dissecting SCCP messages within this frame or
     * chunk of reassembled data.
     *
     * If it gets a BoundsError, we can stop, as there's nothing more to
     * see, so we just re-throw it.
     */
    TRY {
      dissect_skinny_pdu(next_tvb, pinfo, tree);
    }
    CATCH(BoundsError) {
      RETHROW;
    }
    CATCH(ReportedBoundsError) {
      show_reported_bounds_error(tvb, pinfo, tree);
    }
    ENDTRY;

    /*
     * Skip the SCCP header and the payload.
     */
    offset += hdr_data_length + 8;
  }
}



/* Register the protocol with Ethereal */
void 
proto_register_skinny(void)
{                 
  
  /* Setup list of header fields */
  static hf_register_info hf[] = {
    { &hf_skinny_data_length,
      { "Data Length", "skinny.data_length",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Number of bytes in the data portion.",
	HFILL }
    },
    { &hf_skinny_reserved,
      { "Reserved", "skinny.reserved",
	FT_UINT32, BASE_HEX, NULL, 0x0,
	"Reserved for furture(?) use.",
	HFILL }
    },
    /* FIXME: Enable use of message name ???  */
    { &hf_skinny_messageid,
      { "Message ID", "skinny.messageid",
	FT_UINT32, BASE_HEX, VALS(message_id), 0x0,
	"The function requested/done with this message.",
	HFILL }
    },

    { &hf_skinny_deviceName,
      { "DeviceName", "skinny.deviceName",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The device name of the phone.",
	HFILL }
    },

    { &hf_skinny_stationUserId,
      { "StationUserId", "skinny.stationUserId",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The station user id.",
	HFILL }
    },

    { &hf_skinny_stationInstance,
      { "StationInstance", "skinny.stationInstance",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The stations instance.",
	HFILL }
    },

    { &hf_skinny_deviceType,
      { "DeviceType", "skinny.deviceType",
	FT_UINT32, BASE_DEC, VALS(deviceTypes), 0x0,
	"DeviceType of the station.",
	HFILL }
    },

    { &hf_skinny_maxStreams,
      { "MaxStreams", "skinny.maxStreams",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"32 bit unsigned integer indicating the maximum number of simultansous RTP duplex streams that the client can handle.",
	HFILL }
    },

    { &hf_skinny_stationIpPort,
      { "StationIpPort", "skinny.stationIpPort",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The station ip port",
	HFILL }
    },

    { &hf_skinny_stationKeypadButton,
      { "KeypadButton", "skinny.stationKeypadButton",
	FT_UINT32, BASE_HEX, VALS(keypadButtons), 0x0,
	"The button pressed on the phone.",
	HFILL }
    },

    { &hf_skinny_calledParty,
      { "CalledParty", "skinny.calledParty",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The number called.",
	HFILL }
    },

    { &hf_skinny_stimulus,
      { "Stimulus", "skinny.stimulus",
	FT_UINT32, BASE_HEX, VALS(deviceStimuli), 0x0,
	"Reason for the device stimulus message.",
	HFILL }
    },

    { &hf_skinny_stimulusInstance,
      { "StimulusInstance", "skinny.stimulusInstance",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The instance of the stimulus",
	HFILL }
    },

    { &hf_skinny_lineNumber,
      { "LineNumber", "skinny.lineNumber",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"linenumber",
	HFILL }
    },

    { &hf_skinny_speedDialNumber,
      { "SpeedDialNumber", "skinny.speedDialNumber",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"which speed dial number",
	HFILL }
    },

    { &hf_skinny_capCount,
      { "CapCount", "skinny.capCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"how many  caps",
	HFILL }
    },

    { &hf_skinny_payloadCapability,
      { "PayloadCapability", "skinny.payloadCapability",
	FT_UINT32, BASE_DEC, VALS(mediaPayloads), 0x0,
	"The payload capability for this media capability structure.",
	HFILL }
    },

    { &hf_skinny_maxFramesPerPacket,
      { "MaxFramesPerPacket", "skinny.maxFramesPerPacket",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"max frames per packet ",
	HFILL }
    },

    { &hf_skinny_alarmSeverity,
      { "AlarmSeverity", "skinny.alarmSeverity",
	FT_UINT32, BASE_DEC, VALS(alarmSeverities), 0x0,
	"The severity of the reported alarm.",
	HFILL }
    },

    { &hf_skinny_alarmParam1,
      { "AlarmParam1", "skinny.alarmParam1",
	FT_UINT32, BASE_HEX, NULL, 0x0,
	"An as yet undecoded param1 value from the alarm message",
	HFILL }
    },

    { &hf_skinny_alarmParam2,
      { "AlarmParam2", "skinny.alarmParam2",
	FT_IPv4, BASE_NONE, NULL, 0x0,
	"This is the second alarm parameter i think it's an ip address",
	HFILL }
    },

    { &hf_skinny_receptionStatus,
      { "ReceptionStatus", "skinny.receptionStatus",
	FT_UINT32, BASE_DEC, VALS(multicastMediaReceptionStatus), 0x0,
	"The current status of the multicast media.",
	HFILL }
    },

    { &hf_skinny_passThruPartyID,
      { "PassThruPartyID", "skinny.passThruPartyID",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The pass thru party id",
	HFILL }
    },

    { &hf_skinny_ORCStatus,
      { "OpenReceiveChannelStatus", "skinny.openReceiveChannelStatus",
	FT_UINT32, BASE_DEC, VALS(openReceiveChanStatus), 0x0,
	"The status of the opened receive channel.",
	HFILL }
    },

    { &hf_skinny_ipAddress,
      { "IP Address", "skinny.ipAddress",
	FT_IPv4, BASE_NONE, NULL, 0x0,
	"An IP address",
	HFILL }
    },

    { &hf_skinny_portNumber,
      { "Port Number", "skinny.portNumber",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"A port number",
	HFILL }
    },

    { &hf_skinny_statsProcessingType,
      { "StatsProcessingType", "skinny.statsProcessingType",
	FT_UINT32, BASE_DEC, VALS(statsProcessingTypes), 0x0,
	"What do do after you send the stats.",
	HFILL }
    },

    { &hf_skinny_callIdentifier,
      { "Call Identifier", "skinny.callIdentifier",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Call identifier for this call.",
	HFILL }
    },

    { &hf_skinny_packetsSent,
      { "Packets Sent", "skinny.packetsSent",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Packets Sent during the call.",
	HFILL }
    },

    { &hf_skinny_octetsSent,
      { "Octets Sent", "skinny.octetsSent",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Octets sent during the call.",
	HFILL }
    },

    { &hf_skinny_packetsRecv,
      { "Packets Received", "skinny.packetsRecv",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Packets received during the call.",
	HFILL }
    },

    { &hf_skinny_octetsRecv,
      { "Octets Received", "skinny.octetsRecv",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Octets received during the call.",
	HFILL }
    },

    { &hf_skinny_packetsLost,
      { "Packets Lost", "skinny.packetsLost",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Packets lost during the call.",
	HFILL }
    },

    { &hf_skinny_latency,
      { "Latency(ms)", "skinny.latency",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Average packet latency during the call.",
	HFILL }
    },

    { &hf_skinny_jitter,
      { "Jitter", "skinny.jitter",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Average jitter during the call.",
	HFILL }
    },

    { &hf_skinny_directoryNumber,
      { "Directory Number", "skinny.directoryNumber",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The number we are reporting statistics for.",
	HFILL }
    },

    { &hf_skinny_lineInstance,
      { "Line Instance", "skinny.lineInstance",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The display call plane associated with this call.",
	HFILL }
    },

    { &hf_skinny_softKeyEvent,
      { "SoftKeyEvent", "skinny.softKeyEvent",
	FT_UINT32, BASE_DEC, VALS(softKeyEvents), 0x0,
	"Which softkey event is being reported.",
	HFILL }
    },

    { &hf_skinny_keepAliveInterval,
      { "KeepAliveInterval", "skinny.keepAliveInterval",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"How often are keep alives exchanges between the client and the call manager.",
	HFILL }
    },

    { &hf_skinny_secondaryKeepAliveInterval,
      { "SecondaryKeepAliveInterval", "skinny.secondaryKeepAliveInterval",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"How often are keep alives exchanges between the client and the secondary call manager.",
	HFILL }
    },

    { &hf_skinny_dateTemplate,
      { "DateTemplate", "skinny.dateTemplate",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The display format for the date/time on the phone.",
	HFILL }
    },

    { &hf_skinny_buttonOffset,
      { "ButtonOffset", "skinny.buttonOffset",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Offset is the number of the first button referenced by this message.",
	HFILL }
    },

    { &hf_skinny_buttonCount,
      { "ButtonCount", "skinny.buttonCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Number of (VALID) button definitions in this message.",
	HFILL }
    },

    { &hf_skinny_totalButtonCount,
      { "TotalButtonCount", "skinny.totalButtonCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The total number of buttons defined for this phone.",
	HFILL }
    },

    { &hf_skinny_buttonInstanceNumber,
      { "InstanceNumber", "skinny.buttonInstanceNumber",
	FT_UINT8, BASE_HEX, VALS(keypadButtons), 0x0,
	"The button instance number for a button or the StationKeyPad value, repeats allowed.",
	HFILL }
    },

    { &hf_skinny_buttonDefinition,
      { "ButtonDefinition", "skinny.buttonDefinition",
	FT_UINT8, BASE_HEX, VALS(buttonDefinitions), 0x0,
	"The button type for this instance (ie line, speed dial, ....",
	HFILL }
    },

    { &hf_skinny_softKeyOffset,
      { "SoftKeyOffset", "skinny.softKeyOffset",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The offset for the first soft key in this message.",
	HFILL }
    },

    { &hf_skinny_softKeyCount,
      { "SoftKeyCount", "skinny.softKeyCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The number of valid softkeys in this message.",
	HFILL }
    },

    { &hf_skinny_totalSoftKeyCount,
      { "TotalSoftKeyCount", "skinny.totalSoftKeyCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The total number of softkeys for this device.",
	HFILL }
    },

    { &hf_skinny_softKeyLabel,
      { "SoftKeyLabel", "skinny.softKeyLabel",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The text label for this soft key.",
	HFILL }
    },

    { &hf_skinny_softKeySetOffset,
      { "SoftKeySetOffset", "skinny.softKeySetOffset",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The offset for the first soft key set in this message.",
	HFILL }
    },

    { &hf_skinny_softKeySetCount,
      { "SoftKeySetCount", "skinny.softKeySetCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The number of valid softkey sets in this message.",
	HFILL }
    },

    { &hf_skinny_totalSoftKeySetCount,
      { "TotalSoftKeySetCount", "skinny.totalSoftKeySetCount",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The total number of softkey sets for this device.",
	HFILL }
    },

    { &hf_skinny_softKeyTemplateIndex,
      { "SoftKeyTemplateIndex", "skinny.softKeyTemplateIndex",
	FT_UINT8, BASE_DEC, VALS(softKeyEvents), 0x0,
	"Array of size 16 8-bit unsigned ints containing an index into the softKeyTemplate.",
	HFILL }
    },

    { &hf_skinny_softKeyInfoIndex,
      { "SoftKeyInfoIndex", "skinny.softKeyInfoIndex",
	FT_UINT16, BASE_DEC, VALS(softKeyIndexes), 0x0,
	"Array of size 16 16-bit unsigned integers containing an index into the soft key description information.",
	HFILL }
    },

    { &hf_skinny_softKeySetDescription,
      { "SoftKeySet", "skinny.softKeySetDescription",
	FT_UINT8, BASE_DEC, VALS(keySetNames), 0x0,
	"A text description of what this softkey when this softkey set is displayed",
	HFILL }
    },

    { &hf_skinny_softKeyMap,
      { "SoftKeyMap","skinny.softKeyMap", 
	FT_UINT16, BASE_DEC, NULL, 0x0,
	"", 
	HFILL }
    },
    
    { &hf_skinny_softKey0,
      { "SoftKey0", "skinny.softKeyMap.0", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY0,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey1,
      { "SoftKey1", "skinny.softKeyMap.1", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY1,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey2,
      { "SoftKey2", "skinny.softKeyMap.2", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY2,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey3,
      { "SoftKey3", "skinny.softKeyMap.3",
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY3,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey4,
      { "SoftKey4", "skinny.softKeyMap.4", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY4,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey5,
      { "SoftKey5", "skinny.softKeyMap.5", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY5,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey6,
      { "SoftKey6", "skinny.softKeyMap.6", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY6,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey7,
      { "SoftKey7", "skinny.softKeyMap.7", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY7,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey8,
      { "SoftKey8", "skinny.softKeyMap.8", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY8,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey9,
      { "SoftKey9", "skinny.softKeyMap.9", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY9,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey10,
      { "SoftKey10", "skinny.softKeyMap.10", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY10,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey11,
      { "SoftKey11", "skinny.softKeyMap.11", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY11,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey12,
      { "SoftKey12", "skinny.softKeyMap.12", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY12,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey13,
      { "SoftKey13", "skinny.softKeyMap.13", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY13,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey14,
      { "SoftKey14", "skinny.softKeyMap.14", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY14,
	"", 
	HFILL }
    },

    { &hf_skinny_softKey15,
      { "SoftKey15", "skinny.softKeyMap.15", 
	FT_BOOLEAN, 16, TFS(&softKeyMapValues), SKINNY_SOFTKEY15,
	"", 
	HFILL }
    },

    { &hf_skinny_lampMode,
      { "LampMode", "skinny.lampMode", 
	FT_UINT32, BASE_DEC, VALS(stationLampModes), 0x0,
	"The lamp mode", 
	HFILL }
    },

    { &hf_skinny_messageTimeOutValue,
      { "Message Timeout", "skinny.messageTimeOutValue", 
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The timeout in seconds for this message", 
	HFILL }
    },

    { &hf_skinny_displayMessage,
      { "DisplayMessage", "skinny.displayMessage",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The message displayed on the phone.",
	HFILL }
    },

    { &hf_skinny_lineDirNumber,
      { "Line Dir Number", "skinny.lineDirNumber",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The directory number for this line.",
	HFILL }
    },

    { &hf_skinny_lineFullyQualifiedDisplayName,
      { "DisplayName", "skinny.fqdn",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The full display name for this line.",
	HFILL }
    },

    { &hf_skinny_speedDialDirNumber,
      { "SpeedDial Number", "skinny.speedDialDirNum",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"the number to dial for this speed dial.",
	HFILL }
    },

    { &hf_skinny_speedDialDisplayName,
      { "SpeedDial Display", "skinny.speedDialDisplay",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The text to display for this speed dial.",
	HFILL }
    },

    { &hf_skinny_dateYear,
      { "Year", "skinny.year",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The current year",
	HFILL }
    },

    { &hf_skinny_dateMonth,
      { "Month", "skinny.month",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The current month",
	HFILL }
    },

    { &hf_skinny_dayOfWeek,
      { "DayOfWeek", "skinny.dayOfWeek",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The day of the week",
	HFILL }
    },

    { &hf_skinny_dateDay,
      { "Day", "skinny.day",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"The day of the current month",
	HFILL }
    },

    { &hf_skinny_dateHour,
      { "Hour", "skinny.hour",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Hour of the day",
	HFILL }
    },

    { &hf_skinny_dateMinute,
      { "Minute", "skinny.minute",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Minute",
	HFILL }
    },

    { &hf_skinny_dateSeconds,
      { "Seconds", "skinny.dateSeconds",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Seconds",
	HFILL }
    },

    { &hf_skinny_dateMilliseconds,
      { "Milliseconds", "skinny.dateMilliseconds",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Milliseconds",
	HFILL }
    },

    { &hf_skinny_timeStamp,
      { "Timestamp", "skinny.timeStamp",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Time stamp for the call reference",
	HFILL }
    },







    /* */


    { &hf_skinny_extension,
      { "Extension", "skinny.extension",
	FT_STRING, BASE_NONE, NULL, 0x0,
	"The extension this packets is for.",
	HFILL }
    },




    { &hf_skinny_unknown,
      { "Unknown Long", "skinny.unknown",
	FT_UINT32, BASE_HEX, NULL, 0x0,
	"An as yet undecoded long value",
	HFILL }
    },
   
    { &hf_skinny_ipSrc,
      { "IP Source", "skinny.ipSrc",
	FT_IPv4, BASE_NONE, NULL, 0x0,
	"Ip source address",
	HFILL }
    },

    { &hf_skinny_ipDest,
      { "IP Destination", "skinny.ipDest",
	FT_IPv4, BASE_NONE, NULL, 0x0,
	"IP destination address",
	HFILL }
    },



    { &hf_skinny_destPort,
      { "Destination Port", "skinny.destPort",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Destination Port",
	HFILL }
    },

    { &hf_skinny_srcPort,
      { "Source Port", "skinny.srcPort",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Source Port",
	HFILL }
    },

    { &hf_skinny_softKeyNumber,
      { "SoftKey", "skinny.softKeyNumber",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"SoftKey",
	HFILL }
    },

    { &hf_skinny_dialedDigit,
      { "Dialed Digit", "skinny.dialedDigit",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Dialed Digit",
	HFILL }
    },

    { &hf_skinny_line,
      { "Line", "skinny.line",
	FT_UINT32, BASE_DEC, NULL, 0x0,
	"Line",
	HFILL }
    },

  };
  
  /* Setup protocol subtree array */
  static gint *ett[] = {
    &ett_skinny,
    &ett_skinny_softKeyMap,
  };
  
  /* Register the protocol name and description */
  proto_skinny = proto_register_protocol("Skinny Client Control Protocol",
					 "SKINNY", "skinny");
  
  /* Required function calls to register the header fields and subtrees used */
  proto_register_field_array(proto_skinny, hf, array_length(hf));
  proto_register_subtree_array(ett, array_length(ett));
};

void
proto_reg_handoff_skinny(void)
{
  dissector_handle_t skinny_handle;
  
  data_handle = find_dissector("data");
  skinny_handle = create_dissector_handle(dissect_skinny, proto_skinny);
  dissector_add("tcp.port", TCP_PORT_SKINNY, skinny_handle);
}
/*
 * packet-skinny.h
 *
 * Paul E. Erkkila pee@xxxxxxxxxxx
 *
 * this header borrowed from various places, and people
 * their names have been changed to protect the guilty =)
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

/*
 * FIXME:
 *
 * This is the status of this decode.
 * Items marked as N/A in the decode field have no params to test
 * implemented for N/A means they exist in the switch statement
 * NC = needs conversion to struct decode
 *
 *  id     message                     implemented  decode tested (via capture)
 *  ---------------------------------------------------------------------------
 *  0x0    keepAlive                       Y        N/A 
 *  0x1    register                        Y        Y
 *  0x2    ipPort                          Y        Y
 *  0x3    keypadButton                    Y        Y
 *  0x4    enblocCall                      Y        N
 *  0x5    stimulus                        Y        N
 *  0x6    offHook                         Y        N/A
 *  0x7    onHook                          Y        N/A
 *  0x8    hookFlash                       Y        N/A
 *  0x9    forwardStatReq                  Y        N
 *  0xa    speedDialStatReq                Y        Y
 *  0xb    lineStatReq                     Y        Y
 *  0xc    configStatReq                   Y        N/A
 *  0xd    timeDateReq                     Y        N/A
 *  0xe    buttonTemplateReq               Y        N/A
 *  0xf    versionReq                      Y        N/A
 *  0x10   capabilitiesRes                 Y        Y -- would like more decodes
 *  0x11   mediaPortList                   N        N
 *  0x12   serverReq                       Y        N/A
 *  0x20   alarmMessage                    Y        Y
 *  0x21   multicastMediaReceptionAck      Y        N
 *  0x22   openReceiveChannelAck           Y        Y
 *  0x23   connectionStatisticsRes         Y        Y
 *  0x24   offHookWithCgpn                 N        N
 *  0x25   softKeySetReq                   Y        N/A
 *  0x26   softKeyEvent                    Y        Y
 *  0x27   unregister                      Y        N/A
 *  0x28   softKeytemplateReq              Y        N/A
 *  0x29   registerTokenReq                N        N
 *******************************
 *  0x2b   unknownClientMessage1           NC       N
 *  0x2d   unknownClientMessage2           NC       N
 *******************************
 *  0x81   registerAck                     Y        Y
 *  0x82   startTone                       NC       N
 *  0x83   stopTone                        Y        N/A
 *  0x85   setRinger                       NC       N
 *  0x86   setLamp                         Y        Y
 *  0x87   setHkFDetect                    N        N
 *  0x88   setSpeakerMode                  NC       N
 *  0x89   setMicroMode                    N        N
 *  0x8A   startMediaTransmission          NC       N
 *  0x8B   stopMediaTransmission           NC       N
 *  0x8C   startMediaReception             N        N
 *  0x8D   stopMediaReception              N        N
 *  0x8E   *reserved*                      *        *
 *  0x8F   callInfo                        N        N
 *  0x90   forwardStat                     N        N
 *  0x91   speedDialStat                   Y        Y
 *  0x92   lineStat                        Y        Y
 *  0x93   configStat                      N        N
 *  0x94   defineTimeDate                  Y        Y
 *  0x95   startSessionTransmission        N        N
 *  0x96   stopSessionTransmission         N        N
 *  0x97   buttonTemplate                  Y        Y -- ugly =)
 *  0x98   version                         N        N
 *  0x99   displayText                     NC       N
 *  0x9A   clearDisplay                    N        N
 *  0x9B   capabilitiesReq                 Y        N/A
 *  0x9C   enunciatorCommand               N        N
 *  0x9D   registerReject                  N        N
 *  0x9E   serverRes                       N        N
 *  0x9F   reset                           NC       N
 *  0x100  keepAliveAck                    Y        N/A
 *  0x101  startMulticastMediaReception    N        N
 *  0x102  startMulticastMediaTermination  N        N
 *  0x103  stopMulticastMediaReception     N        N
 *  0x104  stopMulticastMediaTransmission  N        N
 *  0x105  openreceiveChannel              NC       N
 *  0x106  closeReceiveChannel             NC       N
 *  0x107  connectionStatisticsReq         NC       N
 *  0x108  softKeyTemplateRes              Y        Y
 *  0x109  softKeySetRes                   Y        Y
 *  0x110  selectSoftKeys                  Y        Y
 *  0x111  callState                       NC       N
 *  0x112  displayPromptStatus             Y        Y
 *  0x113  clearPromptStatus               NC       N
 *  0x114  displayNotify                   NC       N
 *  0x115  clearNotify                     N        N
 *  0x116  activateCallPlane               NC       N
 *  0x117  deactivateCallPlane             N        N
 *  0x118  unregisterAck                   NC       N
 *  0x119  backSpaceReq                    N        N
 *  0x11A  registerTokenAck                N        N
 *  0x11B  registerTokenReject             N        N
 *
 *
 */


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <string.h>

#include <epan/packet.h>
#include "prefs.h"
#include "packet-frame.h"

/* the port that skinny runs on */
#define TCP_PORT_SKINNY 2000


#define SKINNY_SOFTKEY0  0x01
#define SKINNY_SOFTKEY1  0x02
#define SKINNY_SOFTKEY2  0x04
#define SKINNY_SOFTKEY3  0x08
#define SKINNY_SOFTKEY4  0x10
#define SKINNY_SOFTKEY5  0x20
#define SKINNY_SOFTKEY6  0x40
#define SKINNY_SOFTKEY7  0x80
#define SKINNY_SOFTKEY8  0x100
#define SKINNY_SOFTKEY9  0x200
#define SKINNY_SOFTKEY10 0x400
#define SKINNY_SOFTKEY11 0x800
#define SKINNY_SOFTKEY12 0x1000
#define SKINNY_SOFTKEY13 0x2000
#define SKINNY_SOFTKEY14 0x4000
#define SKINNY_SOFTKEY15 0x8000

#define DisplayNotifyDefaultTimeOutValue 10 
#define DisplayPromtStatusDefaultTimeOutValue 10 
#define TransferSoftKeyOn 0x00000001 
#define ConferenceSoftKeyOn 0x00000010 

#define StationMaxDirnumSize 24         /* max size of calling or called party dirnum  */
#define StationMaxNameSize 40           /* max size of calling party's name  */
#define StationMaxDeviceNameSize 16     /* max size of station's IP name  */
#define StationMaxSpeedDials 10         /* max number of speed dial numbers allowed on a station */
#define StationMaxVersionSize 16        /* max chars in version string  */
#define StationMaxButtonTemplateSize 42 /* max button template size */ 
#define StationMaxDisplayTextSize 33    /* max text size in DisplayText message */
#define StationMaxPorts 10              /* max number of ports on one device */
#define StationDateTemplateSize 6       /* date template in the form M/D/Y, D/M/Y, ... */
#define StationMaxServerNameSize 48     /* max size of server name */
#define StationMaxServers 5             /* max servers */
#define StationMaxDeviceDirnums 1024    /* max dir numbers per SCM device */
#define StationMaxDirnums 64            /* max dir numbers per physical station (also used in db request msg); */
#define StationMaxSoftKeyLabelSize 16   /* max label size in the message */
#define StationMaxSoftKeyDefinition 32       /* max number of soft key definition in the message */
#define StationMaxSoftKeySetDefinition 16    /* max number of soft key set definition in the message */
#define StationMaxSoftKeyIndex 16            /* max number of soft key indices in a station soft key set */
#define StationMaxDisplayPromptStatusSize 32 /* max status text size in the display status message */
#define StationMaxDisplayNotifySize 32       /* max prompt text size in the display prompt message */

static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);

/* Initialize the protocol and registered fields */
static int proto_skinny          = -1;
static int hf_skinny_data_length = -1;
static int hf_skinny_reserved    = -1;
static int hf_skinny_messageid   = -1;
static int hf_skinny_deviceName  = -1;
static int hf_skinny_stationUserId = -1;
static int hf_skinny_stationInstance = -1;
static int hf_skinny_deviceType = -1;
static int hf_skinny_maxStreams = -1;
static int hf_skinny_stationIpPort = -1;
static int hf_skinny_stationKeypadButton = -1;
static int hf_skinny_calledParty = -1;
static int hf_skinny_stimulus = -1;
static int hf_skinny_stimulusInstance = -1;
static int hf_skinny_lineNumber = -1;
static int hf_skinny_speedDialNumber = -1;
static int hf_skinny_capCount = -1;
static int hf_skinny_payloadCapability = -1;
static int hf_skinny_maxFramesPerPacket = -1;
static int hf_skinny_alarmSeverity = -1;
static int hf_skinny_alarmParam1 = -1;
static int hf_skinny_alarmParam2 = -1;
static int hf_skinny_receptionStatus = -1;
static int hf_skinny_passThruPartyID = -1;
static int hf_skinny_ORCStatus = -1;
static int hf_skinny_ipAddress = -1;
static int hf_skinny_portNumber = -1;
static int hf_skinny_statsProcessingType = -1;
static int hf_skinny_callIdentifier = -1;
static int hf_skinny_packetsSent = -1;
static int hf_skinny_octetsSent  = -1;
static int hf_skinny_packetsRecv = -1;
static int hf_skinny_octetsRecv  = -1;
static int hf_skinny_packetsLost = -1;
static int hf_skinny_latency     = -1;
static int hf_skinny_jitter      = -1;
static int hf_skinny_directoryNumber = -1;
static int hf_skinny_softKeyEvent = -1;
static int hf_skinny_lineInstance = -1;
static int hf_skinny_keepAliveInterval = -1;
static int hf_skinny_dateTemplate = -1;
static int hf_skinny_secondaryKeepAliveInterval = -1;
static int hf_skinny_buttonOffset = -1;
static int hf_skinny_buttonCount = -1;
static int hf_skinny_totalButtonCount = -1;
static int hf_skinny_buttonInstanceNumber = -1;
static int hf_skinny_buttonDefinition = -1;
static int hf_skinny_softKeyOffset = -1;
static int hf_skinny_softKeyCount = -1;
static int hf_skinny_totalSoftKeyCount = -1;
static int hf_skinny_softKeyLabel = -1;
static int hf_skinny_softKeySetOffset = -1;
static int hf_skinny_softKeySetCount = -1;
static int hf_skinny_totalSoftKeySetCount = -1;
static int hf_skinny_softKeyTemplateIndex = -1;
static int hf_skinny_softKeyInfoIndex = -1;
static int hf_skinny_softKeySetDescription = -1;
static int hf_skinny_softKeyMap = -1;
static int hf_skinny_softKey0 = -1;
static int hf_skinny_softKey1 = -1;
static int hf_skinny_softKey2 = -1;
static int hf_skinny_softKey3 = -1;
static int hf_skinny_softKey4 = -1;
static int hf_skinny_softKey5 = -1;
static int hf_skinny_softKey6 = -1;
static int hf_skinny_softKey7 = -1;
static int hf_skinny_softKey8 = -1;
static int hf_skinny_softKey9 = -1;
static int hf_skinny_softKey10 = -1;
static int hf_skinny_softKey11 = -1;
static int hf_skinny_softKey12 = -1;
static int hf_skinny_softKey13 = -1;
static int hf_skinny_softKey14 = -1;
static int hf_skinny_softKey15 = -1;
static int hf_skinny_lampMode = -1;
static int hf_skinny_messageTimeOutValue = -1;
static int hf_skinny_displayMessage = -1;
static int hf_skinny_lineDirNumber = -1;
static int hf_skinny_lineFullyQualifiedDisplayName = -1;
static int hf_skinny_speedDialDirNumber = -1;
static int hf_skinny_speedDialDisplayName = -1;
static int hf_skinny_dateYear = -1;
static int hf_skinny_dateMonth = -1;
static int hf_skinny_dayOfWeek = -1;
static int hf_skinny_dateDay = -1;
static int hf_skinny_dateHour = -1;
static int hf_skinny_dateMinute = -1;
static int hf_skinny_dateSeconds = -1;
static int hf_skinny_dateMilliseconds = -1;
static int hf_skinny_timeStamp = -1;


static int hf_skinny_extension   = -1;
static int hf_skinny_unknown = -1;
static int hf_skinny_ipDest = -1;
static int hf_skinny_ipSrc = -1;
static int hf_skinny_destPort = -1;
static int hf_skinny_srcPort = -1;
static int hf_skinny_softKeyNumber = -1;
static int hf_skinny_line = -1;
static int hf_skinny_dialedDigit = -1;

/* Initialize the subtree pointers */
static gint ett_skinny          = -1;
static gint ett_skinny_softKeyMap = -1;

/* desegmentation of SCCP */
static gboolean skinny_desegment = TRUE;

static dissector_handle_t data_handle;

/* KeyMap Show/No Show */
static const true_false_string softKeyMapValues = {
  "Show",
  "Do Not Show"
};


/*
 * Message id -> text conversion
 */
static const value_string  message_id[] = {

  /* Station -> Callmanager */
  {0x0000, "KeepAliveMessage"},
  {0x0001, "RegisterMessage"},
  {0x0002, "IpPortMessage"},
  {0x0003, "KeypadButtonMessage"},
  {0x0004, "EnblocCallMessage"},
  {0x0005, "StimulusMessage"},
  {0x0006, "OffHookMessage"},
  {0x0007, "OnHookMessage"},
  {0x0008, "HookFlashMessage"},
  {0x0009, "ForwardStatReqMessage"},
  {0x000A, "SpeedDialStatReqMessage"},
  {0x000B, "LineStatReqMessage"},
  {0x000C, "ConfigStatReqMessage"},
  {0x000D, "TimeDateReqMessage"},
  {0x000E, "ButtonTemplateReqMessage"},
  {0x000F, "VersionReqMessage"},
  {0x0010, "CapabilitiesResMessage"},
  {0x0011, "MediaPortListMessage"},
  {0x0012, "ServerReqMessage"},
  {0x0020, "AlarmMessage"},
  {0x0021, "MulticastMediaReceptionAck"},
  {0x0022, "OpenReceiveChannelAck"},
  {0x0023, "ConnectionStatisticsRes"},
  {0x0024, "OffHookWithCgpnMessage"},
  {0x0025, "SoftKeySetReqMessage"},
  {0x0026, "SoftKeyEventMessage"},
  {0x0027, "UnregisterMessage"},
  {0x0028, "SoftKeyTemplateReqMessage"},
  {0x0029, "RegisterTokenReq"},
  {0x002B, "unknownClientMessage1"},
  {0x002D, "unknownClientMessage2"},
  
  /* Callmanager -> Station */
  /* 0x0000, 0x0003? */
  {0x0081, "RegisterAckMessage"},
  {0x0082, "StartToneMessage"},
  {0x0083, "StopToneMessage"},
  {0x0085, "SetRingerMessage"},
  {0x0086, "SetLampMessage"},
  {0x0087, "SetHkFDetectMessage"},
  {0x0088, "SetSpeakerModeMessage"},
  {0x0089, "SetMicroModeMessage"},
  {0x008A, "StartMediaTransmission"},
  {0x008B, "StopMediaTransmission"},
  {0x008C, "StartMediaReception"},
  {0x008D, "StopMediaReception"},
  {0x008F, "CallInfoMessage"},
  {0x0090, "ForwardStatMessage"},
  {0x0091, "SpeedDialStatMessage"},
  {0x0092, "LineStatMessage"},
  {0x0093, "ConfigStatMessage"},
  {0x0094, "DefineTimeDate"},
  {0x0095, "StartSessionTransmission"},
  {0x0096, "StopSessionTransmission"},
  {0x0097, "ButtonTemplateMessage"},
  {0x0098, "VersionMessage"},
  {0x0099, "DisplayTextMessage"},
  {0x009A, "ClearDisplay"},
  {0x009B, "CapabilitiesReqMessage"},
  {0x009C, "EnunciatorCommandMessage"},
  {0x009D, "RegisterRejectMessage"},
  {0x009E, "ServerResMessage"},
  {0x009F, "Reset"},
  {0x0100, "KeepAliveAckMessage"},
  {0x0101, "StartMulticastMediaReception"},
  {0x0102, "StartMulticastMediaTransmission"},
  {0x0103, "StopMulticastMediaReception"},
  {0x0104, "StopMulticastMediaTransmission"},
  {0x0105, "OpenReceiveChannel"},
  {0x0106, "CloseReceiveChannel"},
  {0x0107, "ConnectionStatisticsReq"},
  {0x0108, "SoftKeyTemplateResMessage"},
  {0x0109, "SoftKeySetResMessage"},
  {0x0110, "SelectSoftKeysMessage"},
  {0x0111, "CallStateMessage"},
  {0x0112, "DisplayPromptStatusMessage"},
  {0x0113, "ClearPromptStatusMessage"},
  {0x0114, "DisplayNotifyMessage"},
  {0x0115, "ClearNotifyMessage"},
  {0x0116, "ActivateCallPlaneMessage"},
  {0x0117, "DeactivateCallPlaneMessage"},
  {0x0118, "UnregisterAckMessage"},
  {0x0119, "BackSpaceReqMessage"},
  {0x011A, "RegisterTokenAck"},
  {0x011B, "RegisterTokenReject"},
  {0x011D, "unknownForwardMessage1"},

  {0     , NULL}	/* needed for value_string automagic */
};


/*
 * Device type to text conversion table
 */
static const value_string  deviceTypes[] = {
  {1  , "DeviceStation30SPplus"},
  {2  , "DeviceStation12SPplus"},
  {3  , "DeviceStation12SP"},
  {4  , "DeviceStation12"},
  {5  , "DeviceStation30VIP"},
  {6  , "DeviceStationTelecaster"},
  {7  , "DeviceStationTelecasterMgr"},
  {8  , "DeviceStationTelecasterBus"},
  {20 , "DeviceVirtual30SPplus"},
  {21 , "DeviceStationPhoneApplication"},
  {30 , "DeviceAnalogAccess"},
  {40 , "DeviceDigitalAccessPRI"},
  {41 , "DeviceDigitalAccessT1"},
  {42 , "DeviceDigitalAccessTitan2"},
  {47 , "DeviceAnalogAccessElvis"},
  {49 , "DeviceDigitalAccessLennon"},
  {50 , "DeviceConferenceBridge"},
  {51 , "DeviceConferenceBridgeYoko"},
  {60 , "DeviceH225"},
  {61 , "DeviceH323Phone"},
  {62 , "DeviceH323Trunk"},
  {70 , "DeviceMusicOnHold"},
  {71 , "DevicePilot"},
  {72 , "DeviceTapiPort"},
  {73 , "DeviceTapiRoutePoint"},
  {80 , "DeviceVoiceInBox"},
  {81 , "DeviceVoiceInboxAdmin"},
  {82 , "DeviceLineAnnunciator"},
  {90 , "DeviceRouteList"},
  {100, "DeviceLoadSimulator"},
  {110, "DeviceMediaTerminationPoint"},
  {111, "DeviceMediaTerminationPointYoko"},
  {120, "DeviceMGCPStation"},
  {121, "DeviceMGCPTrunk"},
  {122, "DeviceRASProxy"},
  {255, "DeviceNotDefined"},
  { 0    , NULL}
};

/*
 * keypad button -> text conversion
 */
static const value_string keypadButtons[] = {
  {0x0   , "Zero"},
  {0x1   , "One"},
  {0x2   , "Two"},
  {0x3   , "Three"},
  {0x4   , "Four"},
  {0x5   , "Five"},
  {0x6   , "Six"},
  {0x7   , "Seven"},
  {0x8   , "Eight"},
  {0x9   , "Nine"},
  {0xa   , "A"},
  {0xb   , "B"},
  {0xc   , "C"},
  {0xd   , "D"},
  {0xe   , "Star"},
  {0xf   , "Pound"},
  {0     , NULL}
};

static const value_string deviceStimuli[] = {
  {1    , "SsLastNumberRedial"},
  {2    , "SsSpeedDial"},
  {3    , "SsHold"},
  {4    , "SsTransfer"},
  {5    , "SsForwardAll"},
  {6    , "SsForwardBusy"},
  {7    , "SsForwardNoAnswer"},
  {8    , "SsDisplay"},
  {9    , "SsLine"},
  {0xa  , "SsT120Chat"},
  {0xb  , "SsT120Whiteboard"},
  {0xc  , "SsT120ApplicationSharing"},
  {0xd  , "SsT120FileTransfer"},
  {0xe  , "SsVideo"},
  {0xf  , "SsVoiceMail"},
  {0x11 , "SsAutoAnswer"},
  {0x21 , "SsGenericAppB1"},
  {0x22 , "SsGenericAppB2"},
  {0x23 , "SsGenericAppB3"},
  {0x24 , "SsGenericAppB4"},
  {0x25 , "SsGenericAppB5"},
  {0x7b , "SsMeetMeConference"},
  {0x7d , "SsConference=0x7d"},
  {0x7e , "SsCallPark=0x7e"},
  {0x7f , "SsCallPickup"},
  {0x80 , "SsGroupCallPickup=80"},
  {0,NULL}
};


/* Note i'm only using 7 later on cuz i'm lazy ;) */
#define DeviceMaxCapabilities 18 /* max capabilities allowed in Cap response message */

static const value_string mediaPayloads[] = {
  {1   , "Media_Payload_NonStandard"},
  {2   , "Media_Payload_G711Alaw64k"},
  {3   , "Media_Payload_G711Alaw56k"},
  {4   , "Media_Payload_G711Ulaw64k"},
  {5   , "Media_Payload_G711Ulaw56k"},
  {6   , "Media_Payload_G722_64k"},
  {7   , "Media_Payload_G722_56k"},
  {8   , "Media_Payload_G722_48k"},
  {9   , "Media_Payload_G7231"},
  {10  , "Media_Payload_G728"},
  {11  , "Media_Payload_G729"},
  {12  , "Media_Payload_G729AnnexA"},
  {13  , "Media_Payload_Is11172AudioCap"},
  {14  , "Media_Payload_Is13818AudioCap"},
  {15  , "Media_Payload_G729AnnexB"},
  {16  , "Media_Payload_G729AnnexAwAnnexB"},
  {32  , "Media_Payload_Data64"},
  {33  , "Media_Payload_Data56"},
  {80  , "Media_Payload_GSM"},
  {81  , "Media_Payload_ActiveVoice"},
  {82  , "Media_Payload_G726_32K"},
  {83  , "Media_Payload_G726_24K"},
  {84  , "Media_Payload_G726_16K"},
  {85  , "Media_Payload_G729_B"},
  {86  , "Media_Payload_G729_B_LOW_COMPLEXITY"},
  {0  , NULL}
};

static const value_string alarmSeverities[] = {
  {0   , "severityCritical"},
  {7   , "severityMajor"},
  {8   , "severityMinor"},
  {1   , "severityWarning"},
  {10  , "severityMarginal"},
  {4   , "severityUnknown"},
  {2   , "severityInformational"},
  {20  , "severityTraceInfo"},
  {0  , NULL}
};

static const value_string multicastMediaReceptionStatus[] = {
  {0  , "mmrOk"},
  {1  , "mmrError"},
  {0  , NULL}
};

static const value_string openReceiveChanStatus[] = {
  {0   , "orcOk"},
  {1   , "orcError"},
  {0   , NULL}
};


static const value_string statsProcessingTypes[] = {
  {0   , "clearStats"},
  {1   , "doNotClearStats"},
  {0   , NULL}
};

#define SkMaxSoftKeyCount 18 /* this value should be the same as the max soft key value */
static const value_string softKeyEvents[] = {
  {1   , "SkRedial"},
  {2   , "SkNewCall"},
  {3   , "SkHold"},
  {4   , "SkTrnsfer"},
  {5   , "SkCFwdAll"},
  {6   , "SkCFwdBusy"},
  {7   , "SkCFwdNoAnswer"},
  {8   , "SkBackSpace"},
  {9   , "SkEndCall"},
  {10  , "SkResume"},
  {11  , "SkAnswer"},
  {12  , "SkInfo"},
  {13  , "SkConfrn"},
  {14  , "SkPark"},
  {15  , "SkJoin"},
  {16  , "SkMeetMeConfrn"},
  {17  , "SkCallPickUp"},
  {18  , "SkGrpCallPickUp"},
  {0   , NULL}
};

/* Define info index for each softkey event for Telecaster station. */
static const value_string softKeyIndexes[] = {
  {301  , "SkRedialInfoIndex"},
  {302  , "SkNewCallInfoIndex"},
  {303  , "SkHoldInfoIndex"},
  {304  , "SkTrnsferInfoIndex"},
  {305  , "SkCFwdAllInfoIndex"},
  {306  , "SkCFwdBusyInfoIndex"},     /* not used yet */
  {307  , "SkCFwdNoAnswerInfoIndex"}, /* not used yet */
  {308  , "SkBackSpaceInfoIndex"},
  {309  , "SkEndCallInfoIndex"},
  {310  , "SkResumeInfoIndex"},
  {311  , "SkAnswerInfoIndex"},
  {312  , "SkInfoInfoIndex"},
  {313  , "SkConfrnInfoIndex"},
  {314  , "SkParkInfoIndex"},
  {315  , "SkJoinInfoIndex"},
  {316  , "SkMeetMeConfrnInfoIndex"},
  {317  , "SkCallPickUpInfoIndex"},
  {318  , "SkGrpCallPickUpInfoIndex"},
  {0   , NULL}
};


static const value_string buttonDefinitions[] = {
  {1    , "BtLastNumberRedial"},
  {2    , "BtSpeedDial"},
  {3    , "BtHold"},
  {4    , "BtTransfer"},
  {5    , "BtForwardAll"},
  {6    , "BtForwardBusy"},
  {7    , "BtForwardNoAnswer"},
  {8    , "BtDisplay"},
  {9    , "BtLine"},
  {0xa  , "BtT120Chat"},
  {0xb  , "BtT120Whiteboard"},
  {0xc  , "BtT120ApplicationSharing"},
  {0xd  , "BtT120FileTransfer"},
  {0xe  , "BtVideo"},
  {0x10 , "BtAnswerRelease"},
  {0xf0 , "BtKeypad"},
  {0xfd , "BtAEC"},
  {0xff , "BtUndefined"},
  {0   , NULL}
};

#define StationTotalSoftKeySets 10 /* total number of the soft key sets */
static const value_string keySetNames[] = {
  {0   , "OnHook"},
  {1   , "Connected"},
  {2   , "OnHold"},
  {3   , "RingIn"},
  {4   , "OffHook"},
  {5   , "Connected with transfer"},
  {6   , "Digits after dialing first digit"},
  {7   , "Connected with conference"},
  {8   , "RingOut"},
  {9   , "OffHook with features"},
  {0   , NULL}
};

/* Define soft key labels for the Telecaster station */
static const value_string softKeyLabel[] = { 
  {0   , "undefined"},
  {1   , "Redial"},
  {2   , "NewCall"},
  {3   , "Hold"},
  {4   , "Trnsfer"},
  {5   , "CFwdAll"},
  {6   , "CFwdBusy"},
  {7   , "CFwdNoAnswer"},
  {8   , "<<"},
  {9   , "EndCall"},
  {10  , "Resume"},
  {11  , "Answer"},
  {12  , "Info"},
  {13  , "Confrn"},
  {14  , "Park"},
  {15  , "Join"},
  {16  , "MeetMe"},
  {17  , "PickUp"},
  {18  , "GPickUp"},
  {0   , NULL}
}; 


/* 
 * define lamp modes; 
 * lamp cadence is defined as follows 
 * Wink (on 80%) = 448msec on / 64msec off 
 * Flash (fast flash) = 32msec on / 32msec off 
 * Blink (on 50%) = 512msec on / 512msec off 
 * On (on steady) 
 */
static const value_string stationLampModes[] = {
  {0   , "Undefined"},
  {0x1 , "LampOff"},
  {0x2 , "LampOn"},
  {0x3 , "LampWink"},
  {0x4 , "LampFlash"},
  {0x5 , "LampBlink"},
  {0   , NULL}
}; 


# define NUM_MEDIA_PAYLOADTYPES 19 
static char *Media_PayloadList[] = { 
  "Undefined", 
  "Media_Payload_NonStandard", 
  "Media_Payload_G711Alaw64k", 
  "Media_Payload_G711Alaw56k", 
  "Media_Payload_G711Ulaw64k", 
  "Media_Payload_G711Ulaw56k", 
  "Media_Payload_G722_64k", 
  "Media_Payload_G722_56k", 
  "Media_Payload_G722_48k", 
  "Media_Payload_G7231", 
  "Media_Payload_G728", 
  "Media_Payload_G729", 
  "Media_Payload_G729AnnexA", 
  "Media_Payload_Is11172AudioCap", 
  "Media_Payload_Is13818AudioCap", 
  "Media_Payload_G729AnnexB", 
  "Media_Payload_G729AnnexAwAnnexB", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Media_Payload_Data64", 
  "Media_Payload_Data56", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Undefined", 
  "Media_Payload_GSM", 
  "Media_Payload_ActiveVoice", 
  "Media_Payload_G726_32K", 
  "Media_Payload_G726_24K", 
  "Media_Payload_G726_16K", 
  "Media_Payload_G729_B", 
  "Media_Payload_G729_B_LOW_COMPLEXITY", 
  "Undefined", 
  "Undefined" 
}; 

/*
 * FIXME
 * Some import conversion defs, these should go away
 *
 */
typedef guint32 UINT32;
typedef guint16 UINT16;
typedef guint8 UINT8;

typedef enum { 
  Media_SilenceSuppression_Off = 0 , 
  Media_SilenceSuppression_On = 1 
} Media_SilenceSuppression; 

typedef enum { 
  Media_EchoCancellation_Off = 0 , 
  Media_EchoCancellation_On = 1 
} Media_EchoCancellation; 

typedef enum { 
  Media_G723BRate_5_3 = 1 , 
  Media_G723BRate_6_4 = 2 
} Media_G723BitRate; 

typedef struct { 
  UINT32 precedenceValue; 
  Media_SilenceSuppression ssValue; 
  UINT16 maxFramesPerPacket; 
  Media_G723BitRate g723BitRate; /* only used with G.723 payload */
} Media_QualifierOutgoing; 

typedef struct { 
  Media_EchoCancellation ecValue; 
  Media_G723BitRate g723BitRate; /* only used with G.723 payload */
} Media_QualifierIncoming; 



typedef struct {
  guint32 payloadCapability;
  guint32 maxFramesPerPacket;
union { 
  guint8 futureUse[8]; 
    Media_G723BitRate g723BitRate; 
  } PAYLOADS; 
} MediaCapabilityStructure; 



/* textual description for each device type */
#define DTextStation30SPplus "30 SP+" 
#define DTextStation12SPplus "12 SP+" 
#define DTextStation12SP "12 SP" 
#define DTextStation12 "12 S" 
#define DTextStation30VIP "30 VIP" 
#define DTextStationTelecaster "Telecaster" 
#define DTextVirtual30SPplus "Virtual 30 SP+" 
#define DTextAnalogAccess "Analog Access" 
#define DTextDigitalAccessPRI "PRI Digital Access" 
#define DTextDigitalAccessT1 "T1 Digital Access" 
#define DTextConferenceBridge "Conf Bridge" 
#define DTextH225 "H.225" 
#define DTextMusicOnHold "Music on Hold" 
#define DTextPilot "Pilot" 
#define DTextTapiPort "TAPI Port" 
#define DTextTapiRoutePoint "TAPI Route Point" 
#define DTextVoiceInBox "VoiceInbox" 
#define DTextVoiceInboxAdmin "VoiceInbox Admin" 
#define DTextLineAnnunciator "Line Annunciator" 
#define DTextRouteList "Route List" 
#define DTextMediaTerminationPoint "MediaTerminationPoint" 
#define DTextMGCPStation "MGCPStation" 
#define DTextMGCPTrunk "MGCPTrunk" 
#define DTextRASPRoxy "RASProxy" 

/* 
 * define station-playable tones; 
 * for tone definitions see SR-TSV-002275, "BOC Notes on the LEC Networks -- 1994" 
 */

typedef enum { 
  DtSilence = 0 , 
  DtDtmf1 = 1 , 
  DtDtmf2 = 2 , 
  DtDtmf3 = 3 , 
  DtDtmf4 = 4 , 
  DtDtmf5 = 5 , 
  DtDtmf6 = 6 , 
  DtDtmf7 = 7 , 
  DtDtmf8 = 8 , 
  DtDtmf9 = 9 , 
  DtDtmf0 = 0xa, 
  DtDtmfStar = 0xe, 
  DtDtmfPound = 0xf, 
  DtDtmfA = 0x10, 
  DtDtmfB = 0x11, 
  DtDtmfC = 0x12, 
  DtDtmfD = 0x13, 
  DtInsideDialTone = 0x21, 
  DtOutsideDialTone = 0x22,
  DtLineBusyTone = 0x23, 
  DtAlertingTone = 0x24, 
  DtReorderTone = 0x25, 
  DtRecorderWarningTone = 0x26, 
  DtRecorderDetectedTone = 0x27, 
  DtRevertingTone = 0x28, 
  DtReceiverOffHookTone = 0x29, 
  DtPartialDialTone = 0x2A, 
  DtNoSuchNumberTone = 0x2B, 
  DtBusyVerificationTone = 0x2C, 
  DtCallWaitingTone = 0x2D, 
  DtConfirmationTone = 0x2E, 
  DtCampOnIndicationTone = 0x2F, 
  DtRecallDialTone = 0x30, 
  DtZipZip = 0x31, 
  DtZip = 0x32, 
  DtBeepBonk = 0x33, 
  DtMusicTone = 0x34, 
  DtHoldTone = 0x35, 
  DtTestTone = 0x36, 
  /* titan only */
  Dt_AddCallWaiting = 0x40, 
  Dt_PriorityCallWait = 0x41, 
  Dt_RecallDial = 0x42, 
  Dt_BargIn = 0x43, 
  Dt_DistinctAlert = 0x44, 
  Dt_PriorityAlert = 0x45, 
  Dt_ReminderRing = 0x46, 
  /* agena only */
  Dt_MF1 = 0x50, 
  Dt_MF2 = 0x51, 
  Dt_MF3 = 0x52, 
  Dt_MF4 = 0x53, 
  Dt_MF5 = 0x54, 
  Dt_MF6 = 0x55, 
  Dt_MF7 = 0x56, 
  Dt_MF8 = 0x57, 
  Dt_MF9 = 0x58, 
  Dt_MF0 = 0x59, 
  Dt_MFKP1 = 0x5A, 
  Dt_MFST = 0x5B, 
  Dt_MFKP2 = 0x5C, 
  Dt_MFSTP = 0x5D, 
  Dt_MFST3P = 0x5E, 
  Dt_MILLIWATT = 0x5F, 
  Dt_MILLIWATTTEST = 0x60, 
  Dt_HIGHTONE = 0x61, 
  Dt_FLASHOVERRIDE = 0x62, 
  Dt_FLASH = 0x63, 
  Dt_PRIORITY = 0x64, 
  Dt_IMMEDIATE = 0x65, 
  Dt_PREAMPWARN = 0x66, 
  Dt_2105HZ = 0x67, 
  Dt_2600HZ = 0x68, 
  Dt_440HZ = 0x69, 
  Dt_300HZ = 0x6A, 
  Dt_NoTone = 0x7F, 
  Dt_MAX 
} DeviceTone; 

static char *toneNames[] = { 
  "DtSilence", 
  "DtDtmf1", 
  "DtDtmf2", 
  "DtDtmf3",
  "DtDtmf4", 
  "DtDtmf5", 
  "DtDtmf6", 
  "DtDtmf7", 
  "DtDtmf8", 
  "DtDtmf9", 
  "DtDtmf0", 
  "undefined", 
  "undefined", 
  "undefined", 
  "DtDtmfStar", 
  "DtDtmfPound", 
  "DtDtmfA", 
  "DtDtmfB", 
  "DtDtmfC", 
  "DtDtmfD", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "InsideDialTone", 
  "OutsideDialTone", 
  "LineBusyTone", 
  "AlertingTone", 
  "ReorderTone", 
  "RecorderWarningTone", 
  "RecorderDetectedTone", 
  "RevertingTone", 
  "ReceiverOffHookTone", 
  "PartialDialTone", 
  "NoSuchNumberTone", 
  "BusyVerificationTone", 
  "CallWaitingTone", 
  "ConfirmationTone", 
  "CampOnIndicationTone", 
  "RecallDialTone", 
  "ZipZip", 
  "Zip", 
  "BeepBonk", 
  "MusicTone", 
  "HoldTone", 
  "TestTone", 
  "0x37", 
  "0x38", 
  "0x39", 
  "0x3a", 
  "0x3b", 
  "0x3c", 
  "0x3d", 
  "0x3e", 
  "0x3f", 
  "0x40", 
  "0x41", 
  "0x42", 
  "0x43", 
  "0x44", 
  "0x45", 
  "0x46", 
  "0x47", 
  "0x48", 
  "0x49", 
  "0x4a",
  "0x4b", 
  "0x4c", 
  "0x4d", 
  "0x4e", 
  "0x4f", 
  "0x50", 
  "0x51", 
  "0x52", 
  "0x53", 
  "0x54", 
  "0x55", 
  "0x56", 
  "0x57", 
  "0x58", 
  "0x59", 
  "0x5a", 
  "0x5b", 
  "0x5c", 
  "0x5d", 
  "0x5e", 
  "0x5f", 
  "0x60", 
  "0x61", 
  "0x62", 
  "0x63", 
  "0x64", 
  "0x65", 
  "0x66", 
  "0x67", 
  "0x68", 
  "0x69", 
  "0x6a", 
  "0x6b", 
  "0x6c", 
  "0x6d", 
  "0x6e", 
  "0x6f", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined", 
  "undefined"
  "undefined", 
  "undefined", 
  "undefined" 
}; 


/* define device application types  */

typedef enum { 
  AnalogCOTrunk = 1 , 
  DigitalToAnalogCO = 2 , 
  AnalogTieTrunk = 3 , 
  DigitalToDigitalCO = 4 , 
  ISDNStation = 5 , 
  ISDN_DigitalTieTrunk = 6 , 
  ISDNTrunk = 7 , 
  OnPremisePOTSLine = 8 , 
  OffPremisePOTSLine = 9 , 
  SatelliteAnalogTieTrunk = 10, 
  SatelliteDigitalTieTrunk = 11, 
  AnalogTollTrunk = 12, 
  MaxDeviceApplication = 12 
} DeviceApplication; 

/* define device reset types  */

typedef enum { 
  DEVICE_RESET = 1 , 
  DEVICE_RESTART = 2 
} DeviceResetType; 

/* Device Server (CM node) types */

#define DeviceMaxServerNameSize 48 /* max size of server name */
#define DeviceMaxServers 5 /* max servers  */

typedef struct { 
  char ServerName[DeviceMaxServerNameSize]; /* uniquely identifies CM node */
} ServerIdentifier; 

typedef UINT32 ServerTcpListenPort; /* CM server listening port for Devices */

/* Device Unregister types */

typedef enum { 
  UnregisterOk = 0 , 
  UnregisterError, 
  UnregisterNAK /* Unregister requ est is rejected for reaso n such as existence of a call */
} DeviceUnregisterStatus; 




#define StationMaxCapabilities DeviceMaxCapabilities 


/* define the session request types */

typedef enum { 
  StChat = 1 , 
  StWhiteboard = 2 , 
  StApplicationSharing = 4 , 
  StFileTransfer = 8 , 
  StVideo = 0x10 
  } SessionType; 


/* defines key pad buttons; note the values are defined for easy convertion to and from integers. */




/* define ring types (definitions TBD) */

typedef enum { 
  StationRingOff = 0x1, 
  StationInsideRing = 0x2, 
  StationOutsideRing = 0x3, 
  StationFeatureRing = 0x4 
} StationRingMode; 

static char *StationOutputSetRingerList[] = { 
  "undefined", "RingOff", 
  "InsideRing", 
  "OutsideRing", 
  "FeatureRing", 
  "undefined" 
}; 




/* define hook flash detection mode */

typedef enum { 
  StationHookFlashOn = 1 , 
  StationHookFlashOff = 2 
} StationHookFlashDetectionMode; 

/* define station speaker modes: 
 * speaker on (Off Hook) - The speaker is enabled and the phone is logically put in the "off hook" state. 
 * Audio to the phone is played through the speaker. 
 * speaker off - The speaker is disabled. If the handset is physically "off hook", audio is 
 * directed to the hand set; otherwise the phone is put in a logical "on hook" state. 
 */

typedef enum { 
  StationSpeakerOn = 1 , 
  StationSpeakerOff = 2 
} StationSpeakerMode; 

/* define station microphone modes; 
 * Mic On - The speakerphone's microphone is turned on ONLY if the phone is in the "Speaker On (Off Hook)" 
 * state (see above). 
 * Mic Off - The microphone is turned off or, if it's not on, the command is ignored. 
 */

typedef enum { 
  StationMicOn = 1 , 
  StationMicOff = 2 
} StationMicrophoneMode; 

/* define station identifier and associated types */

typedef UINT32 StationUserId; 
typedef UINT32 StationInstance; 

typedef struct { 
  char DeviceName[StationMaxDeviceNameSize]; /* uniquely identifies station device */
  StationUserId reserved_for_future_use; 
  StationInstance instance; /* normally set to 1  */
} StationIdentifier; /* define station button template values; to specify keypad buttons */

/* use BtKeypad for the button definition with a StationKeypadButton 
 * value as the instance number; to specify an undefined button, you 
 * must set buttonDefintion to BtUndefined. 
 */

#define BtLastNumberRedial SsLastNumberRedial 
#define BtSpeedDial SsSpeedDial 
#define BtHold SsHold 
#define BtTransfer SsTransfer 
#define BtForwardAll SsForwardAll 
#define BtForwardBusy SsForwardBusy 
#define BtForwardNoAnswer SsForwardNoAnswer 
#define BtDisplay SsDisplay 
#define BtLine SsLine 
#define BtT120Chat SsT120Chat 
#define BtT120Whiteboard SsT120Whiteboard 
#define BtT120ApplicationSharing SsT120ApplicationSharing 
#define BtT120FileTransfer SsT120FileTransfer 
#define BtVideo SsVideo 
#define BtAnswerRelease SsAnswerRelease 
#define BtKeypad 0xf0 
#define BtAEC 0xfd 
#define BtUndefined 0xff 

typedef struct { 
  UINT8 instanceNumber; /* set to instance number or StationKeyPadButton value */
  UINT8 buttonDefinition; /* set to one of the preceding Bt values */
} StationButtonDefinition; 

typedef struct { 
  UINT32 buttonOffset;	/* 
			 * table offset of buttons; normally zero; for example, if 
			 * 40, then 1st definition defines button 40, 2nd 41, etc 
			 */
  UINT32 buttonCount;	/* buttons defined in this message -- StationButtonDefintion 
			 * fields used; fields greater than buttonCount are undefined 
			 */
  UINT32 totalButtonCount; /* total buttons defined for the station */
  StationButtonDefinition definition[StationMaxButtonTemplateSize]; 
} StationButtonTemplate; 

typedef enum { 
  meNone, /* no enunciation */
  meCallPark /* enunciation for call park */
} MediaEnunciationType; 





typedef struct { 
  char softKeyLabel[StationMaxSoftKeyLabelSize]; /* null terminated string */
  guint32 softKeyEvent; /* set to one of the preceding soft key event values */
} StationSoftKeyDefinition; 

typedef struct { 
  guint32 softKeyOffset; /* table offset of softKeys; normally zero; for example, if 
			 * 5, then 1st definition defines softkey 6, 2nd 7, etc 
			 */
  guint32 softKeyCount;	/* # o f softkeys defined in this message (1 - 32). 
			 * fields greater than softKeyCount are undefined 
			 */
  guint32 totalSoftKeyCount; /* total softkeys defined for the station (1 - 256) */
  StationSoftKeyDefinition definition[StationMaxSoftKeyDefinition]; 
} StationSoftKeyTemplate; 

typedef struct { 
  guint8 softKeyTemplateIndex[StationMaxSoftKeyIndex]; /* Index of the downloaded softkey template */
  guint16 softKeyInfoIndex[StationMaxSoftKeyIndex]; /* Index of the soft key description informatin */
} StationSoftKeySetDefinition; 

typedef struct { 
  guint32 softKeySetOffset;	/* table offset of softKey sets; normally zero; for example, if
				 * 5, then 1st definition defines softkey set 5, 2nd 6, etc 
				 */
  guint32 softKeySetCount;	/* # o f softkey sets defined in this message (1 - 32). 
				 * fields greater than softKeySetCount are undefined 
				 */
  guint32 totalSoftKeySetCount;	/* total softkey sets defined for the station (1 - 256) */
  StationSoftKeySetDefinition definition[StationMaxSoftKeySetDefinition]; 
} StationSoftKeySets; 



/* Defined the Call States to be sent to the Telecaste station. 
 * These are NOT the call states used in CM internally. Instead, 
 * they are the call states sent from CM and understood by the Telecaster station 
 */

typedef enum { 
  TsOffHook = 1 , 
  TsOnHook = 2 , 
  TsRingOut = 3 , 
  TsRingIn = 4 , 
  TsConnected = 5 , 
  TsBusy = 6 , 
  TsCongestion = 7 , 
  TsHold = 8 , 
  TsCallWaiting = 9 , 
  TsCallTransfer = 10, 
  TsCallPark = 11, 
  TsProceed = 12, 
  TsCallRemoteMultiline = 13, 
  TsInvalidNumber = 14 
} StationDCallState; 

/* Defined Call Type */

typedef enum { 
  TsInBoundCall = 1 , 
  TsOutBoundCall = 2 , 
  TsForwardCall = 3 
} StationCallType; 


/* Define the call status text to be sent to the Telecaster station */

static char *TsCallStatusText[] = {
  "Your current options", 
  "Off Hook", 
  "On Hook", 
  "Ring Out", 
  "From ",
  "Connected", 
  "Busy", 
  "Line In Use", 
  "Hold",
  "Call Waiting", 
  "Call Transfer", 
  "Call Park", 
  "Call Proceed", 
  "In Use Remotely" 
}; 

/* Each identifier defines a unique message  */

typedef guint32 StationMessageID; 

/*
 *
 * Received from station
 *
 */
/* Request a Station Registration token. */

struct StationRegisterTokenReq {
  StationMessageID messageID; 
  StationIdentifier sid; 
  guint32 stationIpAddr; 
  guint32 deviceType; 
}; 

/* Register the station with the server */

struct StationRegisterMessage {
  StationMessageID messageID;
  StationIdentifier sid;
  guint32 stationIpAddr;
  guint32 deviceType;
  guint32 maxStreams;
};

/* Un-register the station with the server */
struct StationUnregisterMessage { 
  StationMessageID messageID; 
}; 

/* */
struct StationIpPortMessage { 
  StationMessageID messageID; 
  guint32 stationIpPort;
}; 

/* Notify the server a keypad button was pressed. This message 
 * can also be reversed -- sent from server to station to indicate 
 * button presses (example use would be to implement a voice recorder 
 * by emulating a station). 
 */
struct StationKeypadButtonMessage { 
  StationMessageID messageID; 
  guint32 kpButton; 
}; 

/*
 * Notify the server to make a call to the specified number; 
 * equilvalent to an offhook followed by a sequence of keypad button messages 
 */
struct StationEnblocCallMessage { 
  StationMessageID messageID; 
  char calledParty[StationMaxDirnumSize]; 
}; 

/* Notify the server of a functional stimulus  */
struct StationStimulusMessage { 
  StationMessageID messageID; 
  guint32 stimulus; 
  guint32 stimulusInstance; /* normally set to 1 (except speed dial and line) */
}; 

/* Notify the server the phone has went off hook */
struct StationOffHookMessage { 
  StationMessageID messageID; 
}; 

/* Notify the server the phone has went on hook */ 
struct StationOnHookMessage { 
  StationMessageID messageID; 
}; 

/* Notify the server a hook flash has occurred */
struct StationHookFlashMessage { 
  StationMessageID messageID; 
}; 

/* Requests Call Forward status for a particular line number */
struct StationForwardStatReqMessage { 
  StationMessageID messageID; 
  guint32 lineNumber; 
}; 

/* Request speed dial status for a particular number */
struct StationSpeedDialStatReqMessage { 
  StationMessageID messageID; 
  guint32 speedDialNumber; 
}; 

/* Request dirnum for a particular line number */
struct StationLineStatReqMessage { 
  StationMessageID messageID; 
  guint32 lineNumber; 
}; 

/* Requests configuration info such as SID, user name, server name */
struct StationConfigStatReqMessage { 
  StationMessageID messageID; 
}; 

/* Requests a time/data update */
struct StationTimeDateReqMessage { 
  StationMessageID messageID; 
}; 

/* Requests button template update; multiple messages may be returned */
struct StationButtonTemplateReqMessage { 
  StationMessageID messageID; 
}; 

/* Requests version number of station load */
struct StationVersionReqMessage { 
  StationMessageID messageID; 
}; 

/* Received from the station to show link is alive  */
struct StationKeepAliveMessage { 
  StationMessageID messageID; 
}; 

/* Reports this stations capabilities to the server */
struct StationCapabilitiesRes { 
  StationMessageID messageID; 
  guint32 capCount; 
  /* Big time kludgy haxor!
   * MediaCapabilityStructure caps[StationMaxCapabilities]; 
   * did i say 8 ? i meant 7 =)
  */
  MediaCapabilityStructure caps[7];
}; 

/* Notifies server of alarm condition */
struct StationAlarmMessage { 
  StationMessageID messageID; 
  guint32 alarmSeverity; 
  char text[80]; /* describes alarm condition */
  guint32 parm1; /* optional first parameter to further describe alarm */
  guint32 parm2; /* optional second parameter to further describe alarm */
}; 

/* */
struct StationServerReqMessage { 
  StationMessageID messageID; 
}; 

/* 
 * response to the connection statistics request
 * note cisco sucks and the latency field is 100% BS
 *
 */
struct StationConnectionStatisticsResMessage { 
  StationMessageID messageID; 
  char directoryNum[StationMaxDirnumSize]; 
  guint32 callIdentifier; 
  guint32 statsProcessingMode; /* StatsProcessingType */
  guint32 numberPacketsSent; 
  guint32 numberOctetsSent; 
  guint32 numberPacketsReceived; 
  guint32 numberOctetsReceived; 
  guint32 numberPacketsLost; 
  guint32 jitter; 
  guint32 latency; 
}; 

/* 
 * Notify the server the phone has went off hook and inform it of the calling party number 
 */ 

struct StationOffHookWithCgpnMessage { 
  StationMessageID messageID; 
  char callingPartyNumber[StationMaxDirnumSize]; 
}; 

/* Requests softkey template update; multiple messages may be returned */
struct StationSoftKeyTemplateReqMessage { 
  StationMessageID messageID; 
}; 

/* Requests softkey set update/download; multiple messages may be returned */
struct StationSoftKeySetReqMessage { 
  StationMessageID messageID; 
}; 

/* SoftKey event report from the Telecaster station */
struct StationSoftKeyEventMessage { 
  StationMessageID messageID; 
  guint32 softKeyEvent; /* set to one of the preceding soft key event values */
  guint32 lineInstance; /* indicates which call plane */
  guint32 callReference; /* Reference ID */
}; 


/* returned to the station to show link is alive */

struct StationKeepAliveAckMessage { 
  StationMessageID messageID; 
}; 

/* Acknowledge to the station that registration with server is complete */
struct StationRegisterAckMessage { 
  StationMessageID messageID; 
  guint32 keepAliveInterval;	              /* seconds; keep-alive must be received from the station 
					       *at least with this frequency 
					       */
  char dateTemplate[StationDateTemplateSize]; /* date template in the form M/D/YA 
					       * M,D,Y in any order, A for AM/PM, anything else for 24 Hr.
					       */
  guint32 secondaryKeepAliveInterval;         /* seconds; This is for the connection between the 
					       * station and the secondary Call Manager
					       */
}; 

/* Acknowledge the token request */
struct StationRegisterTokenAck { /* New feature to be enabled in CCM 3.1 */
  StationMessageID messageID; 
}; 

/* Reject the token request.... Try again please... */

struct StationRegisterTokenReject { /* New feature to be enabled in CCM 3.1 */
  StationMessageID messageID; 
  UINT32 waitTimeBeforeNextReq; 
}; 

/* Acknowledge to the station that Un-registration with the server is complete */

struct StationUnregisterAckMessage { 
  StationMessageID messageID; 
  DeviceUnregisterStatus status; /* Status of the unregistration from Server. */
}; 

/* Acknowledge to the station that registration with server is complete */
struct StationRegisterRejectMessage { 
  StationMessageID messageID; 
  char text[StationMaxDisplayTextSize]; /* null terminated string */
}; 

/* Notify the station to play a tone; if a tone is already being
 * played, the new tone will supercede the old one; If the tone 
 * definition is continuous, the tone will play until the 
 * StationStopToneMessage is received. If the tone definition has 
 * a fixed interval, the tone will automatically stop at the end.
 */

struct StationStartToneMessage { 
  StationMessageID messageID; 
DeviceTone tone; 
}; 

/* Notify the station to stop any tone being played */
struct StationStopToneMessage { 
  StationMessageID messageID; 
}; 

/* Notify the station to set the ringer mode */
struct StationSetRingerMessage { 
  StationMessageID messageID; 
  StationRingMode ringMode; 
}; 

/* Notify the station to set a particular lamp's display mode */
struct StationSetLampMessage { 
  StationMessageID messageID; 
  guint32 stimulus; 
  guint32 stimulusInstance; /* normally set to 1 (except speed dial and line) */
  guint32 lampMode; 
}; 

/* Notify the station of the hook flash detection interval */
struct StationSetHkFDetectMessage { 
  StationMessageID messageID; 
  StationHookFlashDetectionMode hfdMode; 
  UINT32 detectInterval; /* detectInterval is in milliseconds */
}; 

/* Notify the station of the speaker mode */
struct StationSetSpeakerModeMessage { 
  StationMessageID messageID; 
  StationSpeakerMode speakerMode; 
}; 

/* Notify the station of the microphone mode */
struct StationSetMicroModeMessage { 
  StationMessageID messageID; 
  StationMicrophoneMode micMode; 
}; 

/* Notify the station it may start session transmission to the given 
 * transport address
 */
struct StationStartSessionTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 remoteIpAddr; 
  SessionType sessionType; 
}; 

/* Notify the station to stop session transmission */
struct StationStopSessionTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 remoteIpAddr; 
  SessionType sessionType; 
}; 

/* Notify the station it may start transmission to the given 
 * rtp address 
*/

struct StationStartMediaTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
  UINT32 remoteIpAddr; 
  UINT32 remotePortNumber; 
  UINT32 millisecondPacketSize; 
  guint32 compressionType; /* Media_PayloadType */
  Media_QualifierOutgoing qualifierOut; 
}; 

/* Notify the station to stop transmission */
struct StationStopMediaTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
}; 

/* Notify the station to open an inbound media channel */
struct StationOpenReceiveChannelMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
  UINT32 millisecondPacketSize; 
  guint32 compressionType; /* Media_PayloadType */
  Media_QualifierIncoming qualifierIn; 
}; 


/* Acknowledgement to Open Receive Channel */
struct StationOpenReceiveChannelAckMessage { 
  StationMessageID messageID; 
  guint32 orcStatus; /* OpenReceiveChanStatus */
  guint32 ipAddr; 
  guint32 portNumber; 
  guint32 passThruPartyID; 
}; 

/* Close logical channel */
struct StationCloseReceiveChannelMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
}; 

/*
 * Notify the station to perform a reset (i.e. break the TCP/IP connection, 
 * reread the config file, and reregister) 
 */

struct StationReset { 
  StationMessageID messageID; 
  DeviceResetType resetType; 
}; 

/* Notify the station of call related info for incoming call; */
struct StationCallInfoMessage { 
  StationMessageID messageID; 
  char callingPartyName[StationMaxNameSize]; 
  char callingParty[StationMaxDirnumSize]; 
  char calledPartyName[StationMaxNameSize]; 
  char calledParty[StationMaxDirnumSize]; 
  UINT32 lineInstance; /* indicates which DN line that this call is on */
  UINT32 callReference; /* Differentiate between multiple calls in a D N line */
  StationCallType callType; /* INBOUND=1, OUTBOUND=2, FORWARD=3 */
  char originalCalledPartyName[StationMaxNameSize]; 
  char originalCalledParty[StationMaxDirnumSize]; 
}; 

/* 
 * Notify station of Call Forward status for a particular line number;
 * may be sent at any time
 */
struct StationForwardStatMessage { 
  StationMessageID messageID; 
  UINT32 activeForward; /* if nonzero, station is forwarded in at 
			 * least one of the following modes UINT32 lineNumber; 
			 * call forward all takes precedence over busy and no-answer 
			 */
  UINT32 forwardAllActive; /* if nonzero, forwarded all */
  char forwardAllDirnum[StationMaxDirnumSize]; 
  UINT32 forwardBusyActive; /* if nonzero, forward busy */
  char forwardBusyDirnum[StationMaxDirnumSize]; 
  UINT32 forwardNoAnswerActive; /* if nonzero, forward no answer */
  char forwardNoAnswerlDirnum[StationMaxDirnumSize]; 
}; 

/* 
 * Notify station of speed dial status for a particular number; 
 * may be sent at any time 
 */
struct StationSpeedDialStatMessage { 
  StationMessageID messageID; 
  guint32 speedDialNumber; /* forwarded line number */
  char speedDialDirNumber[StationMaxDirnumSize]; 
  char speedDialDisplayName[StationMaxNameSize]; 
}; 

/*
 * Notify station of dirnum for a particular line number; 
 * may be sent at any time 
*/
struct StationLineStatMessage { 
  StationMessageID messageID; 
  guint32 lineNumber; /* forwarded line number */
  char lineDirNumber[StationMaxDirnumSize]; 
  char lineFullyQualifiedDisplayName[StationMaxNameSize]; 
}; 

/*
 * Notify station of configuration info 
 *may be sent at any time 
 */
struct StationConfigStatMessage { 
  StationMessageID messageID; 
  StationIdentifier sid; 
  char userName[StationMaxNameSize]; 
  char serverName[StationMaxNameSize]; 
  UINT32 numberOfLines; 
  UINT32 numberOfSpeedDials; 
}; 

/*
 * Notify the station of the current time and date; this is required to 
 * sync the time between stations; may be sent at any time 
 */
struct StationDefineTimeDateMessage { 
  StationMessageID messageID; 
  guint32 year; 
  guint32 month; 
  guint32 dayOfWeek; 
  guint32 day; 
  guint32 hour; 
  guint32 minute; 
  guint32 seconds;
  guint32 milliseconds; 
  guint32 systemTime; 
}; 

/* Notify the station to update its button template; multiple messages may be sent */
struct StationButtonTemplateMessage { 
  StationMessageID messageID; 
  StationButtonTemplate buttonTemplate; 
}; 

/* Notify station of the version it should be running */
struct StationVersionMessage { 
  StationMessageID messageID; 
  char version[StationMaxVersionSize]; 
}; 

/*
 * Notify station to display the specified text string; 
 * The station will pad the unused display field with blanks; 
 * The client can clear the whole field by sending an empty text string.
 */
struct StationDisplayTextMessage { 
  StationMessageID messageID; 
  char text[StationMaxDisplayTextSize]; /* null terminated string */
}; 

/* Notify station to clear its display. */
struct StationClearDisplay { 
  StationMessageID messageID; 
}; 

/* request Station to return its current capabilities */
struct StationCapabilitiesReq { 
  StationMessageID messageID; 
}; 

/* request Station to enunciate message in the media stream */
struct StationEnunciatorCommand { 
  StationMessageID messageID; 
  MediaEnunciationType intro_message; 
  guint32 enunciationList[StationMaxDirnumSize]; 
  MediaEnunciationType terminating_message; 
}; 

struct StationServerResMessage { 
  StationMessageID messageID; 
  ServerIdentifier server[StationMaxServers]; 
  ServerTcpListenPort serverTcpListenPort[StationMaxServers]; 
  UINT32 serverIpAddr[StationMaxServers]; 
}; 

struct StationConnectionStatisticsReqMessage { 
  StationMessageID messageID; 
  char directoryNum[StationMaxDirnumSize]; 
  guint32 callIdentifier; 
  guint32 statsProcessingMode; /* StatsProcessingType */
}; 


/* Notify a station to start receiving from a multicast address */
struct StationStartMulticastMediaReceptionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
  UINT32 multicastIpAddr; 
  UINT32 multicastPortNumber; 
  UINT32 millisecondPacketSize; 
  guint32 compressionType; /* Media_PayloadType */
  Media_QualifierIncoming qualifierIn; 
}; 

/* MulicastReception Acknowledgement  0x21 */
struct StationMulticastMediaReceptionAckMessage { 
  StationMessageID messageID; 
  guint32 receptionStatus; /* MulticastMediaReceptionStatus */
  guint32 passThruPartyID; 
}; 

/* Notify the station it may start transmission to the given 
 * multicast address
 */
struct StationStartMulticastMediaTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
  UINT32 multicastIpAddr; 
  UINT32 multicastPortNumber; 
  UINT32 millisecondPacketSize; 
  guint32 compressionType; /* MediaPayloadType */
  Media_QualifierOutgoing qualifierOut;
}; 

/* Stop multicast reception */
struct StationStopMulticastMediaReceptionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
}; 

/* Stop multicast transmission */
struct StationStopMulticastMediaTransmissionMessage { 
  StationMessageID messageID; 
  UINT32 conferenceID; 
  UINT32 passThruPartyID; 
}; 

/* Notify the Telecaster station to update its softkey template; 
 * multiple messages may be sent 
 */
struct StationSoftKeyTemplateResMessage { 
  StationMessageID messageID; 
  StationSoftKeyTemplate softKeyTemplate; 
}; 

/* Notify the Telecaster station to update/download its softkey sets
 * multiple messages may be sent 
 *
 */
struct StationSoftKeySetResMessage { 
  StationMessageID messageID; 
  StationSoftKeySets softKeySets; 
}; 


/*
 * Notify the Telecaster station to update the softkey mapping 
 * in the designated call plane 
 */
struct StationSelectSoftKeysMessage { 
  StationMessageID messageID; 
  guint32 instance; /* Line/Call Plane. Normally set to1-6 */
  guint32 reference; /* Indicate which call within the call plane */
  guint32 softKeySetIndex; /* Index of the new soft ket sets (0 - 255) */
  guint32 validKeyMask; /* UINT32 is used instead of UINT16 due to alligment issue 
			* As default, all the bits are 1 (valid) even for undefined 
			* soft key position. If a bit is zero, then the soft key with 
			* the bit position is invalid (shaded). The bit 0 (the less 
			* significant bit) indicates index 0 o f the soft key array[16]. 
			*/
}; 

/* Notify the Telecaster station of the call related info */
struct StationCallStateMessage { 
  StationMessageID messageID; 
  StationDCallState callState;	
				
  UINT32 lineInstance; /* indicates which DN line that this call is on */
  UINT32 callReference; /* Differentiate between multiple calls in a D N line */
}; 

/*
 * Notify the Telecaster station to display the specified status string; 
 * The station will pad the unused display field with blanks; 
 */
struct StationDisplayPromptStatusMessage { 
  StationMessageID messageID; 
  guint32 timeOutValue; /* in seconds */
  char promptStatus[StationMaxDisplayPromptStatusSize]; /* null terminated string; max 32 */
  guint32 lineInstance; /* indicates which DN line that this call is on */
  guint32 callReference; /* Differentiate between multiple calls in a D N line */
}; 

/* Notify the Telecaster station to clear its display. */
struct StationClearPromptStatusMessage { 
  StationMessageID messageID; 
  UINT32 lineInstance; /* indicates which DN line that this call is on */
  UINT32 callReference; /* Differentiate between multiple calls in a D N line */
}; 

/* Notify the Telecaster station to display the specified text string; 
 * The station will pad the unused display field with blanks; 
 */
struct StationDisplayNotifyMessage { 
  StationMessageID messageID; 
  UINT32 timeOutValue; /* in seconds */
  char notify[StationMaxDisplayNotifySize]; /* null terminated string; max 32 char */
}; 


/* Notify the Telecaster station to clear its display. */
struct StationClearNotifyMessage { 
  StationMessageID messageID; 
}; 

/* Request to activate a specific call plane */
struct StationActivateCallPlaneMessage { 
  StationMessageID messageID; 
  UINT32 lineInstance; /* indicates which call plane to be activated */
}; 

/* Request to deactivate the active call plane */
struct StationDeactivateCallPlaneMessage { 
  StationMessageID messageID; 
}; 

/* Tell the telecaster station to backspace the last dialed digit */
struct StationBackSpaceReqMessage { 
  StationMessageID messageID; 
  guint32 lineInstance; /* indicates which DN line that this call is on */
  guint32 callReference; /* Differentiate between multiple calls in a D N line */
};