balsa r7916 - in trunk: . libbalsa src



Author: pawels
Date: Fri Apr 25 18:19:30 2008
New Revision: 7916
URL: http://svn.gnome.org/viewvc/balsa?rev=7916&view=rev

Log:
* src/balsa-mime-widget-message.c: use URIs instead of paths.
* src/sendmsg-window.[ch]: use gnome-vfs for attachment reading.
* src/balsa-mime-widget-callbacks.c: ditto.
* src/balsa-message.c: allow saving to URIs.
* src/main.c: -o flag accepts an URI now.
* src/information-dialog.h: add argument checking.
* libbalsa/misc.[hc]: return more detailed error information.
* libbalsa/body.h: store attachment URIs.
* libbalsa/send.[ch]: handle errors when reading from URIs.
* libbalsa/files.[ch]: file access operations use URIs now.
* libbalsa/misc.c: move some functions to libbalsa-vfs.c
* libbalsa/body.c: part operations accept URIs now.


Added:
   trunk/libbalsa/libbalsa-vfs.c
   trunk/libbalsa/libbalsa-vfs.h
Modified:
   trunk/ChangeLog
   trunk/libbalsa/Makefile.am
   trunk/libbalsa/body.c
   trunk/libbalsa/body.h
   trunk/libbalsa/files.c
   trunk/libbalsa/files.h
   trunk/libbalsa/message.h
   trunk/libbalsa/misc.c
   trunk/libbalsa/misc.h
   trunk/libbalsa/send.c
   trunk/libbalsa/send.h
   trunk/src/balsa-message.c
   trunk/src/balsa-mime-widget-callbacks.c
   trunk/src/balsa-mime-widget-message.c
   trunk/src/information-dialog.h
   trunk/src/main.c
   trunk/src/sendmsg-window.c
   trunk/src/sendmsg-window.h

Modified: trunk/libbalsa/Makefile.am
==============================================================================
--- trunk/libbalsa/Makefile.am	(original)
+++ trunk/libbalsa/Makefile.am	Fri Apr 25 18:19:30 2008
@@ -74,6 +74,8 @@
 	filter.h		\
 	folder-scanners.c	\
 	folder-scanners.h	\
+	gmime-stream-gnome-vfs.c\
+	gmime-stream-gnome-vfs.h\
 	html.c                  \
 	html.h                  \
 	identity.c		\
@@ -89,6 +91,8 @@
 	libbalsa.c		\
 	libbalsa.h		\
 	libbalsa_private.h	\
+	libbalsa-vfs.c		\
+	libbalsa-vfs.h		\
 	mailbackend.h		\
 	mailbox-filter.c	\
 	mailbox-filter.h	\

Modified: trunk/libbalsa/body.c
==============================================================================
--- trunk/libbalsa/body.c	(original)
+++ trunk/libbalsa/body.c	Fri Apr 25 18:19:30 2008
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 
 #include "libbalsa.h"
+#include "libbalsa-vfs.h"
 #include "misc.h"
 #include <glib/gi18n.h>
 
@@ -45,6 +46,7 @@
     body->embhdrs = NULL;
     body->content_type = NULL;
     body->filename = NULL;
+    body->file_uri = NULL;
     body->temp_filename = NULL;
     body->charset = NULL;
 
@@ -72,7 +74,8 @@
     libbalsa_message_headers_destroy(body->embhdrs);
     g_free(body->content_type);
     g_free(body->filename);
-
+    if (body->file_uri)
+        g_object_unref(body->file_uri);
     if (body->temp_filename)
 	unlink(body->temp_filename);
     g_free(body->temp_filename);
@@ -322,8 +325,18 @@
 		body->temp_filename = tmp_file_name;
 	    fd = open(body->temp_filename, O_WRONLY | O_EXCL | O_CREAT,
                       LIBBALSA_MESSAGE_BODY_SAFE);
-	    if (fd >= 0)
-		return libbalsa_message_body_save_fd(body, fd, FALSE, err);
+	    if (fd >= 0) {
+                GMimeStream *tmp_stream;
+
+                if ((tmp_stream = g_mime_stream_fs_new(fd)) != NULL)
+                    return libbalsa_message_body_save_stream(body, tmp_stream, FALSE, err);
+                else {
+                    g_set_error(err, LIBBALSA_ERROR_QUARK, 1,
+                                _("Failed to create output stream"));
+                    close(fd);
+                    return FALSE;
+                }
+            }
 	} while (errno == EEXIST && --count > 0);
 
 	/* Either we hit a real error, or we used up 100 attempts. */
@@ -356,16 +369,42 @@
 {
     int fd;
     int flags = O_CREAT | O_EXCL | O_WRONLY;
+    GMimeStream *out_stream;
 
 #ifdef O_NOFOLLOW
     flags |= O_NOFOLLOW;
 #endif
 
-    if ((fd=libbalsa_safe_open(filename, flags, mode)) < 0)
+    if ((fd = libbalsa_safe_open(filename, flags, mode, err)) < 0)
 	return FALSE;
-    return libbalsa_message_body_save_fd(body, fd, filter_crlf, err);
+
+    if ((out_stream = g_mime_stream_fs_new(fd)) != NULL)
+        return libbalsa_message_body_save_stream(body, out_stream,
+                                                 filter_crlf, err);
+
+    /* could not create stream */
+    g_set_error(err, LIBBALSA_ERROR_QUARK, 1,
+                _("Failed to create output stream"));
+    close(fd);
+    return FALSE;
+}
+
+
+gboolean
+libbalsa_message_body_save_vfs(LibBalsaMessageBody * body,
+                               LibbalsaVfs * dest, mode_t mode,
+                               gboolean filter_crlf,
+                               GError **err)
+{
+    GMimeStream * out_stream;
+    
+    if (!(out_stream = libbalsa_vfs_create_stream(dest, mode, TRUE, err)))
+        return FALSE;
+
+    return libbalsa_message_body_save_stream(body, out_stream, filter_crlf, err);
 }
 
+
 static GMimeStream *
 libbalsa_message_body_stream_add_filter(GMimeStream * stream,
                                         GMimeFilter * filter)
@@ -568,17 +607,17 @@
 }
 
 gboolean
-libbalsa_message_body_save_fd(LibBalsaMessageBody * body, int fd,
-                              gboolean filter_crlf, GError ** err)
+libbalsa_message_body_save_stream(LibBalsaMessageBody * body,
+                                  GMimeStream * dest, gboolean filter_crlf,
+                                  GError ** err)
 {
-    GMimeStream *stream, *stream_fs;
+    GMimeStream *stream;
     ssize_t len;
 
     stream = libbalsa_message_body_get_stream(body, err);
     if (!body->mime_part)
         return FALSE;
 
-    stream_fs = g_mime_stream_fs_new(fd);
     libbalsa_mailbox_lock_store(body->message->mailbox);
 
     if (stream) {
@@ -600,7 +639,7 @@
             g_object_unref(filter);
         }
 
-        len = g_mime_stream_write_to_stream(stream, stream_fs);
+        len = g_mime_stream_write_to_stream(stream, dest);
         g_object_unref(stream);
     } else {
         /* body->mime_part is not a GMimePart. */
@@ -612,11 +651,11 @@
             mime_part =
                 GMIME_OBJECT(GMIME_MESSAGE_PART(mime_part)->message);
 
-        len = g_mime_object_write_to_stream(mime_part, stream_fs);
+        len = g_mime_object_write_to_stream(mime_part, dest);
     }
 
     libbalsa_mailbox_unlock_store(body->message->mailbox);
-    g_object_unref(stream_fs);
+    g_object_unref(dest);
 
     return len >= 0;
 }

Modified: trunk/libbalsa/body.h
==============================================================================
--- trunk/libbalsa/body.h	(original)
+++ trunk/libbalsa/body.h	Fri Apr 25 18:19:30 2008
@@ -29,6 +29,7 @@
 #include <gmime/gmime.h>
 #include <gdk/gdk.h>
 
+#include "libbalsa-vfs.h"
 #include "config.h"
 
 #ifdef HAVE_GPGME
@@ -73,6 +74,7 @@
     const gchar *content_dsp;	/* content-disposition */ 
     const gchar *content_id;    /* content-id */
     gchar *filename;		/* holds filename for attachments and such (used mostly for sending) */
+    LibbalsaVfs * file_uri;     /* file uri for attachments (used for sending) */
     LibBalsaAttachMode attach_mode; /* attachment mode for sending */
     gchar *temp_filename;	/* Holds the filename of a the temporary file where this part is saved */
     gchar *charset;		/* the charset, used for sending, replying. */
@@ -103,11 +105,18 @@
 GdkPixbuf *libbalsa_message_body_get_pixbuf(LibBalsaMessageBody * body,
                                             GError ** err);
 
-gboolean libbalsa_message_body_save_fd(LibBalsaMessageBody * body, int fd,
-                                       gboolean filter_crlf, GError **err);
+gboolean libbalsa_message_body_save_stream(LibBalsaMessageBody * body,
+                                           GMimeStream * dest,
+                                           gboolean filter_crlf,
+                                           GError **err);
 gboolean libbalsa_message_body_save(LibBalsaMessageBody * body,
                                     const gchar * filename, mode_t mode,
                                     gboolean filter_crlf, GError **err);
+gboolean libbalsa_message_body_save_vfs(LibBalsaMessageBody * body,
+                                        LibbalsaVfs * dest,
+                                        mode_t mode,
+                                        gboolean filter_crlf,
+                                        GError **err);
 gboolean libbalsa_message_body_save_temporary(LibBalsaMessageBody * body,
                                               GError **err);
 

Modified: trunk/libbalsa/files.c
==============================================================================
--- trunk/libbalsa/files.c	(original)
+++ trunk/libbalsa/files.c	Fri Apr 25 18:19:30 2008
@@ -34,6 +34,7 @@
 #include "misc.h"
 #include "files.h"
 #include <glib/gi18n.h>
+#include "libbalsa-vfs.h"
 
 static const gchar *permanent_prefixes[] = {
 /*	BALSA_DATA_PREFIX,
@@ -132,7 +133,7 @@
  *   return the complete path to the icon file.
  */
 GdkPixbuf *
-libbalsa_icon_finder(const char *mime_type, const char *filename, 
+libbalsa_icon_finder(const char *mime_type, const LibbalsaVfs * for_file, 
                      gchar** used_type, GtkIconSize size)
 {
     char *content_type;
@@ -142,6 +143,7 @@
 #ifdef HAVE_GNOME
     const char *icon_file;
     GtkIconTheme *icon_theme;
+    const gchar * filename = NULL;
 #endif
 
     if (!gtk_icon_size_lookup(size, &width, &height))
@@ -149,9 +151,10 @@
     
     if (mime_type)
         content_type = g_strdup(mime_type);
-    else if(filename)
-        content_type = libbalsa_lookup_mime_type(filename);
-    else
+    else if (for_file) {
+        content_type = g_strdup(libbalsa_vfs_get_mime_type(for_file));
+        filename = libbalsa_vfs_get_uri(for_file);
+    } else
 	content_type = g_strdup("application/octet-stream");
 
 #ifdef HAVE_GNOME

Modified: trunk/libbalsa/files.h
==============================================================================
--- trunk/libbalsa/files.h	(original)
+++ trunk/libbalsa/files.h	Fri Apr 25 18:19:30 2008
@@ -27,6 +27,7 @@
 #include <glib.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gtk/gtk.h>
+#include "libbalsa-vfs.h"
 
 /* filename is the filename (naw!)
  * splice is what to put in between the prefix and the filename, if desired
@@ -43,7 +44,7 @@
 #define balsa_pixmap_finder_no_warn(filename) \
     (balsa_file_finder((filename), "pixmaps", NULL, FALSE))
 
-GdkPixbuf *libbalsa_icon_finder(const char *mime_type, const char *filename,
+GdkPixbuf *libbalsa_icon_finder(const char *mime_type, const LibbalsaVfs * for_file,
 				gchar** used_type, GtkIconSize size);
 
 void libbalsa_fill_vfs_menu_by_content_type(GtkMenu * menu,

Added: trunk/libbalsa/libbalsa-vfs.c
==============================================================================
--- (empty file)
+++ trunk/libbalsa/libbalsa-vfs.c	Fri Apr 25 18:19:30 2008
@@ -0,0 +1,728 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * libbalsa vfs glue layer library
+ * Copyright (C) 2008 Albrecht Dreß<albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * 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.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gmime/gmime.h>
+#include "gmime-stream-gnome-vfs.h"
+#include "misc.h"
+#include "libbalsa-vfs.h"
+
+
+#ifdef HAVE_GNOME
+#  include <libgnomevfs/gnome-vfs.h>
+#  define USE_GNOME_VFS  1
+#else
+#  undef USE_GNOME_VFS
+#endif
+
+
+#define LIBBALSA_VFS_ERROR_QUARK (g_quark_from_static_string("libbalsa-vfs"))
+
+
+struct _LibbalsaVfsPriv {
+    gchar * file_uri;
+    gchar * file_utf8;
+    gchar * folder_uri;
+    gchar * mime_type;
+    gchar * charset;
+    LibBalsaTextAttribute text_attr;
+#ifdef USE_GNOME_VFS
+    GnomeVFSURI * gvfs_uri;
+    GnomeVFSFileInfo * info;
+#else
+    gchar * local_name;
+#endif
+};
+
+
+static GObjectClass *libbalsa_vfs_parent_class = NULL;
+
+
+static void libbalsa_vfs_class_init(LibbalsaVfsClass * klass);
+static void libbalsa_vfs_init(LibbalsaVfs * self);
+static void libbalsa_vfs_finalize(LibbalsaVfs * self);
+
+
+gboolean
+libbalsa_vfs_local_only(void)
+{
+#ifdef USE_GNOME_VFS
+    return FALSE;
+#else
+    return TRUE;
+#endif
+}
+
+
+GType
+libbalsa_vfs_get_type(void)
+{
+    static GType libbalsa_vfs_type = 0;
+
+    if (!libbalsa_vfs_type) {
+        static const GTypeInfo libbalsa_vfs_type_info = {
+            sizeof(LibbalsaVfsClass),     /* class_size */
+            NULL,               /* base_init */
+            NULL,               /* base_finalize */
+            (GClassInitFunc) libbalsa_vfs_class_init,   /* class_init */
+            NULL,               /* class_finalize */
+            NULL,               /* class_data */
+            sizeof(LibbalsaVfs),  /* instance_size */
+            0,                  /* n_preallocs */
+            (GInstanceInitFunc) libbalsa_vfs_init,      /* instance_init */
+            /* no value_table */
+        };
+
+        libbalsa_vfs_type =
+            g_type_register_static(G_TYPE_OBJECT, "LibbalsaVfs",
+                                   &libbalsa_vfs_type_info, 0);
+    }
+
+    return libbalsa_vfs_type;
+}
+
+
+static void
+libbalsa_vfs_class_init(LibbalsaVfsClass * klass)
+{
+    GObjectClass *gobject_klass = G_OBJECT_CLASS(klass);
+
+    libbalsa_vfs_parent_class = g_type_class_peek(G_TYPE_OBJECT);
+    gobject_klass->finalize =
+        (GObjectFinalizeFunc) libbalsa_vfs_finalize;
+}
+
+
+static void
+libbalsa_vfs_init(LibbalsaVfs * self)
+{
+    self->priv = NULL;
+}
+
+
+static void
+libbalsa_vfs_finalize(LibbalsaVfs * self)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_if_fail(self != NULL);
+    priv = self->priv;
+
+    if (priv) {
+        g_free(priv->file_uri);
+        g_free(priv->file_utf8);
+        g_free(priv->folder_uri);
+        g_free(priv->mime_type);
+        g_free(priv->charset);
+#ifdef USE_GNOME_VFS
+        if (priv->gvfs_uri)
+            gnome_vfs_uri_unref(priv->gvfs_uri);
+        if (priv->info)
+            gnome_vfs_file_info_unref(priv->info);
+#else
+        g_free(priv->local_name);
+#endif
+        g_free(priv);
+    }
+
+    libbalsa_vfs_parent_class->finalize(G_OBJECT(self));
+}
+
+
+LibbalsaVfs *
+libbalsa_vfs_new(void)
+{
+    return LIBBALSA_VFS(g_object_new(LIBBALSA_TYPE_VFS, NULL));
+}
+
+
+LibbalsaVfs *
+libbalsa_vfs_new_from_uri(const gchar * uri)
+{
+    LibbalsaVfs * retval;
+
+    g_return_val_if_fail(uri, NULL);
+    if (!(retval = libbalsa_vfs_new()))
+        return NULL;
+
+    if (!(retval->priv = g_new0(struct _LibbalsaVfsPriv, 1))) {
+        g_object_unref(G_OBJECT(retval));
+        return NULL;
+    }
+    retval->priv->text_attr = (LibBalsaTextAttribute) -1;
+
+    retval->priv->file_uri = g_strdup(uri);
+#ifdef USE_GNOME_VFS
+    retval->priv->gvfs_uri = gnome_vfs_uri_new(uri);
+    if (!retval->priv->gvfs_uri)
+        g_message(_("Failed to convert %s to a Gnome VFS URI"), uri);
+#else
+    retval->priv->local_name = g_filename_from_uri(uri, NULL, NULL);
+#endif
+
+    return retval;
+}
+
+
+/* create a new LibbalsaVfs object by appending text to the existing object
+ * file (note: text is in utf8, not escaped) */
+LibbalsaVfs *
+libbalsa_vfs_append(const LibbalsaVfs * file, const gchar * text)
+{
+    gchar * p;
+    gchar * q;
+    LibbalsaVfs * retval;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    g_return_val_if_fail(file->priv->file_uri, NULL);
+    g_return_val_if_fail(text, NULL);
+
+    /* fake an absolute file name which we can convert to an uri */
+    p = g_strconcat("/", text, NULL);
+    q = g_filename_to_uri(p, NULL, NULL);
+    g_free(p);
+    if (!q)
+        return NULL;
+
+    /* append to the existing uri and create the new object from it */
+    p = g_strconcat(file->priv->file_uri, q + 8, NULL);
+    g_free(q);
+    retval = libbalsa_vfs_new_from_uri(p);
+    g_free(p);
+    return retval;
+}
+
+
+/* create a new LibbalsaVfs object by appending filename to the existing
+ * object dir which describes a folder (note: filename is in utf8, not
+ * escaped) */
+LibbalsaVfs *
+libbalsa_vfs_dir_append(const LibbalsaVfs * dir, const gchar * filename)
+{   
+    gchar * p;
+    gchar * q;
+    LibbalsaVfs * retval;
+
+    g_return_val_if_fail(dir, NULL);
+    g_return_val_if_fail(dir->priv, NULL);
+    g_return_val_if_fail(dir->priv->file_uri, NULL);
+    g_return_val_if_fail(filename, NULL);
+
+    /* fake an absolute file name which we can convert to an uri */
+    p = g_strconcat("/", filename, NULL);
+    q = g_filename_to_uri(p, NULL, NULL);
+    g_free(p);
+    if (!q)
+        return NULL;
+
+    /* append to the existing uri and create the new object from it */
+    p = g_strconcat(dir->priv->file_uri, q + 7, NULL);
+    g_free(q);
+    retval = libbalsa_vfs_new_from_uri(p);
+    g_free(p);
+    return retval;
+}
+
+
+/* return the text uri of the passed file, removing the last component */
+const gchar *
+libbalsa_vfs_get_folder(const LibbalsaVfs * file)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, NULL);
+
+    if (!priv->folder_uri) {
+        gchar * p;
+
+        if ((priv->folder_uri = g_strdup(priv->file_uri)) &&
+            (p = g_utf8_strrchr(priv->folder_uri, -1, g_utf8_get_char("/"))))
+            *p = '\0';
+    }
+
+    return priv->folder_uri;
+}
+
+
+/* return the text uri of the passed file */
+const gchar *
+libbalsa_vfs_get_uri(const LibbalsaVfs * file)
+{
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    g_return_val_if_fail(file->priv->file_uri, NULL);
+
+    return file->priv->file_uri;
+}
+
+
+/* return the text uri of the passed file as utf8 string (%xx replaced) */
+const gchar *
+libbalsa_vfs_get_uri_utf8(const LibbalsaVfs * file)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, NULL);
+
+    if (!priv->file_utf8) {
+        gchar * p;
+        gchar * q;
+
+        if (!(p = priv->file_utf8 = g_malloc(strlen(priv->file_uri) + 1)))
+            return NULL;
+        q = priv->file_uri;
+        while (*q != '\0') {
+            if (*q == '%') {
+                if (g_ascii_isxdigit(q[1]) && g_ascii_isxdigit(q[2])) {
+                    gint val = (g_ascii_xdigit_value(q[1]) << 4) +
+                        g_ascii_xdigit_value(q[2]);
+                    *p++ = (gchar) val;
+                    q += 3;
+                } else
+                    *p++ = *q++; /* hmmm - shouldn't happen! */
+            } else
+                *p++ = *q++;
+        }
+        *p = '\0';
+    }
+
+    return priv->file_utf8;
+}
+
+
+const gchar *
+libbalsa_vfs_get_basename_utf8(const LibbalsaVfs * file)
+{
+    const gchar * uri_utf8 = libbalsa_vfs_get_uri_utf8(file);
+    const gchar * p;
+
+    if (uri_utf8 &&
+        (p = g_utf8_strrchr(uri_utf8, -1, g_utf8_get_char("/"))))
+        return p + 1;
+    else
+        return NULL;
+}
+
+
+const gchar *
+libbalsa_vfs_get_mime_type(const LibbalsaVfs * file)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, NULL);
+
+    if (!priv->mime_type) {
+#ifdef USE_GNOME_VFS
+        /* use GnomeVFS to determine the mime type of the file */
+        g_return_val_if_fail(priv->gvfs_uri, FALSE);
+
+        if (!priv->info)
+            priv->info = gnome_vfs_file_info_new();
+
+        if (priv->info) {
+            if ((priv->info->valid_fields &
+                 GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) == 0)
+                gnome_vfs_get_file_info_uri(priv->gvfs_uri, priv->info,
+                                            GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
+                                            GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE |
+                                            GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+            if ((priv->info->valid_fields &
+                 GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0)
+                priv->mime_type = g_strdup(gnome_vfs_file_info_get_mime_type(priv->info));
+        }
+
+        /* always fall back to application/octet-stream */
+        if (!priv->mime_type)
+#endif
+            priv->mime_type = g_strdup("application/octet-stream");
+    }
+
+    return priv->mime_type;
+}
+
+
+const gchar *
+libbalsa_vfs_get_charset(const LibbalsaVfs * file)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, NULL);
+
+    if (!priv->charset && priv->text_attr == (LibBalsaTextAttribute) -1) {
+        libbalsa_vfs_get_text_attr(file);
+
+        if (!(priv->text_attr & LIBBALSA_TEXT_HI_BIT))
+            priv->charset = g_strdup("us-ascii");
+        else if (priv->text_attr & LIBBALSA_TEXT_HI_UTF8)
+            priv->charset = g_strdup("utf-8");
+    }
+
+    return priv->charset;
+}
+
+
+LibBalsaTextAttribute
+libbalsa_vfs_get_text_attr(const LibbalsaVfs * file)
+{
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, 0);
+    g_return_val_if_fail(file->priv, 0);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, 0);
+
+    if (priv->text_attr == (LibBalsaTextAttribute) -1) {
+#ifdef USE_GNOME_VFS
+        GnomeVFSHandle *handle;
+
+        /* use GnomeVFS to determine the text attributes of the file */
+        g_return_val_if_fail(priv->gvfs_uri, 0);
+        priv->text_attr = 0;
+
+        /* read and check - see libbalsa_text_attr_file() */
+        if (gnome_vfs_open_uri(&handle, priv->gvfs_uri, GNOME_VFS_OPEN_READ) ==
+            GNOME_VFS_OK) {
+            gchar buf[1024];
+            gchar *new_chars = buf;
+            gboolean has_esc = FALSE;
+            gboolean has_hi_bit = FALSE;
+            gboolean has_hi_ctrl = FALSE;
+            gboolean is_utf8 = TRUE;
+            GnomeVFSFileSize bytes_read;
+
+            while ((is_utf8 || (!has_esc || !has_hi_bit || !has_hi_ctrl)) &&
+                   gnome_vfs_read(handle, new_chars, (sizeof buf) - (new_chars - buf) - 1,
+                                  &bytes_read) == GNOME_VFS_OK) {
+                new_chars[bytes_read] = '\0';
+                
+                if (!has_esc || !has_hi_bit || !has_hi_ctrl) {
+                    guchar * p;
+
+                    for (p = (guchar *) new_chars; *p; p++)
+                        if (*p == 0x1b)
+                            has_esc = TRUE;
+                        else if (*p >= 0x80) {
+                            has_hi_bit = TRUE;
+                            if (*p <= 0x9f)
+                                has_hi_ctrl = TRUE;
+                        }
+                }
+
+                if (is_utf8) {
+                    const gchar *end;
+
+                    new_chars = buf;
+                    if (!g_utf8_validate(buf, -1, &end)) {
+                        if (g_utf8_get_char_validated(end, -1) == (gunichar) (-1))
+                            is_utf8 = FALSE;
+                        else
+                            /* copy any remaining bytes, including the
+                             * terminating '\0', to start of buffer */
+                            while ((*new_chars = *end++) != '\0')
+                                new_chars++;
+                    }
+                }
+            }
+
+            gnome_vfs_close(handle);
+
+            if (has_esc)
+                priv->text_attr |= LIBBALSA_TEXT_ESC;
+            if (has_hi_bit)
+                priv->text_attr |= LIBBALSA_TEXT_HI_BIT;
+            if (has_hi_ctrl)
+                priv->text_attr |= LIBBALSA_TEXT_HI_CTRL;
+            if (is_utf8 && has_hi_bit)
+                priv->text_attr |= LIBBALSA_TEXT_HI_UTF8;
+        }
+#else
+        /* use function from misc to get the text attributes */
+        g_return_val_if_fail(priv->local_name, 0);
+
+        priv->text_attr = libbalsa_text_attr_file(priv->local_name);
+#endif
+    }
+
+    return priv->text_attr;
+}
+
+
+gsize
+libbalsa_vfs_get_size(const LibbalsaVfs * file)
+{
+#ifndef USE_GNOME_VFS
+    struct stat s;
+#endif
+    gsize retval = 0;
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, 0);
+    g_return_val_if_fail(file->priv, 0);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, 0);
+
+#ifdef USE_GNOME_VFS
+    /* use GnomeVFS to determine the size of the file */
+    g_return_val_if_fail(priv->gvfs_uri, 0);
+
+    if (!priv->info)
+        priv->info = gnome_vfs_file_info_new();
+
+    if (priv->info) {
+        if ((priv->info->valid_fields &
+             GNOME_VFS_FILE_INFO_FIELDS_SIZE) == 0)
+            gnome_vfs_get_file_info_uri(priv->gvfs_uri, priv->info,
+                                        GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS |
+                                       GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+        if ((priv->info->valid_fields &
+             GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0)
+            retval = (gsize) priv->info->size;
+    }
+#else
+    /* call stat on the file to get the size */
+    g_return_val_if_fail(priv->local_name, 0);
+
+    if (g_stat(priv->local_name, &s) == 0)
+        retval = (gsize) s.st_size;
+#endif
+
+    return retval;
+}
+
+
+/* get a GMime stream for the passed file, either read-only or in
+ * read-write mode */
+GMimeStream *
+libbalsa_vfs_create_stream(const LibbalsaVfs * file, mode_t mode, 
+                           gboolean rdwr, GError ** err)
+{
+#ifdef USE_GNOME_VFS
+    GnomeVFSOpenMode openmode = GNOME_VFS_OPEN_RANDOM | GNOME_VFS_OPEN_READ;
+    GnomeVFSHandle * handle;
+    GnomeVFSResult result;
+#else
+    int fd;
+    int flags = O_EXCL;
+#endif
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, NULL);
+    g_return_val_if_fail(file->priv, NULL);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, NULL);
+
+#ifdef USE_GNOME_VFS
+    /* use GnomeVFS to create a GMime Gnome VFS stream */
+    g_return_val_if_fail(priv->gvfs_uri, NULL);
+
+    if (rdwr) {
+        openmode |= GNOME_VFS_OPEN_WRITE;
+        result = gnome_vfs_create_uri(&handle, priv->gvfs_uri,
+                                      openmode, TRUE, mode);
+    } else
+        result = gnome_vfs_open_uri(&handle, priv->gvfs_uri, openmode);
+    if (result != GNOME_VFS_OK) {
+        g_set_error(err, LIBBALSA_ERROR_QUARK, result,
+                    gnome_vfs_result_to_string(result));
+        return NULL;
+    }
+
+    return g_mime_stream_gvfs_new(handle);
+#else
+    /* use libc to create a GMime file system stream */
+    g_return_val_if_fail(priv->local_name, NULL);
+
+    flags |= rdwr ? O_CREAT | O_RDWR : O_RDONLY;
+
+#ifdef O_NOFOLLOW
+    flags |= O_NOFOLLOW;
+#endif
+
+    if ((fd = libbalsa_safe_open(priv->local_name, flags, mode, err)) < 0)
+	return NULL;
+
+    return g_mime_stream_fs_new(fd);
+#endif
+}
+
+
+/* return TRUE if the passed file exists */
+gboolean
+libbalsa_vfs_file_exists(const LibbalsaVfs * file)
+{
+    gboolean result = FALSE;
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, FALSE);
+    g_return_val_if_fail(file->priv, FALSE);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, FALSE);
+
+#ifdef USE_GNOME_VFS
+    /* use GnomeVFS to check if the file exists */
+    g_return_val_if_fail(priv->gvfs_uri, FALSE);
+
+    if (!priv->info)
+        priv->info = gnome_vfs_file_info_new();
+
+    if (priv->info) {
+        if ((priv->info->valid_fields &
+             GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS) == 0)
+            gnome_vfs_get_file_info_uri(priv->gvfs_uri, priv->info,
+                                        GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS |
+                                        GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+        if ((priv->info->valid_fields &
+             GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS))
+            result = TRUE;
+    }
+#else
+    /* use g_access to check if the (local) file exists */
+    g_return_val_if_fail(priv->local_name, FALSE);
+
+    result = (g_access(priv->local_name, F_OK) == 0);
+#endif
+
+    return result;
+}
+
+
+gboolean
+libbalsa_vfs_is_regular_file(const LibbalsaVfs * file, GError **err)
+{
+#ifndef USE_GNOME_VFS
+    struct stat s;
+#endif
+    gboolean result = FALSE;
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, FALSE);
+    g_return_val_if_fail(file->priv, FALSE);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, FALSE);
+
+#ifdef USE_GNOME_VFS
+    /* use GnomeVFS to check if the file is a regular one which can be read */
+    g_return_val_if_fail(priv->gvfs_uri, FALSE);
+
+    if (!priv->info)
+        priv->info = gnome_vfs_file_info_new();
+
+    if (priv->info) {
+        if ((priv->info->valid_fields &
+             (GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+              GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS)) == 0)
+            gnome_vfs_get_file_info_uri(priv->gvfs_uri, priv->info,
+                                        GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS |
+                                        GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+        g_message("fields = %x", priv->info->valid_fields);
+        if ((priv->info->valid_fields &
+             (GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+              GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS)) !=
+            (GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+             GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS))
+            g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1,
+                        _("cannot read file information"));
+        else if (priv->info->type != GNOME_VFS_FILE_TYPE_REGULAR)
+            g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1,
+                        _("not a regular file"));
+        else if ((priv->info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_ACCESS) &&
+                 !(priv->info->permissions & GNOME_VFS_PERM_ACCESS_READABLE))
+            g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1, _("cannot read"));
+        else
+            result = TRUE;
+    }
+#else
+    /* use libc to check if the file is a regular one which can be read */
+    g_return_val_if_fail(priv->local_name, FALSE);
+
+    if (g_stat(priv->local_name, &s) != 0)
+        g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, errno,
+                    g_strerror(errno));
+    else if (!S_ISREG(s.st_mode))
+        g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1, _("not a regular file"));
+    else if (g_access(priv->local_name, R_OK) != 0)
+        g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, -1, _("cannot read"));
+    else
+        result = TRUE;
+#endif
+
+    return result;
+}
+
+
+/* unlink the passed file, return 0 on success and -1 on error */
+gint
+libbalsa_vfs_file_unlink(const LibbalsaVfs * file, GError **err)
+{
+#ifdef USE_GNOME_VFS
+    GnomeVFSResult vfs_res;
+#endif
+    gint result = -1;
+    struct _LibbalsaVfsPriv * priv;
+
+    g_return_val_if_fail(file, -1);
+    g_return_val_if_fail(file->priv, -1);
+    priv = file->priv;
+    g_return_val_if_fail(priv->file_uri, -1);
+
+#ifdef USE_GNOME_VFS
+    /* use GnomeVFS to unlink the file */
+    g_return_val_if_fail(priv->gvfs_uri, -1);
+
+    if ((vfs_res = gnome_vfs_unlink_from_uri(priv->gvfs_uri)) != GNOME_VFS_OK)
+        g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, vfs_res,
+                    gnome_vfs_result_to_string(vfs_res));
+    else
+        result = 0;
+#else
+    /* use g_unlink to unlink the (local) file */
+    g_return_val_if_fail(priv->local_name, -1);
+
+    result = g_unlink(priv->local_name);
+    if (result != 0)
+        g_set_error(err, LIBBALSA_VFS_ERROR_QUARK, errno,
+                    g_strerror(errno));
+#endif
+
+    return result;
+}

Added: trunk/libbalsa/libbalsa-vfs.h
==============================================================================
--- (empty file)
+++ trunk/libbalsa/libbalsa-vfs.h	Fri Apr 25 18:19:30 2008
@@ -0,0 +1,258 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * libbalsa vfs glue layer library
+ * Copyright (C) 2008 Albrecht Dreß<albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * 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.
+ */
+
+#ifndef __LIBBALSA_VFS_H__
+#define __LIBBALSA_VFS_H__
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmime/gmime.h>
+#include "misc.h"
+
+
+G_BEGIN_DECLS
+
+
+/* a vfs file description as GObject */
+#define LIBBALSA_TYPE_VFS            (libbalsa_vfs_get_type())
+#define LIBBALSA_VFS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), LIBBALSA_TYPE_VFS, LibbalsaVfs))
+#define LIBBALSA_VFS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+#define LIBBALSA_IS_VFS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_IS_VFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_VFS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+
+typedef struct _LibbalsaVfs LibbalsaVfs;
+typedef struct _LibbalsaVfsClass LibbalsaVfsClass;
+
+
+struct _LibbalsaVfs {
+    GObject parent;
+
+    struct _LibbalsaVfsPriv * priv;
+};
+
+struct _LibbalsaVfsClass {
+    GObjectClass parent;
+};
+
+gboolean libbalsa_vfs_local_only(void);
+
+GType libbalsa_vfs_get_type(void);
+LibbalsaVfs * libbalsa_vfs_new(void);
+LibbalsaVfs * libbalsa_vfs_new_from_uri(const gchar * uri);
+LibbalsaVfs * libbalsa_vfs_append(const LibbalsaVfs * file,
+                                  const gchar * text);
+LibbalsaVfs * libbalsa_vfs_dir_append(const LibbalsaVfs * dir,
+                                      const gchar * filename);
+const gchar * libbalsa_vfs_get_folder(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_basename_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_mime_type(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_charset(const LibbalsaVfs * file);
+LibBalsaTextAttribute libbalsa_vfs_get_text_attr(const LibbalsaVfs * file);
+gsize libbalsa_vfs_get_size(const LibbalsaVfs * file);
+GMimeStream * libbalsa_vfs_create_stream(const LibbalsaVfs * file,
+                                         mode_t mode, 
+                                         gboolean rdwr,
+                                         GError ** err);
+gboolean libbalsa_vfs_file_exists(const LibbalsaVfs * file);
+gboolean libbalsa_vfs_is_regular_file(const LibbalsaVfs * file, GError **err);
+gint libbalsa_vfs_file_unlink(const LibbalsaVfs * file, GError **err);
+
+
+G_END_DECLS
+
+
+#endif				/* __LIBBALSA_VFS_H__ */
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * libbalsa vfs glue layer library
+ * Copyright (C) 2008 Albrecht Dreß<albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * 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.
+ */
+
+#ifndef __LIBBALSA_VFS_H__
+#define __LIBBALSA_VFS_H__
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmime/gmime.h>
+#include "misc.h"
+
+
+G_BEGIN_DECLS
+
+
+/* a vfs file description as GObject */
+#define LIBBALSA_TYPE_VFS            (libbalsa_vfs_get_type())
+#define LIBBALSA_VFS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), LIBBALSA_TYPE_VFS, LibbalsaVfs))
+#define LIBBALSA_VFS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+#define LIBBALSA_IS_VFS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_IS_VFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_VFS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+
+typedef struct _LibbalsaVfs LibbalsaVfs;
+typedef struct _LibbalsaVfsClass LibbalsaVfsClass;
+
+
+struct _LibbalsaVfs {
+    GObject parent;
+
+    struct _LibbalsaVfsPriv * priv;
+};
+
+struct _LibbalsaVfsClass {
+    GObjectClass parent;
+};
+
+gboolean libbalsa_vfs_local_only(void);
+
+GType libbalsa_vfs_get_type(void);
+LibbalsaVfs * libbalsa_vfs_new(void);
+LibbalsaVfs * libbalsa_vfs_new_from_uri(const gchar * uri);
+LibbalsaVfs * libbalsa_vfs_append(const LibbalsaVfs * file,
+                                  const gchar * text);
+LibbalsaVfs * libbalsa_vfs_dir_append(const LibbalsaVfs * dir,
+                                      const gchar * filename);
+const gchar * libbalsa_vfs_get_folder(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_basename_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_mime_type(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_charset(const LibbalsaVfs * file);
+LibBalsaTextAttribute libbalsa_vfs_get_text_attr(const LibbalsaVfs * file);
+gsize libbalsa_vfs_get_size(const LibbalsaVfs * file);
+GMimeStream * libbalsa_vfs_create_stream(const LibbalsaVfs * file,
+                                         mode_t mode, 
+                                         gboolean rdwr,
+                                         GError ** err);
+gboolean libbalsa_vfs_file_exists(const LibbalsaVfs * file);
+gboolean libbalsa_vfs_is_regular_file(const LibbalsaVfs * file, GError **err);
+gint libbalsa_vfs_file_unlink(const LibbalsaVfs * file, GError **err);
+
+
+G_END_DECLS
+
+
+#endif				/* __LIBBALSA_VFS_H__ */
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/*
+ * libbalsa vfs glue layer library
+ * Copyright (C) 2008 Albrecht Dreß<albrecht dress arcor de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option) 
+ * any later version.
+ *  
+ * 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.
+ */
+
+#ifndef __LIBBALSA_VFS_H__
+#define __LIBBALSA_VFS_H__
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmime/gmime.h>
+#include "misc.h"
+
+
+G_BEGIN_DECLS
+
+
+/* a vfs file description as GObject */
+#define LIBBALSA_TYPE_VFS            (libbalsa_vfs_get_type())
+#define LIBBALSA_VFS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), LIBBALSA_TYPE_VFS, LibbalsaVfs))
+#define LIBBALSA_VFS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+#define LIBBALSA_IS_VFS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_IS_VFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LIBBALSA_TYPE_VFS))
+#define LIBBALSA_VFS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), LIBBALSA_TYPE_VFS, LibbalsaVfsClass))
+
+typedef struct _LibbalsaVfs LibbalsaVfs;
+typedef struct _LibbalsaVfsClass LibbalsaVfsClass;
+
+
+struct _LibbalsaVfs {
+    GObject parent;
+
+    struct _LibbalsaVfsPriv * priv;
+};
+
+struct _LibbalsaVfsClass {
+    GObjectClass parent;
+};
+
+gboolean libbalsa_vfs_local_only(void);
+
+GType libbalsa_vfs_get_type(void);
+LibbalsaVfs * libbalsa_vfs_new(void);
+LibbalsaVfs * libbalsa_vfs_new_from_uri(const gchar * uri);
+LibbalsaVfs * libbalsa_vfs_append(const LibbalsaVfs * file,
+                                  const gchar * text);
+LibbalsaVfs * libbalsa_vfs_dir_append(const LibbalsaVfs * dir,
+                                      const gchar * filename);
+const gchar * libbalsa_vfs_get_folder(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_uri_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_basename_utf8(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_mime_type(const LibbalsaVfs * file);
+const gchar * libbalsa_vfs_get_charset(const LibbalsaVfs * file);
+LibBalsaTextAttribute libbalsa_vfs_get_text_attr(const LibbalsaVfs * file);
+gsize libbalsa_vfs_get_size(const LibbalsaVfs * file);
+GMimeStream * libbalsa_vfs_create_stream(const LibbalsaVfs * file,
+                                         mode_t mode, 
+                                         gboolean rdwr,
+                                         GError ** err);
+gboolean libbalsa_vfs_file_exists(const LibbalsaVfs * file);
+gboolean libbalsa_vfs_is_regular_file(const LibbalsaVfs * file, GError **err);
+gint libbalsa_vfs_file_unlink(const LibbalsaVfs * file, GError **err);
+
+
+G_END_DECLS
+
+
+#endif				/* __LIBBALSA_VFS_H__ */

Modified: trunk/libbalsa/message.h
==============================================================================
--- trunk/libbalsa/message.h	(original)
+++ trunk/libbalsa/message.h	Fri Apr 25 18:19:30 2008
@@ -288,12 +288,6 @@
                                    gboolean fetch_all_headers);
 void libbalsa_message_body_unref(LibBalsaMessage * message);
 
-gboolean libbalsa_message_postpone(LibBalsaMessage * message,
-				   LibBalsaMailbox * draftbox,
-				   LibBalsaMessage * reply_message,
-				   gchar ** extra_headers,
-				   gboolean flow);
-
 /*
  * misc message releated functions
  */

Modified: trunk/libbalsa/misc.c
==============================================================================
--- trunk/libbalsa/misc.c	(original)
+++ trunk/libbalsa/misc.c	Fri Apr 25 18:19:30 2008
@@ -53,36 +53,6 @@
 					      LibBalsaCodeset Codeset);
 static int getdnsdomainname(char *s, size_t l);
 
-/* libbalsa_lookup_mime_type:
-   find out mime type of a file. Must work for both relative and absolute
-   paths.
-*/
-gchar*
-libbalsa_lookup_mime_type(const gchar * path)
-{
-#ifdef HAVE_GNOME
-    GnomeVFSFileInfo* vi = gnome_vfs_file_info_new();
-    gchar* uri, *mime_type;
-
-    if(g_path_is_absolute(path))
-        uri = g_strconcat("file://", path, NULL);
-    else {
-        gchar* curr_dir = g_get_current_dir();
-        uri = g_strconcat("file://", curr_dir, "/", path, NULL);
-        g_free(curr_dir);
-    }
-    gnome_vfs_get_file_info (uri, vi,
-                             GNOME_VFS_FILE_INFO_GET_MIME_TYPE
-                             | GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
-    g_free(uri);
-    mime_type = g_strdup(gnome_vfs_file_info_get_mime_type(vi));
-    gnome_vfs_file_info_unref(vi);
-    return mime_type ? mime_type : g_strdup("application/octet-stream");
-#else
-    return g_strdup("application/octet-stream");
-#endif/* HAVE_GNOME */
-}
-
 gchar *
 libbalsa_get_hostname(void)
 {
@@ -829,43 +799,28 @@
     return attr;
 }
 
-/* Check whether a file is all ascii or utf-8, and return charset
- * accordingly (NULL if it's neither).
- * This function is called only as a last resort when a message is being
- * prepared for sending.  The charset should always be set when the file
- * is being attached.
- */
-const gchar *
-libbalsa_file_get_charset(const gchar * filename)
-{
-    LibBalsaTextAttribute attr = libbalsa_text_attr_file(filename);
-
-    if (!(attr & LIBBALSA_TEXT_HI_BIT))
-	return "us-ascii";
-    if (attr & LIBBALSA_TEXT_HI_UTF8)
-	return "utf-8";
-    return NULL;
-}
-
 #define compare_stat(osb, nsb)  ( (osb.st_dev != nsb.st_dev || osb.st_ino != nsb.st_ino || osb.st_rdev != nsb.st_rdev) ? -1 : 0 )
 
 int 
-libbalsa_safe_open (const char *path, int flags, mode_t mode)
+libbalsa_safe_open (const char *path, int flags, mode_t mode, GError **err)
 {
   struct stat osb, nsb;
   int fd;
  
-  if ((fd = open (path, flags, mode)) < 0)
-    return fd;
+  if ((fd = open (path, flags, mode)) < 0) {
+      g_set_error(err, LIBBALSA_ERROR_QUARK, errno,
+                  _("Cannot open %s: %s"), path, g_strerror(errno));
+      return fd;
+  }
  
   /* make sure the file is not symlink */
   if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 ||
-      compare_stat(osb, nsb) == -1)
-      {
-	  g_warning("safe_open(): %s is a symlink!\n", path);
-	  close (fd);
-	  return (-1);
-      }
+      compare_stat(osb, nsb) == -1) {
+      close (fd);
+      g_set_error(err, LIBBALSA_ERROR_QUARK, errno,
+                  _("Cannot open %s: is a symbolic link"), path);
+      return (-1);
+  }
  
   return (fd);
 }

Modified: trunk/libbalsa/misc.h
==============================================================================
--- trunk/libbalsa/misc.h	(original)
+++ trunk/libbalsa/misc.h	Fri Apr 25 18:19:30 2008
@@ -96,13 +96,12 @@
     GString *ml_url_buffer;
 };
 
+#define LIBBALSA_ERROR_QUARK (g_quark_from_static_string("libbalsa"))
+
 extern LibBalsaCodesetInfo libbalsa_codeset_info[];
 GtkWidget *libbalsa_charset_button_new(void);
 LibBalsaTextAttribute libbalsa_text_attr_string(const gchar * string);
 LibBalsaTextAttribute libbalsa_text_attr_file(const gchar * filename);
-const gchar *libbalsa_file_get_charset(const gchar * filename);
-
-gchar *libbalsa_lookup_mime_type(const gchar * path);
 
 size_t libbalsa_readfile(FILE * fp, char **buf);
 size_t libbalsa_readfile_nostat(FILE * fp, char **buf);
@@ -153,7 +152,7 @@
 			      guint * count, guint * index);
 #endif                          /* USE_GREGEX */
 
-int libbalsa_safe_open (const char *path, int flags, mode_t mode);
+int libbalsa_safe_open (const char *path, int flags, mode_t mode, GError **err);
 int libbalsa_lock_file (const char *path, int fd, int excl, int dot, int timeout);
 int libbalsa_unlock_file (const char *path, int fd, int dot);
 int libbalsa_safe_rename (const char *src, const char *target);

Modified: trunk/libbalsa/send.c
==============================================================================
--- trunk/libbalsa/send.c	(original)
+++ trunk/libbalsa/send.c	Fri Apr 25 18:19:30 2008
@@ -402,8 +402,8 @@
     guint big_message;
 #endif /* ESMTP */
     gboolean rc;
-    GError *err = NULL;
 
+    g_assert(error != NULL);
     g_return_val_if_fail(message, LIBBALSA_MESSAGE_CREATE_ERROR);
 
     if ((result = libbalsa_create_msg(message, flow, error)) !=
@@ -441,25 +441,18 @@
             }
             if (rc) {
                 message->mime_msg = mime_msgs[i];
-                rc = libbalsa_message_copy(message, outbox, &err);
+                rc = libbalsa_message_copy(message, outbox, error);
             }
             g_object_unref(mime_msgs[i]);
         }
         g_free(mime_msgs);
         message->mime_msg = mime_msg;
     } else
-        rc = libbalsa_message_copy(message, outbox, &err);
+        rc = libbalsa_message_copy(message, outbox, error);
 #else                           /* ESMTP */
-    rc = libbalsa_message_copy(message, outbox, &err);
+    rc = libbalsa_message_copy(message, outbox, error);
 #endif                          /* ESMTP */
 
-    if (!rc) {
-        libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                             _("Copying message to outbox failed: %s"),
-                             err ? err->message : "?");
-        g_clear_error(&err);
-    }
-
     return rc ?  LIBBALSA_MESSAGE_CREATE_OK : LIBBALSA_MESSAGE_QUEUE_ERROR;
 }
 
@@ -1617,11 +1610,11 @@
 	GMimeObject *mime_part;
 	mime_part=NULL;
 
-	if (body->filename) {
+	if (body->file_uri || body->filename) {
 	    if (body->content_type) {
 		mime_type = parse_content_type(body->content_type);
 	    } else {
-		gchar* mt = libbalsa_lookup_mime_type(body->filename);
+                gchar * mt = g_strdup(libbalsa_vfs_get_mime_type(body->file_uri));
 		mime_type = g_strsplit(mt,"/", 2);
 		g_free(mt);
 	    }
@@ -1633,7 +1626,7 @@
 		g_mime_object_set_content_type(mime_part, content_type);
 		g_mime_part_set_encoding(GMIME_PART(mime_part),
 			                 GMIME_PART_ENCODING_7BIT);
-		if(!strncmp( body->filename, "URL", 3 )) {
+		if (body->filename && !strncmp(body->filename, "URL", 3)) {
 		    g_mime_object_set_content_type_parameter(mime_part,
 					     "access-type", "URL");
 		    g_mime_object_set_content_type_parameter(mime_part,
@@ -1642,18 +1635,32 @@
 		    g_mime_object_set_content_type_parameter(mime_part,
 					     "access-type", "local-file");
 		    g_mime_object_set_content_type_parameter(mime_part,
-					     "name", body->filename);
+                                             "name", libbalsa_vfs_get_uri_utf8(body->file_uri));
 		}
 		lbs_set_content(GMIME_PART(mime_part),
                                 "Note: this is _not_ the real body!\n");
 	    } else if (g_ascii_strcasecmp(mime_type[0], "message") == 0) {
-		int fd;
 		GMimeStream *stream;
 		GMimeParser *parser;
 		GMimeMessage *mime_message;
+		GError *err = NULL;
 
-		fd = open(body->filename, O_RDONLY);
-		stream = g_mime_stream_fs_new(fd);
+		stream = libbalsa_vfs_create_stream(body->file_uri, 0, FALSE, &err);
+		if(!stream) {
+		    if(err) {
+			gchar *msg = 
+			    err->message
+			    ? g_strdup_printf(_("Cannot read %s: %s"),
+					      libbalsa_vfs_get_uri_utf8(body->file_uri),
+					      err->message)
+			    : g_strdup_printf(_("Cannot read %s"),
+					      libbalsa_vfs_get_uri_utf8(body->file_uri));
+			g_set_error(error, err->domain, err->code, msg);
+			g_clear_error(&err);
+			g_free(msg);
+		    }
+		    return LIBBALSA_MESSAGE_CREATE_ERROR;
+		}
 		parser = g_mime_parser_new_with_stream(stream);
 		g_object_unref(stream);
 		mime_message = g_mime_parser_construct_message(parser);
@@ -1666,12 +1673,11 @@
 		const gchar *charset = NULL;
 		GMimeStream *stream;
 		GMimeDataWrapper *content;
-		int fd;
-		gchar *utf8name;
+		GError *err = NULL;
 
 		if (!strcasecmp(mime_type[0], "text")
 		    && !(charset = body->charset)) {
-		    charset = libbalsa_file_get_charset(body->filename);
+		    charset = libbalsa_vfs_get_charset(body->file_uri);
 		    if (!charset) {
 			static const gchar default_type[] =
 			    "application/octet-stream";
@@ -1680,7 +1686,8 @@
 					     _("Cannot determine charset "
 					       "for text file `%s'; "
 					       "sending as mime type `%s'"),
-					     body->filename, default_type);
+					     libbalsa_vfs_get_uri_utf8(body->file_uri),
+                                             default_type);
 			g_strfreev(mime_type);
 			mime_type = g_strsplit(default_type, "/", 2);
 		    }
@@ -1705,14 +1712,25 @@
 							     charset);
 		}
 
-		tmp = g_path_get_basename(body->filename);
-		utf8name = g_filename_to_utf8(tmp, -1, NULL, NULL, NULL);
-		g_free(tmp);
-		g_mime_part_set_filename(GMIME_PART(mime_part), utf8name);
-		g_free(utf8name);
-
-		fd = open(body->filename, O_RDONLY);
-		stream = g_mime_stream_fs_new(fd);
+		g_mime_part_set_filename(GMIME_PART(mime_part),
+                                         libbalsa_vfs_get_basename_utf8(body->file_uri));
+		stream = libbalsa_vfs_create_stream(body->file_uri, 0, FALSE, &err);
+		if(!stream) {
+		    if(err) {
+			gchar *msg = 
+			    err->message
+			    ? g_strdup_printf(_("Cannot read %s: %s"),
+					      libbalsa_vfs_get_uri_utf8(body->file_uri),
+					      err->message)
+			    : g_strdup_printf(_("Cannot read %s"),
+					      libbalsa_vfs_get_uri_utf8(body->file_uri));
+			g_set_error(error, err->domain, err->code, msg);
+			g_clear_error(&err);
+			g_free(msg);
+		    }
+		    g_object_unref(G_OBJECT(mime_part));
+		    return LIBBALSA_MESSAGE_CREATE_ERROR;
+		}
 		content = g_mime_data_wrapper_new_with_stream(stream,
 			GMIME_PART_ENCODING_DEFAULT);
 		g_object_unref(stream);
@@ -1858,16 +1876,12 @@
 libbalsa_message_postpone(LibBalsaMessage * message,
                           LibBalsaMailbox * draftbox,
                           LibBalsaMessage * reply_message,
-			  gchar ** extra_headers, gboolean flow)
+			  gchar ** extra_headers, gboolean flow,
+			  GError **error)
 {
-    gboolean retval;
-    GError *err = NULL;
-
-    /* in postpone mode no crypto operation is triggered, so we don't need to
-       pass the error */
     if (!message->mime_msg
         && libbalsa_message_create_mime_message(message, flow,
-                                                TRUE, NULL) !=
+                                                TRUE, error) !=
         LIBBALSA_MESSAGE_CREATE_OK)
         return FALSE;
 
@@ -1879,16 +1893,7 @@
 				      extra_headers[i + 1]);
     }
 
-    retval = libbalsa_message_copy(message, draftbox, &err);
-
-    if (!retval) {
-        libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                             _("Postponing message failed: %s"),
-                             err ? err->message : "?");
-        g_clear_error(&err);
-    }
-
-    return retval;
+    return libbalsa_message_copy(message, draftbox, error);
 }
 
 

Modified: trunk/libbalsa/send.h
==============================================================================
--- trunk/libbalsa/send.h	(original)
+++ trunk/libbalsa/send.h	Fri Apr 25 18:19:30 2008
@@ -39,6 +39,14 @@
     LIBBALSA_MESSAGE_SERVER_ERROR
 };
 
+gboolean libbalsa_message_postpone(LibBalsaMessage * message,
+				   LibBalsaMailbox * draftbox,
+				   LibBalsaMessage * reply_message,
+				   gchar ** extra_headers,
+				   gboolean flow, 
+				   GError **error);
+
+
 #if ENABLE_ESMTP
 #include <libesmtp.h>
 

Modified: trunk/src/balsa-message.c
==============================================================================
--- trunk/src/balsa-message.c	(original)
+++ trunk/src/balsa-message.c	Fri Apr 25 18:19:30 2008
@@ -47,6 +47,7 @@
 #include "send.h"
 #include "quote-color.h"
 #include "sendmsg-window.h"
+#include "libbalsa-vfs.h"
 
 #include <libgnomevfs/gnome-vfs-mime-handlers.h>
 
@@ -1072,9 +1073,9 @@
     bm->message = message = libbalsa_mailbox_get_message(mailbox, msgno);
     if (!message) {
 	balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not access message %ld "
+                          _("Could not access message %u "
                             "in mailbox \"%s\"."),
-			  msgno, mailbox->name);
+			  (unsigned int) msgno, mailbox->name);
         return FALSE;
     }
 
@@ -1084,9 +1085,9 @@
         g_object_unref(bm->message);
         bm->message = NULL;
 	balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not access message %ld "
+                          _("Could not access message %u "
                             "in mailbox \"%s\"."),
-			  msgno, mailbox->name);
+			  (unsigned int) msgno, mailbox->name);
         return FALSE;
     }
 
@@ -1420,7 +1421,7 @@
 #endif
         if (!content_icon)
 	    content_icon = 
-		libbalsa_icon_finder(content_type, body->filename, NULL,
+		libbalsa_icon_finder(content_type, NULL, NULL,
 				     GTK_ICON_SIZE_LARGE_TOOLBAR);
         gtk_tree_store_set (GTK_TREE_STORE(model), iter, 
                             PART_INFO_COLUMN, info,
@@ -1432,7 +1433,7 @@
         g_free(icon_title);
     } else {
 	content_icon =
-	    libbalsa_icon_finder(content_type, body->filename, NULL,
+	    libbalsa_icon_finder(content_type, NULL, NULL,
 				 GTK_ICON_SIZE_LARGE_TOOLBAR);
         gtk_tree_store_set (GTK_TREE_STORE(model), iter, 
                             PART_INFO_COLUMN, NULL,
@@ -1649,30 +1650,38 @@
                                     GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
     gtk_dialog_set_default_response(GTK_DIALOG(dump_dialog),
                                     GTK_RESPONSE_CANCEL);
-
+    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dump_dialog),
+                                    libbalsa_vfs_local_only());
     if (balsa_app.save_dir)
-        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dump_dialog),
-                                            balsa_app.save_dir);
+        gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(dump_dialog),
+                                                balsa_app.save_dir);
 
     if (gtk_dialog_run(GTK_DIALOG(dump_dialog)) == GTK_RESPONSE_OK) {
-	gchar *dirname =
-	    gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dump_dialog));
+	gchar *dir_name =
+            gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dump_dialog));
+        LibbalsaVfs * dir_uri;
+
+        g_message("store to URI: %s", dir_name);
+        if (!(dir_uri = libbalsa_vfs_new_from_uri(dir_name)))
+            balsa_information(LIBBALSA_INFORMATION_ERROR,
+                              _("Could not create URI for %s"),
+                              dir_name);
 
 	/* remember the folder */
 	g_free(balsa_app.save_dir);
-	balsa_app.save_dir = g_strdup(dirname);
+	balsa_app.save_dir = dir_name;
 
 	/* save all parts without further user interaction */
 	info_list = g_list_first(info_list);
-	while (info_list) {
+	while (dir_uri && info_list) {
 	    BalsaPartInfo *info = BALSA_PART_INFO(info_list->data);
-	    gchar *save_name;
+            LibbalsaVfs * save_uri;
 	    gboolean result;
             GError *err = NULL;
 
 	    if (info->body->filename)
-		save_name =
-		    g_build_filename(dirname, info->body->filename, NULL);
+		save_uri =
+		    libbalsa_vfs_dir_append(dir_uri, info->body->filename);
 	    else {
 		gchar *cont_type =
 		    libbalsa_message_body_get_mime_type(info->body);
@@ -1682,41 +1691,46 @@
 		g_strdelimit(cont_type, G_DIR_SEPARATOR_S, '-');
 		p = g_strdup_printf(_("%s message part"), cont_type);
 		g_free(cont_type);
-		save_name = g_build_filename(dirname, p, NULL);
+		save_uri = libbalsa_vfs_dir_append(dir_uri, p);
 		g_free(p);
 	    }
+            g_message("store to file: %s", libbalsa_vfs_get_uri_utf8(save_uri));
 
 	    /* don't overwrite existing files, append (1), (2), ... instead */
-	    if (access(save_name, F_OK) == 0) {
+	    if (libbalsa_vfs_file_exists(save_uri)) {
 		gint n = 1;
-		gchar *base_name = save_name;
+		LibbalsaVfs * base_uri = save_uri;
 
-		save_name = NULL;
+		save_uri = NULL;
 		do {
-		    g_free(save_name);
-		    save_name = g_strdup_printf("%s (%d)", base_name, n++);
-		} while (access(save_name, F_OK) == 0);
-		g_free(base_name);
+                    gchar * ext = g_strdup_printf(" (%d)", n++);
+		    if (save_uri)
+                        g_object_unref(save_uri);
+                    save_uri = libbalsa_vfs_append(base_uri, ext);
+                    g_free(ext);
+		} while (libbalsa_vfs_file_exists(save_uri));
+		g_object_unref(base_uri);
 	    }
+            g_message("store to file: %s", libbalsa_vfs_get_uri_utf8(save_uri));
 
 	    /* try to save the file */
             result =
-                libbalsa_message_body_save(info->body, save_name,
-                                           LIBBALSA_MESSAGE_BODY_UNSAFE,
-                                           info->body->body_type ==
-                                           LIBBALSA_MESSAGE_BODY_TYPE_TEXT,
-                                           &err);
+                libbalsa_message_body_save_vfs(info->body, save_uri,
+                                               LIBBALSA_MESSAGE_BODY_UNSAFE,
+                                               info->body->body_type ==
+                                               LIBBALSA_MESSAGE_BODY_TYPE_TEXT,
+                                               &err);
 	    if (!result)
 		balsa_information(LIBBALSA_INFORMATION_ERROR,
 				  _("Could not save %s: %s"),
-				  save_name,
-                                  err->message ? 
+				  libbalsa_vfs_get_uri_utf8(save_uri),
+                                  err && err->message ? 
                                   err->message : "Unknown error");
             g_clear_error(&err);
-	    g_free(save_name);
+	    g_object_unref(save_uri);
 	    info_list = g_list_next(info_list);
 	}
-	g_free(dirname);
+	g_object_unref(dir_uri);
     }
     gtk_widget_destroy(dump_dialog);
 }

Modified: trunk/src/balsa-mime-widget-callbacks.c
==============================================================================
--- trunk/src/balsa-mime-widget-callbacks.c	(original)
+++ trunk/src/balsa-mime-widget-callbacks.c	Fri Apr 25 18:19:30 2008
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "balsa-app.h"
 #include <glib/gi18n.h>
+#include "libbalsa-vfs.h"
 #include "balsa-message.h"
 #include "balsa-mime-widget.h"
 #include "balsa-mime-widget-callbacks.h"
@@ -136,7 +137,8 @@
 {
     gchar *cont_type, *title;
     GtkWidget *save_dialog;
-    gchar *filename;
+    gchar *file_uri;
+    LibbalsaVfs *save_file;
     gboolean do_save;
     GError *err = NULL;
 
@@ -156,12 +158,14 @@
     g_free(title);
     g_free(cont_type);
 
+    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(save_dialog),
+                                    libbalsa_vfs_local_only());
     if (balsa_app.save_dir)
-	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog),
-					    balsa_app.save_dir);
+        gtk_file_chooser_set_current_folder_uri(GTK_FILE_CHOOSER(save_dialog),
+                                                balsa_app.save_dir);
 
     if (mime_body->filename) {
-	gchar *filename = g_strdup(mime_body->filename);
+        gchar * filename = g_strdup(mime_body->filename);
 	libbalsa_utf8_sanitize(&filename, balsa_app.convert_unknown_8bit,
 			       NULL);
 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
@@ -175,15 +179,23 @@
 	return;
     }
 
-    /* attempt to save the file */
-    filename
-	= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_dialog));
+    /* get the file name */
+    file_uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(save_dialog));
     gtk_widget_destroy(save_dialog);
+    if (!(save_file = libbalsa_vfs_new_from_uri(file_uri))) {
+        balsa_information(LIBBALSA_INFORMATION_ERROR,
+                          _("Could not construct uri from %s"),
+                          file_uri);
+        g_free(file_uri);
+	return;
+    }
 
+    /* remember the folder uri */
     g_free(balsa_app.save_dir);
-    balsa_app.save_dir = g_path_get_dirname(filename);
+    balsa_app.save_dir = g_strdup(libbalsa_vfs_get_folder(save_file));
 
-    if (access(filename, F_OK) == 0) {
+    /* get a confirmation to overwrite if the file exists */
+    if (libbalsa_vfs_file_exists(save_file)) {
 	GtkWidget *confirm;
 
 	/* File exists. check if they really want to overwrite */
@@ -196,19 +208,27 @@
 	    (gtk_dialog_run(GTK_DIALOG(confirm)) == GTK_RESPONSE_YES);
 	gtk_widget_destroy(confirm);
 	if (do_save)
-	    unlink(filename);
+	    if (libbalsa_vfs_file_unlink(save_file, &err) != 0)
+                balsa_information(LIBBALSA_INFORMATION_ERROR,
+                                  _("Unlink %s: %s"),
+                                  file_uri, err ? err->message : "Unknown error");
     } else
 	do_save = TRUE;
 
-    if (do_save)
-	if (!libbalsa_message_body_save(mime_body, filename,
-                                        LIBBALSA_MESSAGE_BODY_UNSAFE,
-					mime_body->body_type ==
-					LIBBALSA_MESSAGE_BODY_TYPE_TEXT, &err))
+    /* save the file */
+    if (do_save) {
+	if (!libbalsa_message_body_save_vfs(mime_body, save_file,
+                                            LIBBALSA_MESSAGE_BODY_UNSAFE,
+                                            mime_body->body_type ==
+                                            LIBBALSA_MESSAGE_BODY_TYPE_TEXT,
+                                            &err))
 	    balsa_information(LIBBALSA_INFORMATION_ERROR,
 			      _("Could not save %s: %s"),
-			      filename, err ? err->message : "Unknown error");
-    g_free(filename);
+			      file_uri, err ? err->message : "Unknown error");
+    }
+
+    g_object_unref(save_file);
+    g_free(file_uri);
 }
 
 static void

Modified: trunk/src/balsa-mime-widget-message.c
==============================================================================
--- trunk/src/balsa-mime-widget-message.c	(original)
+++ trunk/src/balsa-mime-widget-message.c	Fri Apr 25 18:19:30 2008
@@ -90,7 +90,6 @@
     if (!g_ascii_strcasecmp("message/external-body", content_type)) {
 	gchar *access_type;
 	rfc_extbody_id *extbody_type = rfc_extbodys;
-	BalsaMimeWidget *mw = NULL;
 
 	access_type =
 	    libbalsa_message_body_get_parameter(mime_body, "access-type");
@@ -150,19 +149,14 @@
     BalsaMimeWidget *mw;
 
     if (url_type == RFC2046_EXTBODY_LOCALFILE) {
-	gchar *local_name;
-
-	local_name =
-	    libbalsa_message_body_get_parameter(mime_body, "name");
+	url = libbalsa_message_body_get_parameter(mime_body, "name");
 
-	if (!local_name)
+	if (!url)
 	    return NULL;
 
-	url = g_strdup_printf("file:%s", local_name);
 	msg = g_string_new(_("Content Type: external-body\n"));
 	g_string_append_printf(msg, _("Access type: local-file\n"));
-	g_string_append_printf(msg, _("File name: %s"), local_name);
-	g_free(local_name);
+	g_string_append_printf(msg, _("File name: %s"), url);
     } else if (url_type == RFC2017_EXTBODY_URL) {
 	gchar *local_name;
 

Modified: trunk/src/information-dialog.h
==============================================================================
--- trunk/src/information-dialog.h	(original)
+++ trunk/src/information-dialog.h	Fri Apr 25 18:19:30 2008
@@ -31,10 +31,20 @@
     BALSA_INFORMATION_SHOW_STDERR,
 };
 
-void balsa_information(LibBalsaInformationType type, const char *fmt, ...);
+void balsa_information(LibBalsaInformationType type, const char *fmt, ...)
+#ifdef __GNUC__
+    __attribute__ ((format (printf, 2, 3)))
+#endif
+;
+
 void balsa_information_parented(GtkWindow *widget,
                                 LibBalsaInformationType type, 
-                                const char *fmt, ...);
+                                const char *fmt, ...)
+#ifdef __GNUC__
+    __attribute__ ((format (printf, 3, 4)));
+#endif
+;
+
 void balsa_information_real(GtkWindow *parent, LibBalsaInformationType type,
                             const char *msg);
 

Modified: trunk/src/main.c
==============================================================================
--- trunk/src/main.c	(original)
+++ trunk/src/main.c	Fri Apr 25 18:19:30 2008
@@ -284,7 +284,7 @@
 	{"compose", 'm', 0, G_OPTION_ARG_STRING, &(opt_compose_email),
 	 N_("Compose a new email to EMAIL ADDRESS"), "EMAIL ADDRESS"},
 	{"attach", 'a', 0, G_OPTION_ARG_FILENAME_ARRAY, &(attach_vect),
-	 N_("Attach file at PATH"), "PATH"},
+	 N_("Attach file at URI"), "URI"},
 	{"open-mailbox", 'o', 0, G_OPTION_ARG_STRING,
          &(cmd_line_open_mailboxes),
 	 N_("Opens MAILBOXNAME"), N_("MAILBOXNAME")},
@@ -859,7 +859,7 @@
         for(lst = opt_attach_list; lst; lst = g_slist_next(lst))
             add_attachment(snd, lst->data, FALSE, NULL);
 	snd->quit_on_close = FALSE;
-    };
+    }
     gtk_widget_show(window);
 
     if (cmd_check_mail_on_startup || balsa_app.check_mail_upon_startup)

Modified: trunk/src/sendmsg-window.c
==============================================================================
--- trunk/src/sendmsg-window.c	(original)
+++ trunk/src/sendmsg-window.c	Fri Apr 25 18:19:30 2008
@@ -34,6 +34,7 @@
 #include <libgnomevfs/gnome-vfs-uri.h>
 #include <libgnomevfs/gnome-vfs-mime-handlers.h>
 #include <glib/gi18n.h>
+#include <glib/gstdio.h>
 #include <ctype.h>
 #include <glib.h>
 
@@ -41,7 +42,6 @@
 #include <locale.h>
 #endif
 
-#include <sys/stat.h>		/* for check_if_regular_file() */
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -114,7 +114,6 @@
 
 static void close_window_cb    (GtkAction * action, gpointer data);
 
-static gchar* check_if_regular_file(const gchar *);
 static void balsa_sendmsg_destroy_handler(BalsaSendmsg * bsmsg);
 static void check_readiness(BalsaSendmsg * bsmsg);
 static void init_menus(BalsaSendmsg *);
@@ -667,7 +666,8 @@
     BalsaSendmsg *bm;                 /* send message back reference */
 
     GtkWidget *popup_menu;            /* popup menu */
-    gchar *filename;                  /* file name of the attachment */
+    LibbalsaVfs *file_uri;            /* file uri of the attachment */
+    gchar *uri_ref;                   /* external body URI reference */
     gchar *force_mime_type;           /* force using this particular mime type */
     gchar *charset;                   /* forced character set */
     gboolean delete_on_destroy;       /* destroy the file when not used any more */
@@ -735,7 +735,7 @@
     BalsaAttachInfo * info = BALSA_ATTACH_INFO(object);
     
     info->popup_menu = NULL;
-    info->filename = NULL;
+    info->file_uri = NULL;
     info->force_mime_type = NULL;
     info->charset = NULL;
     info->delete_on_destroy = FALSE;
@@ -763,24 +763,32 @@
     info = BALSA_ATTACH_INFO(object);
 
     /* unlink the file if necessary */
-    if (info->delete_on_destroy) {
-	char *last_slash = strrchr(info->filename, '/');
+    if (info->delete_on_destroy && info->file_uri) {
+        gchar * folder_name;
 
+        /* unlink the file */
 	if (balsa_app.debug)
 	    fprintf (stderr, "%s:%s: unlink `%s'\n", __FILE__, __FUNCTION__,
-		     info->filename);
-	unlink(info->filename);
-	*last_slash = 0;
-	if (balsa_app.debug)
-	    fprintf (stderr, "%s:%s: rmdir `%s'\n", __FILE__, __FUNCTION__,
-		     info->filename);
-	rmdir(info->filename);
+		     libbalsa_vfs_get_uri_utf8(info->file_uri));
+	libbalsa_vfs_file_unlink(info->file_uri, NULL);
+
+        /* remove the folder if possible */
+        folder_name = g_filename_from_uri(libbalsa_vfs_get_folder(info->file_uri),
+                                          NULL, NULL);
+        if (folder_name) {
+            if (balsa_app.debug)
+                fprintf (stderr, "%s:%s: rmdir `%s'\n", __FILE__, __FUNCTION__,
+                         folder_name);
+            g_rmdir(folder_name);
+            g_free(folder_name);
+        }
     }
 
     /* clean up memory */
     if (info->popup_menu)
         gtk_widget_destroy(info->popup_menu);
-    g_free(info->filename);
+    if (info->file_uri)
+        g_object_unref(G_OBJECT(info->file_uri));
     g_free(info->force_mime_type);
     g_free(info->charset);
     libbalsa_message_headers_destroy(info->headers);
@@ -1702,14 +1710,9 @@
     /* verify that the user *really* wants to attach as reference */
     if (info->mode != new_mode && new_mode == LIBBALSA_ATTACH_AS_EXTBODY) {
 	GtkWidget *extbody_dialog, *parent;
-	gchar *utf8name;
-	GError *err = NULL;
 	gint result;
 
 	parent = gtk_widget_get_ancestor(menu_item, GNOME_TYPE_APP);
-	utf8name = g_filename_to_utf8(info->filename, -1, NULL, NULL, &err);
-	if (err)
-	    g_error_free(err);
 	extbody_dialog =
 	    gtk_message_dialog_new(GTK_WINDOW(parent),
 				   GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1723,8 +1726,7 @@
 				     "`real' file.\n\n"
 				     "Do you really want to attach "
 				     "this file as reference?"),
-				   utf8name);
-	g_free(utf8name);
+				   libbalsa_vfs_get_uri_utf8(info->file_uri));
 	gtk_window_set_title(GTK_WINDOW(extbody_dialog),
 			     _("Attach as Reference?"));
 	result = gtk_dialog_run(GTK_DIALOG(extbody_dialog));
@@ -1763,7 +1765,7 @@
 #endif /* HAVE_GNOME_VFS29 */
         if (app) {
 #if HAVE_GNOME_VFS29
-            gchar *uri = g_strconcat("file://", info->filename, NULL);
+            gchar *uri = g_strdup(libbalsa_vfs_get_uri(info->file_uri));
             GList *uris = g_list_prepend(NULL, uri);
             gnome_vfs_mime_application_launch(app, uris);
             g_free(uri);
@@ -1793,15 +1795,18 @@
 on_open_url_cb(GtkWidget * menu_item, BalsaAttachInfo * info)
 {
     GError *err = NULL;
+    const gchar * uri;
 
     g_return_if_fail(info != NULL);
+    uri = libbalsa_vfs_get_uri(info->file_uri);
+    g_return_if_fail(uri != NULL);
 
-    g_message("open URL %s", info->filename + 4);
-    //    gnome_url_show(info->filename + 4, &err);
+    g_message("open URL %s", uri);
+    gnome_url_show(uri, &err);
     if (err) {
         balsa_information(LIBBALSA_INFORMATION_WARNING,
 			  _("Error showing %s: %s\n"),
-			  info->filename + 4, err->message);
+			  uri, err->message);
         g_error_free(err);
     }
 }
@@ -1917,10 +1922,11 @@
         charset = info->std;
         if (info->win && (attr & LIBBALSA_TEXT_HI_CTRL)) {
             charset = info->win;
-            libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                                 _("Character set for file %s changed "
-                                   "from \"%s\" to \"%s\"."), filename,
-                                 info->std, info->win);
+            balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                       LIBBALSA_INFORMATION_WARNING,
+                                       _("Character set for file %s changed "
+                                         "from \"%s\" to \"%s\"."), filename,
+                                       info->std, info->win);
         }
     }
     *attach_charset = g_strdup(charset);
@@ -1981,38 +1987,46 @@
 
 
 /* add_attachment:
-   adds given filename to the list.
-   takes over the ownership of filename.
+   adds given filename (uri format) to the list.
 */
 gboolean
-add_attachment(BalsaSendmsg * bsmsg, gchar *filename, 
+add_attachment(BalsaSendmsg * bsmsg, const gchar *filename, 
                gboolean is_a_temp_file, const gchar *forced_mime_type)
 {
+    LibbalsaVfs * file_uri;
     GtkTreeModel *model;
     GtkTreeIter iter;
     BalsaAttachInfo *attach_data;
     gboolean can_inline, is_fwd_message;
     gchar *content_type = NULL;
-    gchar *err_bsmsg;
     gchar *utf8name;
     GError *err = NULL;
     GdkPixbuf *pixbuf;
     GtkWidget *menu_item;
-    struct stat attach_stat;
 
     if (balsa_app.debug)
 	fprintf(stderr, "Trying to attach '%s'\n", filename);
-    if ( (err_bsmsg=check_if_regular_file(filename)) != NULL) {
-        balsa_information(LIBBALSA_INFORMATION_ERROR, "%s", err_bsmsg);
-	g_free(err_bsmsg);
-	g_free(filename);
+    if (!(file_uri = libbalsa_vfs_new_from_uri(filename))) {
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_ERROR,
+                                   _("Cannot create file URI object for %s"),
+                                   filename);
+        return FALSE;
+    }
+    if (!libbalsa_vfs_is_regular_file(file_uri, &err)) {
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_ERROR,
+                                   "%s: %s", filename,
+                                   err && err->message ? err->message : _("unknown error"));
+	g_error_free(err);
+	g_object_unref(file_uri);
 	return FALSE;
     }
 
 #if defined(ENABLE_TOUCH_UI)
     if(!bsmsg_check_format_compatibility(GTK_WINDOW(bsmsg->window),
 		                         filename)) {
-	g_free(filename);
+	g_object_unref(file_uri);
         return FALSE;
     }
 #endif /* ENABLE_TOUCH_UI */
@@ -2023,7 +2037,7 @@
     if (is_fwd_message)
 	content_type = g_strdup(forced_mime_type);
     pixbuf = 
-	libbalsa_icon_finder(forced_mime_type, filename, &content_type,
+	libbalsa_icon_finder(forced_mime_type, file_uri, &content_type,
 			     GTK_ICON_SIZE_LARGE_TOOLBAR);
     if (!content_type)
 	/* Last ditch. */
@@ -2038,7 +2052,6 @@
 			    &change_type, &attach_data->charset)) {
 	    g_free(content_type);
 	    g_object_unref(attach_data);
-	    g_free(filename);
 	    return FALSE;
 	}
 	if (change_type) {
@@ -2062,32 +2075,20 @@
 	    g_free(tmp);
 	}
     } else {
+        const gchar *uri_utf8 = libbalsa_vfs_get_uri_utf8(file_uri);
 	const gchar *home = g_getenv("HOME");
 
-	if (home && !strncmp(filename, home, strlen(home))) {
-	    utf8name = g_filename_to_utf8(filename + strlen(home) - 1, -1,
-					  NULL, NULL, &err);
-	    if (utf8name)
-		*utf8name = '~';
+	if (home && !strncmp(uri_utf8, "file://", 7) &&
+            !strncmp(uri_utf8 + 7, home, strlen(home))) {
+	    utf8name = g_strdup_printf("~%s", uri_utf8 + 7 + strlen(home));
 	} else
-	    utf8name = g_filename_to_utf8(filename, -1, NULL, NULL, &err);
-
-	if (err) {
-	    balsa_information(LIBBALSA_INFORMATION_WARNING,
-			      _("Error converting \"%s\" to UTF-8: %s\n"),
-			      filename, err->message);
-	    g_error_free(err);
-	}
+	    utf8name = g_strdup(uri_utf8);
     }
 
-    /* determine the size of the attachment */
-    if (stat(filename, &attach_stat) == -1)
-	attach_stat.st_size = 0;
-    
     model = BALSA_MSG_ATTACH_MODEL(bsmsg);
     gtk_list_store_append(GTK_LIST_STORE(model), &iter);
     
-    attach_data->filename = filename;
+    attach_data->file_uri = file_uri;
     attach_data->force_mime_type = g_strdup(forced_mime_type);
     
     attach_data->delete_on_destroy = is_a_temp_file;
@@ -2166,7 +2167,7 @@
 		       ATTACH_ICON_COLUMN, pixbuf,
 		       ATTACH_TYPE_COLUMN, content_type,
 		       ATTACH_MODE_COLUMN, attach_data->mode,
-		       ATTACH_SIZE_COLUMN, (gfloat) attach_stat.st_size,
+		       ATTACH_SIZE_COLUMN, (gfloat) libbalsa_vfs_get_size(file_uri),
 		       ATTACH_DESC_COLUMN, utf8name,
 		       -1);
     g_object_unref(attach_data);
@@ -2207,7 +2208,7 @@
     model = BALSA_MSG_ATTACH_MODEL(bsmsg);
     gtk_list_store_append(GTK_LIST_STORE(model), &iter);
     
-    attach_data->filename = g_strconcat("URL:", url, NULL);
+    attach_data->uri_ref = g_strconcat("URL:", url, NULL);
     attach_data->force_mime_type = g_strdup("message/external-body");
     attach_data->delete_on_destroy = FALSE;
     attach_data->mode = LIBBALSA_ATTACH_AS_EXTBODY;
@@ -2241,7 +2242,7 @@
 		       ATTACH_ICON_COLUMN, pixbuf,
 		       ATTACH_TYPE_COLUMN, _("(URL)"),
 		       ATTACH_MODE_COLUMN, attach_data->mode,
-		       ATTACH_SIZE_COLUMN, 0,
+		       ATTACH_SIZE_COLUMN, (gfloat) 0.0,
 		       ATTACH_DESC_COLUMN, url,
 		       -1);
     g_object_unref(attach_data);
@@ -2253,26 +2254,6 @@
     return TRUE;
 }
 
-static gchar* 
-check_if_regular_file(const gchar * filename)
-{
-    struct stat s;
-    gchar *ptr = NULL;
-
-    if (stat(filename, &s))
-	ptr = g_strdup_printf(_("Cannot get info on file '%s': %s"),
-			      filename, strerror(errno));
-    else if (!S_ISREG(s.st_mode))
-	ptr =
-	    g_strdup_printf(
-		_("Attachment %s is not a regular file."), filename);
-    else if(access(filename, R_OK) != 0) {
-	ptr =
-	    g_strdup_printf(_("File %s cannot be read\n"), filename);
-    }
-    return ptr;
-}
-
 /* attach_dialog_ok:
    processes the attachment file selection. Adds them to the list,
    showing the attachment list, if was hidden.
@@ -2294,16 +2275,17 @@
     }
 
     fc = GTK_FILE_CHOOSER(dialog);
-    files = gtk_file_chooser_get_filenames(fc);
-    for (list = files; list; list = list->next)
+    files = gtk_file_chooser_get_uris(fc);
+    for (list = files; list; list = list->next) {
         if(!add_attachment(bsmsg, list->data, FALSE, NULL))
 	    res++;
+        g_free(list->data);
+    }
 
-    /* add_attachment takes ownership of the filenames. */
     g_slist_free(files);
     
     g_free(balsa_app.attach_dir);
-    balsa_app.attach_dir = gtk_file_chooser_get_current_folder(fc);
+    balsa_app.attach_dir = gtk_file_chooser_get_current_folder_uri(fc);
 
     if (res == 0)
         gtk_widget_destroy(dialog);
@@ -2321,12 +2303,14 @@
                                     GTK_FILE_CHOOSER_ACTION_OPEN,
                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                     GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fsw),
+                                    libbalsa_vfs_local_only());
     gtk_window_set_destroy_with_parent(GTK_WINDOW(fsw), TRUE);
 
     fc = GTK_FILE_CHOOSER(fsw);
     gtk_file_chooser_set_select_multiple(fc, TRUE);
     if (balsa_app.attach_dir)
-	gtk_file_chooser_set_current_folder(fc, balsa_app.attach_dir);
+	gtk_file_chooser_set_current_folder_uri(fc, balsa_app.attach_dir);
 
     g_signal_connect(G_OBJECT(fc), "response",
 		     G_CALLBACK(attach_dialog_response), bsmsg);
@@ -2360,8 +2344,10 @@
         g_free(name);
         return FALSE;
     }
-    add_attachment(bsmsg, name,
-		   TRUE, "message/rfc822");
+    tmp_file_name = g_filename_to_uri(name, NULL, NULL);
+    g_free(name);
+    add_attachment(bsmsg, tmp_file_name, TRUE, "message/rfc822");
+    g_free(tmp_file_name);
     return TRUE;
 }
 
@@ -2408,9 +2394,10 @@
 	    LibBalsaMessage *message = node->data;
 
 	    if(!attach_message(bsmsg, message)) {
-                libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                                     _("Attaching message failed.\n"
-                                       "Possible reason: not enough temporary space"));
+                balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                           LIBBALSA_INFORMATION_WARNING,
+                                           _("Attaching message failed.\n"
+                                             "Possible reason: not enough temporary space"));
                 break;
             }
 	}
@@ -2442,14 +2429,11 @@
     
     length = linebreak - uri_list;
 
-    if (length && uri_list[0] != '#' && strncmp(uri_list,"file://",7)==0) {
+    if (length && uri_list[0] != '#') {
 	gchar *this_uri = g_strndup(uri_list, length);
-	gchar *uri;
 
-	uri = g_filename_from_uri(this_uri, NULL, NULL);
-	g_free(this_uri);
-	if (uri)
-	    list = g_slist_append(list, uri);
+	if (this_uri)
+	    list = g_slist_append(list, this_uri);
       }
 
     uri_list = linebreak + 2;
@@ -2519,17 +2503,18 @@
                 continue;
 
             if(!attach_message(bsmsg, message))
-                libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                                     _("Attaching message failed.\n"
-                                       "Possible reason: not enough temporary space"));
+                balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                           LIBBALSA_INFORMATION_WARNING,
+                                           _("Attaching message failed.\n"
+                                             "Possible reason: not enough temporary space"));
 	    g_object_unref(message);
         }
         balsa_index_selected_msgnos_free(index, selected);
     } else if (info == TARGET_URI_LIST) {
         GSList *uri_list = uri2gslist((gchar *) selection_data->data);
         for (; uri_list; uri_list = g_slist_next(uri_list)) {
-	    add_attachment(bsmsg,
-			   uri_list->data, FALSE, NULL); /* steal strings */
+	    add_attachment(bsmsg, uri_list->data, FALSE, NULL);
+            g_free(uri_list->data);
         }
         g_slist_free(uri_list);
     } else if( info == TARGET_STRING) {
@@ -3054,11 +3039,13 @@
 {
     has_file_attached_t *find_file = (has_file_attached_t *)data;
     BalsaAttachInfo *info;
+    const gchar * uri;
 
     gtk_tree_model_get(model, iter, ATTACH_INFO_COLUMN, &info, -1);
     if (!info)
 	return FALSE;
-    if (!strcmp(find_file->name, info->filename))
+    uri = libbalsa_vfs_get_uri(info->file_uri);
+    if (uri && !strcmp(find_file->name, uri))
 	find_file->found = TRUE;
     g_object_unref(info);
 
@@ -3119,9 +3106,9 @@
 	    gtk_tree_model_foreach(BALSA_MSG_ATTACH_MODEL(bsmsg),
 				   has_file_attached, &find_file);
             if (!find_file.found)
-                add_attachment(bsmsg,  /* steal strings */
-                               uri_list->data, FALSE, NULL);
+                add_attachment(bsmsg, uri_list->data, FALSE, NULL);
         }
+        g_slist_foreach(uri_list, (GFunc) g_free, NULL);
         g_slist_free(uri_list);
     }
         break;
@@ -3300,9 +3287,9 @@
 	}
 	while (body) {
 	    gchar *name, *body_type, *tmp_file_name;
-	    int fd;
             GError *err = NULL;
-            gboolean res;
+            gboolean res = FALSE;
+            
 	    if (body->filename) {
 		libbalsa_mktempdir(&tmp_file_name);
 		name = g_strdup_printf("%s/%s", tmp_file_name, body->filename);
@@ -3311,19 +3298,31 @@
                                                  LIBBALSA_MESSAGE_BODY_SAFE,
                                                  FALSE, &err);
 	    } else {
-		fd = g_file_open_tmp("balsa-continue-XXXXXX", &name, NULL);
-		res = libbalsa_message_body_save_fd(body, fd, FALSE, &err);
+                int fd;
+
+		if ((fd = g_file_open_tmp("balsa-continue-XXXXXX", &name, NULL)) > 0) {
+                    GMimeStream * tmp_stream;
+
+                    if ((tmp_stream = g_mime_stream_fs_new(fd)) != NULL)
+                        res = libbalsa_message_body_save_stream(body, tmp_stream, FALSE, &err);
+                    else
+                        close(fd);
+                }
 	    }
             if(!res) {
-                balsa_information(LIBBALSA_INFORMATION_ERROR,
-                                  _("Could not save attachment: %s"),
-                                  err ? err->message : "Unknown error");
+                balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                           LIBBALSA_INFORMATION_ERROR,
+                                           _("Could not save attachment: %s"),
+                                           err ? err->message : "Unknown error");
                 g_clear_error(&err);
                 /* FIXME: do not try any further? */
             }
 	    body_type = libbalsa_message_body_get_mime_type(body);
-	    add_attachment(bsmsg, name, TRUE, body_type);
+            tmp_file_name = g_filename_to_uri(name, NULL, NULL);
+            g_free(name);
+	    add_attachment(bsmsg, tmp_file_name, TRUE, body_type);
 	    g_free(body_type);
+	    g_free(tmp_file_name);
 	    body = body->next;
 	}
     }
@@ -4936,9 +4935,10 @@
     bsmsg->type = attach ? SEND_FORWARD_ATTACH : SEND_FORWARD_INLINE;
     if (attach) {
 	if(!attach_message(bsmsg, message))
-            libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                                 _("Attaching message failed.\n"
-                                   "Possible reason: not enough temporary space"));
+            balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                       LIBBALSA_INFORMATION_WARNING,
+                                       _("Attaching message failed.\n"
+                                         "Possible reason: not enough temporary space"));
         bsmsg->state = SENDMSG_STATE_CLEAN;
         set_entry_to_subject(GTK_ENTRY(bsmsg->subject[1]), message->body_list,
                              bsmsg->type, bsmsg->ident);
@@ -5100,28 +5100,32 @@
     GtkFileChooser *attach;
 
     if (!g_path_is_absolute(val)) {
-        balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not attach the file %s: %s."), val,
-                          _("not an absolute path"));
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not attach the file %s: %s."), val,
+                                   _("not an absolute path"));
         return;
     }
     if (!(g_str_has_prefix(val, g_get_home_dir())
           || g_str_has_prefix(val, g_get_tmp_dir()))) {
-        balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not attach the file %s: %s."), val,
-                          _("not in your directory"));
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not attach the file %s: %s."), val,
+                                   _("not in your directory"));
         return;
     }
     if (!g_file_test(val, G_FILE_TEST_EXISTS)) {
-        balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not attach the file %s: %s."), val,
-                          _("does not exist"));
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not attach the file %s: %s."), val,
+                                   _("does not exist"));
         return;
     }
     if (!g_file_test(val, G_FILE_TEST_IS_REGULAR)) {
-        balsa_information(LIBBALSA_INFORMATION_WARNING,
-                          _("Could not attach the file %s: %s."), val,
-                          _("not a regular file"));
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not attach the file %s: %s."), val,
+                                   _("not a regular file"));
         return;
     }
     attach = g_object_get_data(G_OBJECT(bsmsg->window),
@@ -5142,9 +5146,10 @@
         g_free(valdir);
         if (!good) {
             /* gtk_file_chooser_select_filename will crash */
-            balsa_information(LIBBALSA_INFORMATION_WARNING,
-                              _("Could not attach the file %s: %s."), val,
-                              _("not in current directory"));
+            balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                       LIBBALSA_INFORMATION_WARNING,
+                                       _("Could not attach the file %s: %s."), val,
+                                       _("not in current directory"));
             return;
         }
     }
@@ -5273,8 +5278,9 @@
     fname = gtk_file_chooser_get_filename(fc);
 
     if ((fl = fopen(fname, "rt")) ==NULL) {
-	balsa_information(LIBBALSA_INFORMATION_WARNING,
-			  _("Could not open the file %s.\n"), fname);
+	balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not open the file %s.\n"), fname);
 	g_free(fname);
 	return;
     }
@@ -5403,7 +5409,11 @@
 
     /* create the attachment */
     body = libbalsa_message_body_new(message);
-    body->filename = g_strdup(attachment->filename);
+    body->file_uri = attachment->file_uri;
+    if (attachment->file_uri)
+        g_object_ref(attachment->file_uri);
+    else
+        body->filename = g_strdup(attachment->uri_ref);
     body->content_type = g_strdup(attachment->force_mime_type);
     body->charset = g_strdup(attachment->charset);
     body->attach_mode = attachment->mode;
@@ -5432,8 +5442,8 @@
     if (path && !(content =
                   libbalsa_get_header_from_path(header, path, NULL,
                                                 &err))) {
-        libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                             error_format, path, err->message);
+        balsa_information(LIBBALSA_INFORMATION_WARNING,
+                          error_format, path, err->message);
         g_error_free(err);
     }
 
@@ -5846,9 +5856,10 @@
     fcc = balsa_find_mailbox_by_url(bsmsg->fcc_url);
 
 #ifdef HAVE_GPGME
-    balsa_information(LIBBALSA_INFORMATION_DEBUG,
-		      _("sending message with gpg mode %d"),
-		      message->gpg_mode);
+    balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                               LIBBALSA_INFORMATION_DEBUG,
+                               _("sending message with gpg mode %d"),
+                               message->gpg_mode);
 #endif
 
 #if ENABLE_ESMTP
@@ -5900,12 +5911,12 @@
         }
 	if (error)
 	    balsa_information_parented(GTK_WINDOW(bsmsg->window),
-				       LIBBALSA_INFORMATION_WARNING,
+				       LIBBALSA_INFORMATION_ERROR,
 				       _("Send failed: %s\n%s"), msg,
 				       error->message);
 	else
 	    balsa_information_parented(GTK_WINDOW(bsmsg->window),
-				       LIBBALSA_INFORMATION_WARNING,
+				       LIBBALSA_INFORMATION_ERROR,
 				       _("Send failed: %s"), msg);
 	return FALSE;
     }
@@ -5943,6 +5954,7 @@
     gboolean successp;
     LibBalsaMessage *message;
     GPtrArray *headers;
+    GError *error = NULL;
 
     /* Silent fallback to UTF-8 */
     message = bsmsg2message(bsmsg);
@@ -5978,21 +5990,24 @@
 	successp = libbalsa_message_postpone(message, balsa_app.draftbox,
                                              bsmsg->parent_message,
                                              (gchar **) headers->pdata,
-                                             bsmsg->flow);
+                                             bsmsg->flow, &error);
     else
 	successp = libbalsa_message_postpone(message, balsa_app.draftbox, 
                                              NULL,
                                              (gchar **) headers->pdata,
-                                             bsmsg->flow);
+                                             bsmsg->flow, &error);
     g_ptr_array_foreach(headers, (GFunc) g_free, NULL);
     g_ptr_array_free(headers, TRUE);
 
     if(successp)
         sw_delete_draft(bsmsg);
-    else
+    else {
         balsa_information_parented(GTK_WINDOW(bsmsg->window),
-                                   LIBBALSA_INFORMATION_WARNING,
-                                   _("Could not postpone message."));
+                                   LIBBALSA_INFORMATION_ERROR,
+                                   _("Could not postpone message: %s"),
+				   error ? error->message : "");
+	g_clear_error(&error);
+    }
 
     g_object_unref(G_OBJECT(message));
     return successp;
@@ -6164,9 +6179,10 @@
                                 bsmsg->spell_check_lang, &err);
     if (!spell) {
         /* Should not happen, since we now check the language. */
-        libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                             _("Error starting spell checker: %s"),
-                             err->message);
+        balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Error starting spell checker: %s"),
+                                   err->message);
         g_error_free(err);
 
         /* No spell checker, so deactivate the button. */
@@ -6330,9 +6346,10 @@
         return;
 #else                           /* USE_GREGEX */
     if (regcomp(&rex, balsa_app.quote_regex, REG_EXTENDED)) {
-	balsa_information(LIBBALSA_INFORMATION_WARNING,
-			  _("Could not compile %s"),
-			  _("Quoted Text Regular Expression"));
+	balsa_information_parented(GTK_WINDOW(bsmsg->window),
+                                   LIBBALSA_INFORMATION_WARNING,
+                                   _("Could not compile %s"),
+                                   _("Quoted Text Regular Expression"));
 	return;
     }
 #endif                          /* USE_GREGEX */

Modified: trunk/src/sendmsg-window.h
==============================================================================
--- trunk/src/sendmsg-window.h	(original)
+++ trunk/src/sendmsg-window.h	Fri Apr 25 18:19:30 2008
@@ -128,7 +128,8 @@
     void sendmsg_window_set_field(BalsaSendmsg *bsmsg, const gchar* key,
                                   const gchar* val);
 
-    gboolean add_attachment(BalsaSendmsg * bsmsg, char *filename, 
+    gboolean add_attachment(BalsaSendmsg * bsmsg,
+                            const gchar *filename, 
                             gboolean is_a_tmp_file, 
                             const gchar *forced_mime_type);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]