/*
 * Copyright (c) 1996, 1997, 1998, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 * All rights reserved.
 *
 * Permission to use, copy, modify and distribute this software is hereby
 * granted provided that (1) source code retains these copyright, permission,
 * and disclaimer notices, and (2) redistributions including binaries
 * reproduce the notices in supporting documentation.
 *
 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
 * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
 * improvements that they make and grant CSL redistribution rights.
 */

#include "iiop-link.h"

#include <assert.h>
#include <ctype.h>
#include <unistd.h>

#ifdef NEED_GETHOSTNAME_DECL
/*
 * `gethostname' should (?) be in <unistd.h>, but Solaris 2.5 at least doesn't
 * declare `gethostname' in any system header.
 */
int gethostname(char *name, int namelen);
#endif /* NEED_GETHOSTNAME_DECL */

/* needed only for flick_check_byte_order */
#include <flick/encode/cdr.h>

/*****************************************************************************/

char flick_is_little_endian = -1; /* not defined yet */

int flick_seqnum = 0;

#ifdef INTERFACE_DAEMON
/* Information about the simple interface repository object */
char *orb_ir_ref;
CORBA_Object orb_ir_obj;
#endif

static CORBA_ORB *orbs = 0;
static int orb_count = 0;

/*
 * XXX --- Just a stub for now.
 */
CORBA_ORB_ObjectIdList *
CORBA_ORB_list_initial_services(CORBA_ORB obj, CORBA_Environment *ev)
{
	CORBA_ORB_ObjectIdList *list;
	
	fprintf(stderr,
		"Warning: `CORBA_ORB_list_initial_services' is not yet "
		"supported.\n");
	
	list = CORBA_alloc(sizeof(CORBA_ORB_ObjectIdList));
	if (!list) {
		flick_set_exception(0 /* boa */, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		return 0;
	}
	
	list->_maximum = 0;
	list->_length = 0;
	list->_buffer = 0;
	
	ev->_major = CORBA_NO_EXCEPTION;
	
	return list;
}

/*
 * XXX --- Just a stub for now until we have at least a Naming Service.
 */
CORBA_Object
CORBA_ORB_resolve_initial_references(CORBA_ORB ths,
				     CORBA_ORB_ObjectId identifier,
				     CORBA_Environment *ev)
{
	fprintf(stderr,
		"Warning: `CORBA_ORB_resolve_initial_references' is not yet "
		"supported.\n");
	CORBA_BOA_set_exception(0 /*boa*/, ev,
				CORBA_USER_EXCEPTION,
				ex_CORBA_ORB_InvalidName,
				/*
				 * Last arg is null; see Section 17.27.2 of
				 * the CORBA 2.1 spec to see why we don't call
				 * `CORBA_ORB_InvalidName__alloc' here.
				 */
				0);
	return 0;
}

CORBA_ORB CORBA_ORB_init_internal(CORBA_ORBid ORBid,
				  CORBA_Environment *ev)
{
        unsigned int i, one = 1;
	
	flick_is_little_endian = *(char *)(&one);
	flick_check_byte_order();
	
#ifdef INTERFACE_DAEMON
	/* These are the builtin defaults */
	if( !orb_ir_ref )
		orb_ir_ref = "iiop:1.0//localhost:6000/FLICK::"
			     "interface_type/SimpleInterfaceRepository";
#endif
	if (!ORBid)
		ORBid = "FlickORB--";
	for (i = 0; i < (unsigned int) orb_count; ++i)
		if (!strcmp(orbs[i]->ORBid, ORBid))
			break;
	
	/* Set the default value for the ir ref */
	if (((int) i) == orb_count) {
		CORBA_ORB *new_orbs, orb;
				
		orb = t_calloc(struct CORBA_ORB_type, 1);
		if (!orb)
			goto err1;		
		orb->ORBid = t_malloc(char, strlen(ORBid) + 1);
		if (!orb->ORBid)
			goto err2;
		strcpy(orb->ORBid, ORBid);
		orb->OA_count = 0;
		orb->boas = 0;
		
		new_orbs = t_realloc(orbs, CORBA_ORB, (orb_count + 1));
		if (!new_orbs)
			goto err3;
		orbs = new_orbs;
		orbs[orb_count++] = orb;
#ifdef INTERFACE_DAEMON
		/* Make a reference to the simple
		   interface repository object */
		orb_ir_obj = CORBA_ORB_string_to_object( orb, orb_ir_ref, ev );
		if (ev->_major != CORBA_NO_EXCEPTION) {
			printf( "Can't get simple interface "
				"repository object.\n" );
			exit(1);
		}
#endif
		return orb;
		
	  err3:
		free(orb->ORBid);
	  err2:
		free(orb);
	  err1:
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for new ORB.\n");
		return 0;
		
	} else
		/* do nothing.  `i' is set correctly. */
	
	return orbs[i];
}


CORBA_ORB CORBA_ORB_init(int *argc, char **argv,
			 CORBA_ORBid ORBid,
			 CORBA_Environment *ev)
{
	int i, new_argc;
	
	/*****/
	
	/* No ORB --> no BOA --> no `CORBA_BOA_set_exception'. */
	ev->_major = CORBA_NO_EXCEPTION;
	
	if (!argc || !argv) {
		flick_set_exception(0 /* XXX boa */, ev,
				    ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: null `argc' or `argv' passed to "
			"`CORBA_ORB_init'.\n");
		return 0;
	}
	
	for (i = new_argc = 1; i < *argc; i++) {
		if (!strcmp(argv[i], "-ORBid") &&
		    i + 1 < *argc) {
			if (!ORBid)
				ORBid = argv[++i];
			else {
				flick_set_exception(0 /* XXX boa */, ev,
						    ex_CORBA_BAD_PARAM,
						    0, CORBA_COMPLETED_NO);
				fprintf(stderr,
					"Error: too many ORB identifiers "
					"specified.\n");
				return 0;
			}
		}
#ifdef INTERFACE_DAEMON
		else if( !strcmp( argv[i], "-ORBir") && (i + 1 < *argc) ) {
			/* The user has specified an alternative
			   reference to the simple interface repository */
			if( !orb_ir_ref )
				orb_ir_ref = argv[++i];
			else {
				flick_set_exception(0 /* XXX boa */, ev,
						    ex_CORBA_BAD_PARAM,
						    0, CORBA_COMPLETED_NO);
				fprintf(stderr,
					"Error: too many ORB identifiers "
					"specified.\n");
				return 0;
			}
		}
#endif
		else
			/* keep all of the arguments except the -ORB ones */
			argv[new_argc++] = argv[i];
	}
	/* nullify the removed arguments */
	for (i = *argc-1; i >= new_argc; i--)
		argv[i] = 0;
	/* export the modified argc */
	*argc = new_argc;
	return CORBA_ORB_init_internal(ORBid, ev);
}

CORBA_BOA CORBA_ORB_BOA_init_internal(CORBA_ORB ths,
				      CORBA_ORB_OAid OAid,
				      char *OAaddr,
				      unsigned short host_port,
				      CORBA_Environment *ev)
{
	int i;
	CORBA_BOA boa, *new_boas;
	int socket_reuseaddr_p = 1;		
	struct hostent *he; /* not on heap */
	
	/*
	 * Convert `OAaddr' into a FQDN.  If we didn't do this, the
	 * IORs for `iiop:1.0/host/foo' and `iiop:1.0/host.dom/foo'
	 * would be different.  We want them to be the same so that our
	 * server doesn't think that the two IORs refer to objects in
	 * different ORBs.  (The server expects the hostnames to be
	 * identical.)
	 */
	if (!(he = gethostbyname(OAaddr))) {
		flick_set_exception(boa /* XXX not initialized yet */, ev,
				    ex_CORBA_INV_IDENT,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: unable to identify host `%s'.\n",
			OAaddr);
		return 0;
	}
	
	/* Check to see if this BOA is already here... */
	for (i = 0; i < ths->OA_count; i++)
		if ((ths->boas[i]->hostport == host_port) &&
		    (!strcmp(ths->boas[i]->hostname, he->h_name))) {
			/* Found it! */
			if ((OAid) && !!strcmp(ths->boas[i]->OAid, OAid))
				fprintf(stderr,
					"Warning: OA id `%s' will not replace"
					" `%s' in ORB `%s'\n",
					OAid, ths->boas[i]->OAid,
					ths->ORBid);
			return ths->boas[i];
		}
	
	boa = t_calloc(struct CORBA_BOA_type, 1);
	if (!boa)
		goto err1;
	
	boa->ipaddr = t_calloc(struct sockaddr_in, 1);
	if (!boa->ipaddr)
		goto err2;
	
	boa->ipaddr->sin_addr.s_addr = *(int *)*he->h_addr_list;
	boa->ipaddr->sin_family = AF_INET;
	boa->ipaddr->sin_port = htons(host_port);
	
	/*
	 * Use the FQDN returned by `gethostbyname', not `OAaddr',
	 * because `OAaddr' may not be fully qualified.
	 */
	boa->hostname = t_malloc(char, strlen(he->h_name) + 1);
	if (!boa->hostname)
		goto err3;
	strcpy(boa->hostname, he->h_name);
	
	boa->hostport = host_port;
	boa->orb = ths;
	
	if (!OAid)
		OAid = "FlickBOA--";
	boa->OAid = t_malloc(char, strlen(OAid) + 1);
	if (!boa->OAid)
		goto err5;
	strcpy(boa->OAid, OAid);
	
	boa->in = t_calloc(FLICK_BUFFER, 1);
	if (!boa->in)
		goto err6;
	boa->in->real_buf_start = boa->in->buf_read = boa->in->buf_start
				= boa->in->buf_current = t_calloc(char, 8192);
	if (!boa->in->buf_start)
		goto err7;
	
	boa->in->real_buf_end = boa->in->buf_end
			      = ((char *) boa->in->buf_start) + 8192;
	
	boa->out = t_calloc(FLICK_BUFFER, 1);
	if (!boa->out)
		goto err8;
	boa->out->real_buf_start = boa->out->buf_read = boa->out->buf_start
				= boa->out->buf_current = t_calloc(char, 8192);
	if (!boa->out->buf_start)
		goto err9;
	
	boa->out->real_buf_end = boa->out->buf_end
			       = ((char *) boa->out->buf_start) + 8192;
	
	boa->out->buf_end = ((char *) boa->out->buf_start) + 8192;
	
	boa->count_servers = 0;
	boa->refs = 0;
	boa->socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (boa->socket_fd < 0) {
		perror("socket");
		flick_set_exception(boa, ev, ex_CORBA_COMM_FAILURE,
				    0, CORBA_COMPLETED_NO);
		goto err10;
	}
	if (setsockopt(boa->socket_fd,
		       SOL_SOCKET, SO_REUSEADDR,
		       ((void *) &socket_reuseaddr_p),
		       sizeof(socket_reuseaddr_p))
	    != 0) {
		perror("setsockopt");
		flick_set_exception(boa, ev, ex_CORBA_COMM_FAILURE,
				    0, CORBA_COMPLETED_NO);
		goto err11;
	}
	boa->connected = 0;
	
	new_boas = t_realloc(ths->boas, CORBA_BOA, ths->OA_count + 1);
	if (!new_boas)
		goto err11;
	ths->boas = new_boas;
	ths->boas[ths->OA_count++] = boa;
	
	CORBA_BOA_set_exception(boa, ev, CORBA_NO_EXCEPTION, 0, 0);
	return boa;
	
  err11:
	close(boa->socket_fd);
  err10:
	free(boa->out->buf_start);
  err9:
	free(boa->out);
  err8:
	free(boa->in->buf_start);
  err7:
	free(boa->in);
  err6:
	free(boa->OAid);
  err5:
	free(boa->hostname);
  err3:
	free(boa->ipaddr);
  err2:
	free(boa);
  err1:
	if (ev->_major == CORBA_NO_EXCEPTION)
		flick_set_exception(boa, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
 	/* set exception */
	return 0;
}

	
CORBA_BOA CORBA_ORB_BOA_init(CORBA_ORB ths, int *argc, char **argv,
			     CORBA_ORB_OAid OAid,
			     CORBA_Environment *ev)
{
	int i, new_argc;
	char *prt = 0;
	unsigned short host_port;
	char *OAaddr = 0;
	char buf[256];
	
	/*****/
	
	if (!argc || !argv) {
		flick_set_exception(0 /* XXX boa */, ev,
				    ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: null `argc' or `argv' passed to "
			"`CORBA_ORB_BOA_init'.\n");
		return 0;
	}
	
	for (i = new_argc = 1; i < *argc; i++) {
                /* XXX should change name to OAipaddr */
		if (!strcmp(argv[i], "-ORBipaddr") &&
		    (i + 1 < *argc)) {
			if (!OAaddr)
				OAaddr = argv[++i];
			else {
				flick_set_exception(0 /* XXX boa */, ev,
						    ex_CORBA_BAD_PARAM,
						    0, CORBA_COMPLETED_NO);
				fprintf(stderr,
					"Error: too many ORB addresses "
					"specified.\n");
				return 0;
			}
		} else if (!strcmp(argv[i], "-OAport") &&
			   i + 1 < *argc) {
			if (!prt)
				prt = argv[++i];
			else {
				flick_set_exception(boa, ev,
						    ex_CORBA_BAD_PARAM,
						    0, CORBA_COMPLETED_NO);
				fprintf(stderr,
					"Error: too many OA ports "
					"specified.\n");
				return 0;
			}
		} else if (!strcmp(argv[i], "-OAid") &&
			   i + 1 < *argc) {
			if (!OAid)
				OAid = argv[++i];
			else {
				flick_set_exception(boa, ev,
						    ex_CORBA_BAD_PARAM,
						    0, CORBA_COMPLETED_NO);
				fprintf(stderr,
					"Error: too many OA id's "
					"specified.\n");
				return 0;
			}
		}
		else
			/* keep all of the arguments except the -OA ones */
			argv[new_argc++] = argv[i];
	}
	/* nullify the removed arguments */
	for (i = *argc-1; i >= new_argc; i--)
		argv[i] = 0;
	
	/* export the modified argc */
	*argc = new_argc;
	
	if (!OAaddr) {
		if (gethostname(buf, 256)) {
			flick_set_exception(0 /* XXX boa */, ev,
					    ex_CORBA_INV_IDENT,
					    0, CORBA_COMPLETED_NO);
			fprintf(stderr,
				"Error: unable to get name of local host.\n");
			return 0;
		}
		OAaddr = &buf[0];
		fprintf(stderr,
			"Warning: no `-ORBipaddr' specified; using `%s'.\n",
			OAaddr);
	}
	
	if (!prt) {
		flick_set_exception(boa, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr, "Error: No `-OAport' specified.\n");
		return 0;
	}
	host_port = atoi(prt);
	return CORBA_ORB_BOA_init_internal(ths, OAid, OAaddr, host_port, ev);
}

CORBA_BOA CORBA_ORB_BOA_create(CORBA_ORB ths,
			       CORBA_ORB_OAid OAid,
			       char *OAaddr,
			       unsigned short host_port,
			       CORBA_Environment *ev)
{
	CORBA_BOA ret;
	
	if (!ths && orb_count)
		ths = orbs[0];
	if (!OAid)
		OAid = "FlickBOA--";
	
	ret = CORBA_ORB_BOA_init_internal(ths, OAid, OAaddr, host_port, ev);
	
	/* Bind to the port. */
	if (!ret->connected) {
		struct sockaddr_in server;
		int len = sizeof(struct sockaddr_in);
		
		if (bind(ret->socket_fd,
			 (struct sockaddr *)ret->ipaddr,
			 sizeof(*ret->ipaddr)) != 0) {
			perror("cannot `bind' to socket");
			flick_set_exception(ths, ev, ex_CORBA_COMM_FAILURE,
					    0, CORBA_COMPLETED_NO);
			return ret;
		}
		
		if ((getsockname(ret->socket_fd,
				 (struct sockaddr *)&server, &len) != 0)
		    || (listen(ret->socket_fd, 8) != 0)) {
			perror("cannot `getsockname' or `listen', "
			       "port may be in use");
			flick_set_exception(ths, ev, ex_CORBA_COMM_FAILURE,
					    0, CORBA_COMPLETED_NO);
			return ret;
		}
		ret->connected = 1;
	}
	
	return ret;
}

CORBA_char *CORBA_ORB_object_to_readable_string(CORBA_ORB orb,
						FLICK_TARGET obj,
						CORBA_Environment *ev)
{
	char buf[1024], *res;
	int text = 1;
	unsigned int pos;
	
	if (!obj) {
		res = t_malloc(char, strlen("iiop:1.0//") + 1);
		if (!res) {
			/* No object --> no BOA. */
			flick_set_exception(0 /*XXX*/, ev, ex_CORBA_NO_MEMORY,
					    0, CORBA_COMPLETED_NO);
			return 0;
		}
		strcpy(res, "iiop:1.0//");
		
		/* No object --> no BOA --> no `CORBA_BOA_set_exception'. */
		ev->_major = CORBA_NO_EXCEPTION;
		
		return res;
	}
	
	for (pos = 0; pos < obj->key._length && text; pos++)
		text = ((obj->key._buffer[pos] >= ' ')
			&& (obj->key._buffer[pos] <= 126));
	if (!text)
		return CORBA_ORB_object_to_string(orb, obj, ev);
	sprintf(buf, "iiop:1.0//%s:%d/%s/",
		obj->boa->hostname,
		obj->boa->hostport,
		obj->type_id);
	pos = strlen(buf);
	memcpy(&buf[pos], obj->key._buffer, obj->key._length);
	buf[pos + obj->key._length] = 0;
	
	res = t_malloc(char, strlen(buf) + 1);
	if (!res) {
		flick_set_exception(obj->boa, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
	} else {
		strcpy(res, buf);
		CORBA_BOA_set_exception(obj->boa, ev, CORBA_NO_EXCEPTION,
					0, 0);
	}
	
	return res;
}

/*
 * This converts an object into a stringified IOR, using hex digits.
 */
CORBA_char *CORBA_ORB_object_to_string(CORBA_ORB orb,
				       FLICK_TARGET obj,
				       CORBA_Environment *ev)
{
	char *buffer = 0, *res;
	unsigned int buffer_len = 0;
	unsigned int i;
	
	unsigned int endian_test = 1;
	char native_endianness = ((char *) &endian_test)[0];
	
	if (!obj) {
		/* make a NULL object IOR */
		buffer = (char *)null_obj_ior;
		buffer_len = null_obj_ior_len;
	} else {
		buffer = obj->ior;
		buffer_len = obj->ior_len;
	}
	/* now convert the IOR into a HEX representation */
	res = t_malloc(char, (buffer_len * 2) + 13);
	if (!res) {
		flick_set_exception((obj ? obj->boa : 0) /* XXX */,
				    ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for stringified IOR.\n");
		return 0;
	}
	
	res[0] = 'I';
	res[1] = 'O';
	res[2] = 'R';
	res[3] = ':';
	sprintf(&(res[4]), "%02x000000", native_endianness & 0xff);
	for (i = 0; i < buffer_len; ++i)
		sprintf(&(res[i * 2 + 12]), "%02x", ((int) buffer[i]) & 0xff);
	res[(buffer_len * 2) + 12] = 0;
	
	CORBA_BOA_set_exception((obj ? obj->boa : 0) /* XXX */,
				ev, CORBA_NO_EXCEPTION, 0, 0);
	return res;
}

static int hexbits(char a)
{
	if (a >= '0' && a <= '9')
		return a - '0';
	if ((a >= 'a' && a < 'g') ||
	    (a >= 'A' && a < 'G'))
		return (a & 15) + 9;
	return -1;
}

static int hexoctet(char x, char y)
{
	return hexbits(x) * 16 + hexbits(y);
}

/* extracts the data from an object string.  Returns the length of the data */
int flick_parse_readable_object_string(char *instr, char **out_OAaddr,
				       unsigned short *out_boa_port,
				       char **out_obj_type_id,
				       unsigned int *out_obj_type_id_len,
				       CORBA_octet **out_obj_key,
				       unsigned int *out_obj_key_len,
				       CORBA_Environment *ev) 
{
	/* We're using a readable stringified object. */
	int len, res;
	char *host, *port, *type, *str, *obj_id, *orig;
	
        /* return the total size of the ior */
	res = strlen(instr) + 1; 
	
	if (!!strncmp("iiop:1.0//", instr, 10)) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: malformed URL-style object "
			"reference.\n");
		return res;
	}
	
	if (res == 10 + 1) {
		/* NULL Object reference */
		*out_OAaddr = *out_obj_type_id = 0;
		*out_obj_key = 0;
		*out_obj_type_id_len = *out_obj_key_len = 0;
		*out_boa_port = 0;
		
		/* No object --> no BOA --> no `CORBA_BOA_set_exception'. */
		ev->_major = CORBA_NO_EXCEPTION;
		return res;
	}
		
	orig = str = t_malloc(char, res);
	if (!str) {
		flick_set_exception(0 /* boa */, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		return 0;
	}
	strcpy(str, instr + 10); /* skip the header */
	
	/* get the host */
	host = str;
	while(*str != ':' && *str != 0) {
		str++;
	}
	if (*str == 0)
		goto bail;
	*str = 0;
	str++;
	
	/* get the port */
	port = str;

	while(*str != '/' && *str != 0) {
		str++;
	}
	if (*str == 0)
		goto bail;
	*str = 0;
	str++;
	
	/* get the type */
	type = str;
	
	while(*str != '/' && *str != 0) {
		str++;
	}
	if (*str == 0)
		goto bail;
	*str = 0;
	str++;
	
	/* str points to the object id */
	obj_id = str;
	
	len = strlen(host);
	*out_OAaddr = t_malloc(char, (len + 1));
	if (!*out_OAaddr) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for ORB address.\n");
		free(orig);
		return res;
	}
	strncpy(*out_OAaddr,
		host,
		(len + 1));
	
	*out_boa_port = atoi(port);
	
	*out_obj_type_id_len = strlen(type);
	*out_obj_type_id = t_malloc(char, (*out_obj_type_id_len + 1));
	if (!*out_obj_type_id) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for object "
			"type.\n");
		free(orig);
		return res;
	}
	strncpy(*out_obj_type_id,
		type,
		(*out_obj_type_id_len + 1));
	
	*out_obj_key_len = strlen(obj_id);
	*out_obj_key = t_malloc(CORBA_octet, *out_obj_key_len);
	if (!*out_obj_key) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for object "
			"key.\n");
		if (*out_obj_type_id) free(*out_obj_type_id);
		free(orig);
		return res;
	}
	memcpy(*out_obj_key, obj_id, *out_obj_key_len);
	
	/* No object --> no BOA --> no `CORBA_BOA_set_exception'. */
	ev->_major = CORBA_NO_EXCEPTION;
	free(orig);
	return res;
	
  bail:
	flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
			    0, CORBA_COMPLETED_NO);
	fprintf(stderr,
		"Error: malformed URL-style object "
		"reference.\n");
	free(orig);
	return res;
	
}

/* extracts the data from an object string.  Returns the length of the data */
int flick_parse_hex_ior(char *str, char **out_OAaddr,
			unsigned short *out_boa_port,
			char **out_obj_type_id,
			unsigned int *out_obj_type_id_len,
			CORBA_octet **out_obj_key,
			unsigned int *out_obj_key_len,
			CORBA_Environment *ev) 
{
	/* We're using the CORBA 2.0 p10.17 stringified object. */
	
	char buf[1024]; /* XXX --- should dynamically alloc `buf'. */
	unsigned int len;     
	
	unsigned i, res;
	unsigned int endian_test = 1;
	char native_endianness = ((char *) &endian_test)[0];
	
	char encapsulation_endianness;
	
	len = strlen(str);
	res = len + 1;
	
	if (!!strncmp("IOR:", str, 4)) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: malformed IOR.\n");
		return res;
	}
	
	/* Skip the IOR: prefix */
	str += 4;
	len -= 4;
	
	/*
	 * Because every byte in the IOR is represented by two hex
	 * digits in the string, the string must contain an even number
	 * of characters.
	 */
	if (len % 2) {
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: invalid IOR (odd number of hex "
			"digits).\n");
		return res;
	}
	if ((len / 2) > sizeof(buf)) {
		/* XXX */
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_IMP_LIMIT,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: IOR too long.\n");
		return res;
	}
	
	/* Decode the hex string into a sequence of bytes in `buf'. */
	for (i = 0; i < len; i += 2) {
		int val = hexoctet(str[i], str[i + 1]);
		if (val < 0) {
			flick_set_exception(0 /*boa*/, ev,
					    ex_CORBA_BAD_PARAM,
					    0, CORBA_COMPLETED_NO);
			fprintf(stderr,
				"Error: invalid IOR (contains non-hex "
				"digits).\n");
			return res;
		} else
			buf[(i / 2)] = val;
	}	
	
	/*
	 * `buf' now holds a CORBA encapsulation of an IOR as described
	 * in Section 10.6.2 of the CORBA 2.0 specification.
	 */
	encapsulation_endianness = buf[0];
	
	flick_cdr_parse_IOR(&(buf[4]),
			    (encapsulation_endianness != native_endianness),
			    out_OAaddr,
			    out_boa_port,
			    out_obj_type_id,
			    out_obj_type_id_len,
			    out_obj_key, out_obj_key_len, ev);
	return res;
}

/* extracts the data from an object string.  Returns the length of the data */
/* The semantics of this function is that it will allocate the space for the
   out strings and the caller will free them. */
int flick_parse_object_string(char *str, char **out_OAaddr,
			      unsigned short *out_boa_port,
			      char **out_obj_type_id,
			      unsigned int *out_obj_type_id_len,
			      CORBA_octet **out_obj_key,
			      unsigned int *out_obj_key_len,
			      CORBA_Environment *ev) 
{
	assert(out_OAaddr && out_boa_port && out_obj_type_id
	       && out_obj_type_id_len && out_obj_key && out_obj_key_len);
	if (!str || !str[0]) {
		/* Null string object reference */
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Warning: empty object reference string.\n");
		return 0;
	}
	
	if (!strncmp("iiop:1.0//", str, 10)) {
		return flick_parse_readable_object_string(str, out_OAaddr,
							  out_boa_port,
							  out_obj_type_id,
							  out_obj_type_id_len,
							  out_obj_key,
							  out_obj_key_len, ev);
	} else if (!strncmp("IOR:", str, 4)) {
		return flick_parse_hex_ior(str, out_OAaddr,
					   out_boa_port,
					   out_obj_type_id,
					   out_obj_type_id_len,
					   out_obj_key, out_obj_key_len, ev);
	} else {
		/* I have no idea what kind of object reference this is. */
		flick_set_exception(0 /*boa*/, ev, ex_CORBA_BAD_PARAM,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: unrecognized object reference format.\n");
		return 0;
	}
}

FLICK_TARGET flick_create_object(char *ORBid, char *OAid, char *OAaddr,
				 unsigned short boa_port,
				 char *obj_type_id,
				 unsigned int obj_type_id_len,
				 CORBA_octet *obj_key,
				 unsigned int obj_key_len,
				 CORBA_Environment *ev)
{
	CORBA_ORB orb;
	
	CORBA_BOA boa;
	
	FLICK_TARGET res;
	
	/*****/
	
	/* return a NULL object if insufficient information is given */
	if ((!obj_type_id) || (!obj_key)) {
		ev->_major = CORBA_NO_EXCEPTION;
		return 0;
	}
	
	orb = CORBA_ORB_init_internal(ORBid, ev);
	if (ev->_major != CORBA_NO_EXCEPTION)
		return 0;
	boa = CORBA_ORB_BOA_init_internal(orb, OAid,
					  OAaddr, boa_port, ev);
	if (ev->_major != CORBA_NO_EXCEPTION)
		return 0;
	res = t_malloc(FLICK_TARGET_STRUCT, 1);
	if (!res) {
		flick_set_exception(boa, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for Object.\n");
		return 0;
	}
	
	res->boa = boa;
	res->key._buffer = obj_key;
	res->key._length = obj_key_len;
	res->key._maximum = obj_key_len;
	res->type_id = obj_type_id;
	res->type_id_len = obj_type_id_len;
	res->ior_len = 0;
	res->ior = 0;
	res->server_func = 0;
	if (!flick_cdr_make_ior(res, &res->ior, &res->ior_len, 0)) {
		flick_set_exception(boa, ev, ex_CORBA_NO_MEMORY,
				    0, CORBA_COMPLETED_NO);
		fprintf(stderr,
			"Error: can't malloc memory for IOR.\n");
		return 0;
	}
	return res;
}

FLICK_TARGET CORBA_ORB_string_to_object(CORBA_ORB ths,
					CORBA_char *str,
					CORBA_Environment *ev)
{
	FLICK_TARGET res;
	char *OAaddr = 0;	
	unsigned short boa_port;	
	char *obj_type_id = 0;
	CORBA_octet *obj_key = 0; 	
	unsigned int obj_type_id_len, obj_key_len;
	
	/*****/
	
	if (!ths) {
		flick_set_exception(0 /* XXX boa */, ev,
				    ex_CORBA_INV_OBJREF,
				    0, CORBA_COMPLETED_NO);
		return 0;
	}
	
	/* extract the useful data from the object string */
	flick_parse_object_string(str, &OAaddr, &boa_port, &obj_type_id,
				  &obj_type_id_len, &obj_key, &obj_key_len,
				  ev);
	if (ev->_major != CORBA_NO_EXCEPTION)
		return 0;
	
	/* create the object (but do not connect it yet) */
	res = flick_create_object(ths->ORBid,
				  0 /*use default OAid*/,
				  OAaddr, boa_port, obj_type_id,
				  obj_type_id_len,
				  obj_key, obj_key_len, ev);
        /* was copied by CORBA_ORB_BOA_init_internal */
	if (OAaddr) free(OAaddr); 
	if (ev->_major != CORBA_NO_EXCEPTION) {
		if (obj_type_id) free(obj_type_id);
		if (obj_key) free(obj_key);
		return 0;
	}
	
	return res;
}

/* End of file. */



syntax highlighted by Code2HTML, v. 0.9.1