/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 *  Authors:  Michael Zucchi <notzed@ximian.com>
 *
 *  Copyright 2004 Ximian, Inc. (www.ximian.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * 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.
 *
 * A GnomeVFS to CamelStream mapper.
 */

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

#include <string.h>
#include <stdio.h>
#include <errno.h>

#include <libgnomevfs/gnome-vfs.h>

#include "em-vfs-stream.h"

#ifndef EINPROGRESS
#define EINPROGRESS EAGAIN
#endif
#ifndef ELOOP
#define ELOOP EIO
#endif

#define LOG_STREAM

#define d(x) 

#define EMVS_CLASS(x) ((EMVFSStreamClass *)(((CamelObject *)(x))->klass))

static CamelStreamClass *parent_class = NULL;

static void
em_vfs_stream_init (CamelObject *object)
{
	/*EMVFSStream *emvfs = (EMVFSStream *)object;*/
}

static void
em_vfs_stream_finalize (CamelObject *object)
{
	EMVFSStream *emvfs = (EMVFSStream *)object;

	if (emvfs->handle)
		gnome_vfs_close(emvfs->handle);
}

static void
emvfs_set_errno(GnomeVFSResult res)
{
	switch(res) {
	case GNOME_VFS_OK:
		g_warning("em-vfs-stream: calling set_errno with no error");
		break;
	case GNOME_VFS_ERROR_NOT_FOUND:
	case GNOME_VFS_ERROR_HOST_NOT_FOUND:
	case GNOME_VFS_ERROR_INVALID_HOST_NAME:
	case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS:
	case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE:
		errno = ENOENT;
		break;
	case GNOME_VFS_ERROR_GENERIC:
	case GNOME_VFS_ERROR_INTERNAL:
	case GNOME_VFS_ERROR_IO:
	case GNOME_VFS_ERROR_EOF: /* will be caught by read before here anyway */
	case GNOME_VFS_ERROR_SERVICE_OBSOLETE:
	case GNOME_VFS_ERROR_PROTOCOL_ERROR:
	default:
		errno = EIO;
		break;
	case GNOME_VFS_ERROR_BAD_PARAMETERS:
	case GNOME_VFS_ERROR_NOT_SUPPORTED:
	case GNOME_VFS_ERROR_INVALID_URI:
	case GNOME_VFS_ERROR_NOT_OPEN:
	case GNOME_VFS_ERROR_INVALID_OPEN_MODE:
	case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM:
		errno = EINVAL;
		break;
	case GNOME_VFS_ERROR_CORRUPTED_DATA: /* not sure about these */
	case GNOME_VFS_ERROR_WRONG_FORMAT:
	case GNOME_VFS_ERROR_BAD_FILE:
		errno = EBADF;
		break;
	case GNOME_VFS_ERROR_TOO_BIG:
		errno = E2BIG;
		break;
	case GNOME_VFS_ERROR_NO_SPACE:
		errno = ENOSPC;
		break;
	case GNOME_VFS_ERROR_READ_ONLY:
	case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM:
		errno = EROFS;
		break;
	case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES:
		errno = EMFILE;
		break;
	case GNOME_VFS_ERROR_NOT_A_DIRECTORY:
		errno = ENOTDIR;
		break;
	case GNOME_VFS_ERROR_IN_PROGRESS:
		errno = EINPROGRESS;
		break;
	case GNOME_VFS_ERROR_INTERRUPTED:
		errno = EINTR;
		break;
	case GNOME_VFS_ERROR_FILE_EXISTS:
		errno = EEXIST;
	case GNOME_VFS_ERROR_LOOP:
		errno = ELOOP;
		break;
	case GNOME_VFS_ERROR_ACCESS_DENIED:
	case GNOME_VFS_ERROR_NOT_PERMITTED:
	case GNOME_VFS_ERROR_LOGIN_FAILED:
		errno = EPERM;
		break;
	case GNOME_VFS_ERROR_IS_DIRECTORY:
	case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY: /* ?? */
		errno = EISDIR;
		break;
	case GNOME_VFS_ERROR_NO_MEMORY:
		errno = ENOMEM;
		break;
	case GNOME_VFS_ERROR_CANCELLED:
		errno = EINTR;
		break;
	case GNOME_VFS_ERROR_DIRECTORY_BUSY:
		errno = EBUSY;
		break;
	case GNOME_VFS_ERROR_TOO_MANY_LINKS:
		errno = EMLINK;
		break;
	case GNOME_VFS_ERROR_NAME_TOO_LONG:
		errno = ENAMETOOLONG;
		break;
	}
}

static ssize_t
emvfs_read(CamelStream *stream, char *buffer, size_t n)
{
	EMVFSStream *emvfs = EM_VFS_STREAM (stream);
	GnomeVFSFileSize count;
	GnomeVFSResult res;

	if (emvfs->handle == NULL) {
		errno = EINVAL;
		return -1;
	}

	/* TODO: handle camel cancellation? */

	res = gnome_vfs_read(emvfs->handle, buffer, n, &count);
	if (res == GNOME_VFS_OK)
		return (ssize_t)count;
	else if (res == GNOME_VFS_ERROR_EOF) {
		stream->eos = TRUE;
		return 0;
	}

	emvfs_set_errno(res);

	return -1;
}

static ssize_t
emvfs_write(CamelStream *stream, const char *buffer, size_t n)
{
	EMVFSStream *emvfs = EM_VFS_STREAM (stream);
	GnomeVFSFileSize count;
	GnomeVFSResult res;

	if (emvfs->handle == NULL) {
		errno = EINVAL;
		return -1;
	}

	res = gnome_vfs_write(emvfs->handle, buffer, n, &count);
	if (res == GNOME_VFS_OK)
		return (ssize_t)count;

	emvfs_set_errno(res);

	return -1;
}

static int
emvfs_close(CamelStream *stream)
{
	EMVFSStream *emvfs = EM_VFS_STREAM (stream);
	GnomeVFSResult res;

	if (emvfs->handle == NULL) {
		errno = EINVAL;
		return -1;
	}

	res = gnome_vfs_close(emvfs->handle);
	emvfs->handle = NULL;
	if (res == GNOME_VFS_OK)
		return 0;

	emvfs_set_errno(res);

	return -1;
}

static off_t
emvfs_seek(CamelSeekableStream *stream, off_t offset, CamelStreamSeekPolicy policy)
{
	EMVFSStream *emvfs = EM_VFS_STREAM (stream);
	GnomeVFSSeekPosition vpolicy;
	GnomeVFSFileSize pos;
	GnomeVFSResult res;

	if (emvfs->handle == NULL) {
		errno = EINVAL;
		return -1;
	}

	switch (policy) {
	case CAMEL_STREAM_SET:
	default:
		vpolicy = GNOME_VFS_SEEK_START;
		break;
	case CAMEL_STREAM_CUR:
		vpolicy = GNOME_VFS_SEEK_CURRENT;
		break;
	case CAMEL_STREAM_END:
		vpolicy = GNOME_VFS_SEEK_END;
		break;
	}

	if ( (res = gnome_vfs_seek(emvfs->handle, vpolicy, offset)) == GNOME_VFS_OK
	     && (res = gnome_vfs_tell(emvfs->handle, &pos)) == GNOME_VFS_OK)
		return pos;

	emvfs_set_errno(res);

	return -1;
}

static off_t
emvfs_tell(CamelSeekableStream *stream)
{
	EMVFSStream *emvfs = EM_VFS_STREAM (stream);
	GnomeVFSFileSize pos;
	GnomeVFSResult res;

	if (emvfs->handle == NULL) {
		errno = EINVAL;
		return -1;
	}

	if ((res = gnome_vfs_tell(emvfs->handle, &pos)) == GNOME_VFS_OK)
		return pos;

	emvfs_set_errno(res);

	return -1;
}

static void
em_vfs_stream_class_init (EMVFSStreamClass *klass)
{
	((CamelStreamClass *)klass)->read = emvfs_read;
	((CamelStreamClass *)klass)->write = emvfs_write;
	((CamelStreamClass *)klass)->close = emvfs_close;

	((CamelSeekableStreamClass *)klass)->seek = emvfs_seek;
	((CamelSeekableStreamClass *)klass)->tell = emvfs_tell;
	/* set_bounds? */
}

CamelType
em_vfs_stream_get_type (void)
{
	static CamelType type = CAMEL_INVALID_TYPE;
	
	if (type == CAMEL_INVALID_TYPE) {
		parent_class = (CamelStreamClass *)camel_seekable_stream_get_type();
		type = camel_type_register ((CamelType)parent_class,
					    "EMVFSStream",
					    sizeof (EMVFSStream),
					    sizeof (EMVFSStreamClass),
					    (CamelObjectClassInitFunc) em_vfs_stream_class_init,
					    NULL,
					    (CamelObjectInitFunc) em_vfs_stream_init,
					    (CamelObjectFinalizeFunc) em_vfs_stream_finalize);
	}
	
	return type;
}

/**
 * emvfs_stream_new:
 * @handle: 
 * 
 * Create a new camel stream from a GnomeVFS handle.  The camel stream
 * will own the handle from now on.
 * 
 * Return value: A CamelStream that will talk to @handle.  This function cannot fail.
 **/
EMVFSStream *
emvfs_stream_new(GnomeVFSHandle *handle)
{
	EMVFSStream *emvfs;

	emvfs = (EMVFSStream *)camel_object_new(em_vfs_stream_get_type());
	emvfs->handle = handle;

	return emvfs;
}
ed79862ad0ab2878e'>commit</a><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/diff/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=b14b5d41dedaba9229096fced79862ad0ab2878e'>diff</a><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/stats/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3'>stats</a></td><td class='form'><form class='right' method='get' action='/~lantw44/cgit/cgit.cgi/freebsd-ports/log/math/R'>
<input type='hidden' name='h' value='dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3'/><input type='hidden' name='id' value='b14b5d41dedaba9229096fced79862ad0ab2878e'/><select name='qt'>
<option value='grep'>log msg</option>
<option value='author'>author</option>
<option value='committer'>committer</option>
<option value='range'>range</option>
</select>
<input class='txt' type='search' size='10' name='q' value=''/>
<input type='submit' value='search'/>
</form>
</td></tr></table>
<div class='path'>path: <a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/log/?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=b14b5d41dedaba9229096fced79862ad0ab2878e'>root</a>/<a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/log/math?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=b14b5d41dedaba9229096fced79862ad0ab2878e'>math</a>/<a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/log/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=b14b5d41dedaba9229096fced79862ad0ab2878e'>R</a></div><div class='content'><table class='list nowrap'><tr class='nohover'><th></th><th class='left'>Commit message (<a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/log/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=b14b5d41dedaba9229096fced79862ad0ab2878e&amp;showmsg=1'>Expand</a>)</th><th class='left'>Author</th><th class='left'>Age</th><th class='left'>Files</th><th class='left'>Lines</th></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=336122d3fc6faaa5e9540bf2794b049a7807502f'>math/R: Update to version 3.6.3</a></td><td>jrm</td><td><span title='2020-03-02 08:51:08 +0800'>2020-03-02</span></td><td>2</td><td><span class='deletions'>-23</span>/<span class='insertions'>+5</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=821b60c5dda9947caea29759a041cb56125bb110'>Fix math/openblas and bump dependent ports</a></td><td>swills</td><td><span title='2020-01-30 22:17:44 +0800'>2020-01-30</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=c3f5ad9627e53330905b3d304787a4ba746fef23'>Add and use a shared INFO description. I have patches to add that knob to</a></td><td>marius</td><td><span title='2019-12-28 03:24:56 +0800'>2019-12-28</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+0</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=bc4ac79aca110c3670379cf4186d0a0212a47fab'>math/R: Update to version 3.6.2</a></td><td>jrm</td><td><span title='2019-12-16 03:50:41 +0800'>2019-12-16</span></td><td>3</td><td><span class='deletions'>-9</span>/<span class='insertions'>+9</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=95ef9489598232d9d15e45509d1ea30278ba9bc5'>math/R: No-op to standardize formatting using ports-mgmt/portfmt</a></td><td>jrm</td><td><span title='2019-12-16 03:50:37 +0800'>2019-12-16</span></td><td>1</td><td><span class='deletions'>-64</span>/<span class='insertions'>+66</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=e791e4581e67889cde38a41a78df6bb9b6d19b0e'>devel/icu: update to 65.1</a></td><td>jbeich</td><td><span title='2019-10-04 04:35:29 +0800'>2019-10-04</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=16cc1a10dfd8ff4d6a5046cd211ad1aca46d83d5'>devel/openmp: update to 9.0.0</a></td><td>jbeich</td><td><span title='2019-09-22 02:59:57 +0800'>2019-09-22</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=9aa885fa2b8cb9e9d9424b8c5c13992ef6b363fb'>math/R: Fix dependency condition for devel/openmp</a></td><td>jrm</td><td><span title='2019-09-20 03:55:44 +0800'>2019-09-20</span></td><td>1</td><td><span class='deletions'>-11</span>/<span class='insertions'>+27</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=4a344e94972b109670f45f04efe4002b50981676'>Bump PORTREVISION for ports depending on the canonical version of GCC</a></td><td>gerald</td><td><span title='2019-07-27 04:46:53 +0800'>2019-07-27</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=260bacbc053cf01691945fe7deab0c48630e1c34'>math/R: Update to version 3.6.1</a></td><td>jrm</td><td><span title='2019-07-15 17:19:17 +0800'>2019-07-15</span></td><td>2</td><td><span class='deletions'>-5</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=6c2a32226db3c17c8755f3a53ccb687d3d2bde51'>math/R: force new compiler on GCC architectures</a></td><td>pkubaj</td><td><span title='2019-06-18 21:04:57 +0800'>2019-06-18</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+2</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=99cb7a3d5e177dee8d8fb58ee19ea206e2c2aca3'>math/R: add powerpc64</a></td><td>pkubaj</td><td><span title='2019-06-17 20:30:50 +0800'>2019-06-17</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=1a20a542d3278974d034038695b89a1831e6cf73'>devel/openmp: phase out</a></td><td>jbeich</td><td><span title='2019-05-09 00:05:53 +0800'>2019-05-09</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=8acf8d59414b381235514d16e735b2bec9bf3497'>cran.mk: Don't include math/R/compiler.mk; it was removed in r500605</a></td><td>jrm</td><td><span title='2019-05-02 03:43:18 +0800'>2019-05-02</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+0</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=c0f822803ab3da646309a065c0f281cca7c05fe6'>math/R: Upgrade to version 3.6.0</a></td><td>jrm</td><td><span title='2019-05-02 03:09:59 +0800'>2019-05-02</span></td><td>4</td><td><span class='deletions'>-92</span>/<span class='insertions'>+91</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=3a09a7a8edcfadb1b03b1d6a88dddb78d28b894a'>Related to revision 499061 bump ports with USES=fortran to have them</a></td><td>gerald</td><td><span title='2019-04-22 21:16:33 +0800'>2019-04-22</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=741853706d92ad948129c91a0f09521d332c814f'>Update devel/readline to 8.0</a></td><td>sunpoet</td><td><span title='2019-04-09 22:04:49 +0800'>2019-04-09</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=740bd405f014b469ba560476582bd8287d30a15e'>devel/icu: update to 64.1</a></td><td>jbeich</td><td><span title='2019-03-28 05:11:08 +0800'>2019-03-28</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/math/R?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=ee2234199a8d5de8d5275e8e92b9e6477e4aa326'>math/R: Update to version 3.5.3</a></td><td>jrm</td><td><span title='2019-03-14 09:35:33 +0800'>2019-03-14</span>