/*  $Id: pdu.c,v 1.17 2000/02/19 19:11:42 remlali Exp $
 *
 *  pdu.c -- Copyright 1999 Larry Liimatainen
 * 
 *  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, Cambridge, MA 02139, USA.
 *
 *  pdu.c
 *  
 */


/*   
 * All these functions operate on a packet that is
 * sent between database daemon and the client API.
 *
 *
 * PROTOCOL LAYOUT
 *
 * +--------+--------+--------+--------+---------+-----+
 * | Action | Length | ObjLen | Object | Members | ... |
 * +--------+--------+--------+--------+---------+-----+
 * <------------- Header -------------><--- PDU ------->
 *
 * HEADER:
 *
 *    Action is a 32bit integer telling upper layer what 
 *    to do with data in PDU.
 *
 *    Length is a 32bit integer and has the size of header
 *    length and PDU length.
 *
 *    ObjLen is the length of Object in header.
 *
 *    Object is a single piece of data, used to represent
 *    a database table.
 * 
 * PDU
 *
 *    The PDU consist of one or more Members. Each
 *    member has following layout:
 *
 *    +--------------+------------+------------+
 *    | memberLength | memberType | MemberData | 
 *    +--------------+------------+------------+
 *
 *    memberLength is the length of the Member.
 *
 *    memberType tells upper layer how to read
 *    data in MemberData, ie a string, integer..
 *
 *    memberData holds actual data, that usually
 *    represent a field in a database row that is
 *    processed.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "g_sqldb.h"
#include "tables.h"
#include "gxsnmpdb.h"

/* debug_decode_output()
 *
 * use this to get a quick look at your packet, before entering gdb
 * n is offset
 * packet is source of output
 * offset is offset to rewind
 * len is how much data to output
 *
 */
void debug_decode_output(gint *n, unsigned char *packet, gint offset, gint len)
{
unsigned char c;
gint i;

  fprintf(stderr,"\ndatadump: n is %d, start is n - %d, printing %d bytes\n", *n, offset, len);
  i = *n;
  i -= offset;
  for(;len;len--){
    c = *(packet +i);
    fprintf(stderr,"%x ", c);
    i++; 
  }
  fprintf(stderr,"\n");
}

/* get_member()
 * decodes depending on memberType to buffer or integer
 *
 *
 */
                                                          
gint get_member(gint *n, void *packet, char *buffer, int *bufint){
gint ml, mt;                                                                     
            
  *bufint = 0;	/* assurance to avoid segfaults */
  buffer[0] = 0;
  memcpy(&ml, packet+*n, sizeof(gint));     /*get MemberLen*/
  *n += sizeof(gint);                                        
  if(ml<8){
    fprintf(stderr,"MemberLen is invalid\n");
    debug_decode_output(n, packet, 20, 40);
    return -1;
  }                     
  memcpy(&mt, packet+*n, sizeof(gint));     /*get MemberType*/
  *n += sizeof(gint);
  if(ml == 8){                              /* we got a empty memberrecord, its OK ( SQL field is NULL or something)*/
    switch(mt)
      {
        case PDUMEMTYPE_INT:
          *bufint = 0;
          return PDUMEMTYPE_INT;
        case PDUMEMTYPE_STR:
          *buffer = 0;
          return PDUMEMTYPE_STR;
      }
  }
  switch(mt){
    case PDUMEMTYPE_INT:
      memcpy(bufint, packet+*n, sizeof(gint));
      *n += sizeof(gint);
      return PDUMEMTYPE_INT;
    case PDUMEMTYPE_STR:
      ml -= sizeof(gint) * 2;		/*length of memberData is: *memberLen - sizeof(memberLen) - sizeof(memberType)*/
      memcpy(buffer, packet+*n, ml);
      buffer[ml] = 0;
      *n += ml;				/* advance packetpointer with sizeof(memberData) */
      return PDUMEMTYPE_STR;
    default:     /*decode error*/
      fprintf(stderr,"get_member(): APP_ERR packet decode error, undefined struct member\n");
      debug_decode_output(n, packet, 20, 40);
      return 0;
  }
  return 0;
}

void 
add_guint (gint *n, gpointer packet, guint data)
{
gint tmp;
  
  tmp = sizeof(guint) * 3;				/* MemberLength is set to Len of itself + MemberType + MemberData*/
  memcpy(packet+*n, &tmp, sizeof(guint));		/* cpy MemberLength */
  *n += sizeof(guint);
  tmp = PDUMEMTYPE_INT;
  memcpy(packet+*n, &tmp, sizeof(guint));		/* cpy MemberType */
  *n += sizeof(guint);
  memcpy(packet+*n, &data, sizeof(guint));		/* cpy MemberData */
  *n += sizeof(guint);
}
void
add_asciiz (gint *n, gpointer packet, gpointer str)
{
static gchar nullstr[] = "";
gint  j, tmp;

  if(!str) str = &nullstr;
  else j   = strlen ((gchar *)str);
  tmp = (sizeof (guint) * 2) + j;		/*tmp holds length of MemberLen + MemberType + MemberData */
  memcpy (packet+*n, &tmp, sizeof (guint));
  *n += sizeof (guint);
  tmp = PDUMEMTYPE_STR;
  memcpy (packet+*n, &tmp, sizeof (guint));
  *n += sizeof (guint);
  memcpy (packet+*n, str, j);
  *n += j;
}

gint
set_pdu_header(gpointer packet, gint type, gint table_name)
{

  memcpy(packet, &type, sizeof(gint));				/*set action type*/
  memcpy(packet+(sizeof(gint) * 2), &table_name, sizeof(gint));	/*copy table name*/
  return sizeof(gint) * 3;                                    	/*header length*/
}
