aboutsummaryrefslogblamecommitdiffstats
path: root/mail/em-vfs-stream.c
blob: d232b3e6cbcc0a4937f89f7cd23d10655b54405f (plain) (tree)


































                                                                        






                          































































































































































































































































































                                                                                                
/* -*- 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;
}