/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 picoiiop - network support for picoSQL

 Copyright (C) Picosoft s.r.l. 1994-2002

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library 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
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
# ifdef WIN32
# include <io.h>
# include <windows.h>
# else
# include <unistd.h>
# endif
#include <stdlib.h>
#include <string.h>
#include "iiopobj.h"
#include "log.h"
static char *rcsid = "$Id: iiopobj.c,v 1.1 1999/06/03 11:42:53 picoSoft Exp $";
static char *rcsidh = iiopobj_h;
#define STRING_ID "IDL:picoRPC:1.0"
#define KEY_ID "key"

# define ToHex(dst,src)  { \
   *dst = (unsigned char) src / 16; \
   if (*dst > 9) \
      *dst += 'A' - 10; \
   else \
      *dst += '0'; \
   *++dst = (unsigned char)src % 16; \
   if (*dst > 9) \
      *dst += 'A' - 10; \
   else \
      *dst += '0'; \
   dst++; \
}

#define fromHex(c) ((c < '0') ? -1 : ( \
                     (c <= '9') ?  c - '0' : ( \
                       (c < 'A')  ?  -1 : ( \
                         (c <= 'F') ? c - 'A' + 10 : ( \
                           (c < 'a')  ? -1 : ( \
                             (c <= 'f') ?   c - 'a' + 10 :  -1) \
                           ) \
                         ) \
                       ) \
                     ) \
                   )

IiopObj *
IiopObj_new (int p, CORBA_Octet *k, int lenk)
{
   char buffer[128];
   IiopObj *this = (IiopObj *)malloc (sizeof(IiopObj));
   if (this &&
       (this->key = (CORBA_Principal *)malloc (sizeof(CORBA_Principal)))) {
      this->host = 0;
      this->key->data = (CORBA_Octet *) malloc (lenk);
      if (this->key->data && !gethostname (buffer, sizeof(buffer)) &&
          (this->host = malloc(strlen(buffer) + 1))) {
         this->majorVer = GIOP_MAJ_VER;
         this->minorVer = GIOP_MIN_VER;
         strcpy (this->host, buffer);
         this->port = p;
         memcpy (this->key->data, k, lenk);
         this->key->size = lenk;
      } else {
         IiopObj_delete (this);
         this = 0;
      }
   }
   return this;
}

void
IiopObj_delete (IiopObj *this)
{
   if (this) {
      if (this->key) {
         if (this->key->data)
            free(this->key->data);
         free (this->key);
      }
      if (this->host)
         free(this->host);
      free(this);
   }
}

char *
IiopObj_toString (IiopObj *this)
{
   char * Return;
   char *pnt;
   unsigned char *buf;
   Message *msg = Message_new();
   CORBA_ULong offsLenProfile;
   CORBA_ULong lenFix;
   CORBA_ULong lenMsg;

   Message_putBoolean (msg, msg->myByteOrder);
   Message_putString (msg, STRING_ID);
   Message_putULong (msg, 1);           /* numero profili */
   Message_putULong (msg, TAG_INTERNET_IOP);
   offsLenProfile = Message_skipBytes (msg, sizeof (CORBA_ULong)) -
                                       msg->logicBuffer;
   lenFix = Message_getSize(msg);
   Message_putBoolean (msg, msg->myByteOrder);
   Message_putByte (msg, this->majorVer);
   Message_putByte (msg, this->minorVer);
   Message_putString (msg, this->host);
   Message_putUShort (msg, this->port);
   Message_putString (msg, KEY_ID);
   lenMsg = Message_getSize(msg);
   *((CORBA_ULong *)&msg->logicBuffer[offsLenProfile]) = lenMsg - lenFix;
   Return = pnt = malloc (lenMsg * 2 + 4 + 1);
   *pnt++ = 'I';
   *pnt++ = 'O';
   *pnt++ = 'R';
   *pnt++ = ':';
   buf = Message_getBuffer (msg, lenMsg, msg->myByteOrder);
   for ( ; lenMsg > 0; lenMsg--, buf++)
      ToHex(pnt,*buf);
   *pnt = '\0';
   Message_delete (msg);
   return Return;
}

IiopObj *
IiopObj_newFromString (char *ior)
{
   IiopObj *this = 0;
   if (ior && ior[0] == 'I'&&ior[1] == 'O' && ior[2] == 'R' && ior[3] == ':') {
      int rc;
      Message *msg = Message_new();
      int len = strlen (ior) / 2;
      unsigned char *buf = Message_getBuffer (msg, len, ior[5] - '0');
      char *pnt = &ior[4];

      CORBA_String str = 0;
      unsigned long ret_long;
      unsigned char c;

      this = (IiopObj *)malloc (sizeof(IiopObj));

      while (*pnt && pnt[1]) {
         if ((rc = fromHex(*pnt)) < 0)
            break;
         else
            c = rc * 16;
         pnt++;
         if ((rc = fromHex(*pnt)) < 0)
            break;
         else
            c += rc;
         pnt++;
         *buf++ = c;
      }
     
      Message_getByte (msg, &c);
      Log ("endian=%d", c);
 
      Message_getString (msg, &str, CORBA_True);
      Log ("str_id=%s", str);
      free (str);

      Message_getLong (msg, &ret_long);
      Log ("n_prof=%ld", ret_long);
      rc = ret_long;
      for ( ; rc > 0; rc--) {
         Message_getLong (msg, &ret_long);
         Log ("iiop=%ld", ret_long);

         if (ret_long != TAG_INTERNET_IOP) {
            Message_getLong (msg, &ret_long);
            Log ("len_prof=%ld", ret_long);
            Message_skipBytes(msg, ret_long);
            continue;
         }

         Message_getLong (msg, &ret_long);
         Log ("len_prof=%ld", ret_long);

         Message_getByte (msg, &c);
         Log ("endian=%d", c);

         Message_getByte (msg, &this->majorVer);
         Log ("maj n=%d", this->majorVer);

         Message_getByte (msg, &this->minorVer);
         Log ("maj n=%d", this->minorVer);

         Message_getString (msg, &this->host, CORBA_True);
         Log ("host  =%s", this->host);

         Message_getShort (msg, &this->port);
         Log ("port    =%d", this->port);

         Message_getPrincipal (msg, &this->key, CORBA_True);
         Log ("key_size=%ld %s\n", this->key->size, this->key->data);
      }
      Message_delete (msg);
   }
   return this;
}
