/*
 * bonobo-stream-efs.c: libefs based Stream implementation
 *
 * Author:
 *   Dietmar Maurer (dietmar@maurer-it.com)
 *
 * Copyright (C) 2000 Maurer IT Systemlösungen KEG
 */

#include <config.h>
#include <storage-modules/bonobo-stream-efs.h>

gint
bonobo_mode_to_efs (Bonobo_Storage_OpenMode mode)
{
	gint efs_mode = 0;

	if (mode & Bonobo_Storage_READ)
		efs_mode |= EFS_READ;
	if (mode & Bonobo_Storage_WRITE)
		efs_mode |= EFS_WRITE;
	if (mode & Bonobo_Storage_CREATE)
		efs_mode |= EFS_CREATE;
	if (mode & Bonobo_Storage_FAILIFEXIST)
		efs_mode |= EFS_EXCL;
	if (mode & Bonobo_Storage_COMPRESSED)
		efs_mode |= EFS_COMP;

	return efs_mode;
}

static BonoboStream *
create_stream_efs_server (const BonoboStreamEFS *stream_efs)
{
	Bonobo_Stream corba_stream;

	corba_stream = bonobo_stream_corba_object_create (
		BONOBO_OBJECT (stream_efs));

	return BONOBO_STREAM (
		bonobo_object_construct (
			BONOBO_OBJECT (stream_efs), 
			corba_stream));
}

static void
bonobo_stream_efs_destroy (GtkObject *object)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (object);

	if (stream_efs->file)
		efs_file_close (stream_efs->file);

	stream_efs->file = NULL;

	if (stream_efs->storage) 
		bonobo_object_unref (BONOBO_OBJECT (stream_efs->storage));    
}

static Bonobo_StorageInfo*
real_get_info (BonoboStream *stream, 
	       const Bonobo_StorageInfoFields mask,
	       CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	Bonobo_StorageInfo *si;
	EFSResult result;
	EFSStat st;
	gchar *content_type = NULL;

	if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
		     Bonobo_FIELD_TYPE)) {
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Storage_NotSupported, NULL);
		return CORBA_OBJECT_NIL;
	}

	if ((result = efs_node_stat (stream_efs->file, &st)))
		goto get_info_except;
	
	if ((mask & Bonobo_FIELD_CONTENT_TYPE) &&
	    ((result = efs_strtype_get (stream_efs->file, &content_type)))) 
		goto get_info_except;

	si = Bonobo_StorageInfo__alloc ();

	si->size = st.size;
	si->type = Bonobo_STORAGE_TYPE_REGULAR;
	si->name = CORBA_string_dup ("");

	if (content_type) 
		si->content_type = CORBA_string_dup (content_type);
	else
		si->content_type = CORBA_string_dup ("");

	return si;

 get_info_except:

	if (result == EFS_ERR_PERM) 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_NoPermission, 
				     NULL);
	else 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_IOError, NULL);
	
	return CORBA_OBJECT_NIL;
}

static void
real_set_info (BonoboStream *stream, 
	       const Bonobo_StorageInfo *info,
	       const Bonobo_StorageInfoFields mask, 
	       CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	EFSResult result = EFS_ERR_PERM;

	if (mask !=  Bonobo_FIELD_CONTENT_TYPE) {
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Storage_NotSupported, NULL);
		return;
	}
	
	if ((result = efs_strtype_set(stream_efs->file, info->content_type))) 
		goto set_info_except;

	return;

 set_info_except:

	if (result == EFS_ERR_PERM) 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_NoPermission, 
				     NULL);
	else 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_IOError, NULL);
}

static void
real_write (BonoboStream *stream, 
	    const Bonobo_Stream_iobuf *buffer,
	    CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	EFSResult result;

	if ((result = efs_file_write (stream_efs->file, buffer->_buffer, 
				   buffer->_length))) {
		
		if (result == EFS_ERR_PERM) 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_NoPermission, 
					     NULL);
		else 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_IOError, NULL);
	}
}

static void
real_read (BonoboStream *stream, 
	   CORBA_long count,
	   Bonobo_Stream_iobuf ** buffer, 
	   CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	CORBA_octet *data;
	gint32 bytes_read;
	EFSResult result;

	if (count < 0) {
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_IOError, NULL);
		return;
	}

	*buffer = Bonobo_Stream_iobuf__alloc ();
	CORBA_sequence_set_release (*buffer, TRUE);
	data = CORBA_sequence_CORBA_octet_allocbuf (count);
	(*buffer)->_buffer = data;
	(*buffer)->_length = 0;

	if ((result = efs_file_read 
	     (stream_efs->file, data, count, &bytes_read))) {

		CORBA_free (*buffer);
		*buffer = NULL;

		if (result == EFS_ERR_PERM)
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_NoPermission, 
					     NULL);
		else 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_IOError, NULL);
	} else
		(*buffer)->_length = bytes_read;
}

static CORBA_long
real_seek (BonoboStream *stream, 
	   CORBA_long offset, 
	   Bonobo_Stream_SeekType whence, 
	   CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	EFSResult result;
	gint efs_whence;
	guint32 pos;

	if (whence == Bonobo_Stream_SEEK_CUR)
		efs_whence = EFS_SEEK_CUR;
	else if (whence == Bonobo_Stream_SEEK_END)
		efs_whence = EFS_SEEK_END;
	else
		efs_whence = EFS_SEEK_SET;
	
	if ((result = efs_file_seek(stream_efs->file, offset, efs_whence, 
				    &pos))) {
		
		if (result == EFS_ERR_NOSEEK)
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_NotSupported, 
					     NULL);
		else
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Stream_IOError, NULL);
		return 0;
	}
	
	return pos;
}

static void
real_truncate (BonoboStream *stream, 
	       const CORBA_long new_size, 
	       CORBA_Environment *ev)
{
	BonoboStreamEFS *stream_efs = BONOBO_STREAM_EFS (stream);
	EFSResult result;

	result = efs_file_trunc (stream_efs->file, new_size);

	if (result == EFS_ERR_NOSEEK) 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
				     ex_Bonobo_Stream_NotSupported, NULL);

	else if (result == EFS_ERR_PERM) 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
				     ex_Bonobo_Stream_NoPermission, NULL);

	else if (result != EFS_ERR_OK) 
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
				     ex_Bonobo_Stream_IOError, NULL);

}

static void
real_copy_to (BonoboStream *stream, 
	      const CORBA_char *dest,
	      const CORBA_long bytes, 
	      CORBA_long *read_bytes,
	      CORBA_long *written_bytes, 
	      CORBA_Environment *ev)
{
	BonoboStreamEFS *efs_stream = BONOBO_STREAM_EFS (stream);
	gchar data [4096];
	gchar *content_type = NULL;
	CORBA_unsigned_long more = bytes;
	gint v;
	EFSFile *out_file = NULL;
	EFSResult result;

	*read_bytes = 0;
	*written_bytes = 0;

	if ((result = efs_file_open (&out_file, efs_stream->storage->dir, 
				     dest, EFS_CREATE|EFS_EXCL)))
		goto copy_to_except;

	if ((result = efs_strtype_get (efs_stream->file, &content_type)) ||
	    (result = efs_strtype_set(out_file, content_type)))		
		goto copy_to_except;

	do {
		if (bytes == -1) 
			more = sizeof (data);

		if ((result = efs_file_read (efs_stream->file, data, 
					     MIN (sizeof (data), more), &v)))
			goto copy_to_except;

		if (v <= 0) 
			break;

		*read_bytes += v;
		more -= v;

		if ((result = efs_file_write (out_file, data, v)))
			goto copy_to_except;

		*written_bytes += v;

	} while ((more > 0 || bytes == -1) && v > 0);

	efs_file_close (out_file);

	return;

 copy_to_except:

	if (out_file)
		efs_file_close (out_file);

	if (result == EFS_ERR_PERM)
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_NoPermission, 
				     NULL);
	else
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Stream_IOError,
				     NULL);
}

static void
real_commit (BonoboStream *stream, 
	     CORBA_Environment *ev)
{
        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                             ex_Bonobo_Stream_NotSupported, NULL);
}

static void
real_revert (BonoboStream *stream, 
	     CORBA_Environment *ev)
{
        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                             ex_Bonobo_Stream_NotSupported, NULL);
}

static void
bonobo_stream_efs_class_init (BonoboStreamEFSClass *class)
{
	GtkObjectClass *object_class = (GtkObjectClass *) class;
	BonoboStreamClass *sclass = BONOBO_STREAM_CLASS (class);
	
	sclass->get_info = real_get_info;
	sclass->set_info = real_set_info;
	sclass->write    = real_write;
	sclass->read     = real_read;
	sclass->seek     = real_seek;
	sclass->truncate = real_truncate;
	sclass->copy_to  = real_copy_to;
	sclass->commit   = real_commit;
	sclass->revert   = real_revert;

	object_class->destroy = bonobo_stream_efs_destroy;
}

GtkType
bonobo_stream_efs_get_type (void)
{
	static GtkType type = 0;

	if (!type) {
		GtkTypeInfo info = {
			"IDL:GNOME/StreamEFS:1.0",
			sizeof (BonoboStreamEFS),
			sizeof (BonoboStreamEFSClass),
			(GtkClassInitFunc) bonobo_stream_efs_class_init,
			(GtkObjectInitFunc) NULL,
			NULL, /* reserved 1 */
			NULL, /* reserved 2 */
			(GtkClassInitFunc) NULL
		};

		type = gtk_type_unique (bonobo_stream_get_type (), &info);
	}
  
	return type;
}

BonoboStream *
bonobo_stream_efs_open (BonoboStorageEFS *storage, 
			const CORBA_char *path, 
			Bonobo_Storage_OpenMode mode,
			CORBA_Environment *ev)
{
	BonoboStreamEFS *stream;
	EFSResult result;
	gint efs_mode;

	if (!(stream = gtk_type_new (bonobo_stream_efs_get_type ()))) {
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Storage_IOError, NULL);
		return NULL;
	}

	efs_mode = bonobo_mode_to_efs (mode);

	if ((result = efs_file_open 
	     (&stream->file, storage->dir, path, efs_mode))) {
		
		bonobo_object_unref (BONOBO_OBJECT (stream));

		if (result == EFS_ERR_NOENT) 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Storage_NotFound, 
					     NULL);
		else if (result == EFS_ERR_PERM) 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Storage_NoPermission, 
					     NULL);
		else if (result == EFS_ERR_EXISTS) 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Storage_NameExists, 
					     NULL);
		else if (result == EFS_ERR_NOTFILE) 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Storage_NotStream, 
					     NULL);
		else 
			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
					     ex_Bonobo_Storage_IOError, NULL);

		return NULL;
	}
	
	stream->storage = storage;
	bonobo_object_ref (BONOBO_OBJECT(storage));

	if (!create_stream_efs_server (stream)) {
		bonobo_object_unref (BONOBO_OBJECT (stream));
		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
				     ex_Bonobo_Storage_IOError, NULL);
		return NULL;
	}

	return BONOBO_STREAM (stream);
}



syntax highlighted by Code2HTML, v. 0.9.1