src/mn-gmime-stream-vfs.gob (7790B) - raw
1 /* 2 * Mail Notification 3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 %headertop{ 21 #include <libgnomevfs/gnome-vfs.h> 22 #include <gmime/gmime.h> 23 %} 24 25 %{ 26 #include <glib/gi18n.h> 27 #include "mn-vfs.h" 28 29 #define VFS_CALL(stream, expr, fail_format, fail_retval) \ 30 { \ 31 GnomeVFSResult result; \ 32 \ 33 result = expr; \ 34 if (result != GNOME_VFS_OK) \ 35 { \ 36 (stream)->_priv->eof = TRUE; \ 37 if (result != GNOME_VFS_ERROR_EOF) \ 38 { \ 39 g_warning((fail_format), \ 40 (stream)->_priv->uri, \ 41 gnome_vfs_result_to_string(result)); \ 42 return (fail_retval); \ 43 } \ 44 } \ 45 } 46 47 #define VFS_READ(stream, buffer, bytes, bytes_read, fail_retval) \ 48 VFS_CALL((stream), gnome_vfs_read((stream)->_priv->handle, (buffer), (bytes), (bytes_read)), _("unable to read %s: %s"), (fail_retval)) 49 #define VFS_WRITE(stream, buffer, bytes, bytes_written, fail_retval) \ 50 VFS_CALL((stream), gnome_vfs_write((stream)->_priv->handle, (buffer), (bytes), (bytes_written)), _("unable to write to %s: %s"), (fail_retval)) 51 #define VFS_SEEK(stream, whence, offset, fail_retval) \ 52 VFS_CALL((stream), gnome_vfs_seek((stream)->_priv->handle, (whence), (offset)), _("unable to seek in %s: %s"), (fail_retval)) 53 #define VFS_TELL(stream, offset_return, fail_retval) \ 54 VFS_CALL((stream), gnome_vfs_tell((stream)->_priv->handle, (offset_return)), _("unable to tell position of %s: %s"), (fail_retval)) 55 #define VFS_CLOSE(stream, fail_retval) \ 56 VFS_CALL((stream), gnome_vfs_close((stream)->_priv->handle), _("unable to close %s: %s"), (fail_retval)) 57 %} 58 59 class MN:GMime:Stream:VFS from GMime:Stream 60 { 61 private GnomeVFSHandle *handle; 62 private gboolean handle_owned; 63 64 private char *uri destroywith g_free; /* used in error messages only */ 65 private gboolean eof; 66 67 finalize (self) 68 { 69 if (selfp->handle_owned) 70 g_mime_stream_close(GMIME_STREAM(self)); 71 } 72 73 override (GMime:Stream) ssize_t 74 read (GMimeStream *stream, char *buf, size_t len) 75 { 76 Self *self = SELF(stream); 77 GnomeVFSFileSize bytes_read; 78 79 if (stream->bound_end != -1 && stream->position >= stream->bound_end) 80 return -1; 81 if (stream->bound_end != -1) 82 len = MIN(stream->bound_end - stream->position, (off_t) len); 83 84 /* make sure we are at the right position */ 85 VFS_SEEK(self, GNOME_VFS_SEEK_START, stream->position, -1); 86 87 VFS_READ(self, buf, len, &bytes_read, -1); 88 stream->position += bytes_read; 89 90 return bytes_read; 91 } 92 93 override (GMime:Stream) ssize_t 94 write (GMimeStream *stream, const char *buf, size_t len) 95 { 96 Self *self = SELF(stream); 97 GnomeVFSFileSize bytes_written; 98 99 if (stream->bound_end != -1 && stream->position >= stream->bound_end) 100 return -1; 101 if (stream->bound_end != -1) 102 len = MIN(stream->bound_end - stream->position, (off_t) len); 103 104 /* make sure we are at the right position */ 105 VFS_SEEK(self, GNOME_VFS_SEEK_START, stream->position, -1); 106 107 VFS_WRITE(self, buf, len, &bytes_written, -1); 108 stream->position += bytes_written; 109 110 return bytes_written; 111 } 112 113 override (GMime:Stream) int 114 flush (GMimeStream *stream) 115 { 116 /* nop */ 117 return 0; /* success */ 118 } 119 120 override (GMime:Stream) int 121 close (GMimeStream *stream) 122 { 123 Self *self = SELF(stream); 124 125 VFS_CLOSE(self, -1); 126 127 return 0; /* success */ 128 } 129 130 override (GMime:Stream) gboolean 131 eos (GMimeStream *stream) 132 { 133 Self *self = SELF(stream); 134 135 if (stream->bound_end == -1) 136 return selfp->eof; 137 else 138 return stream->position >= stream->bound_end; 139 } 140 141 override (GMime:Stream) int 142 reset (GMimeStream *stream) 143 { 144 Self *self = SELF(stream); 145 146 if (stream->position == stream->bound_start) 147 return 0; 148 149 VFS_SEEK(self, GNOME_VFS_SEEK_START, stream->bound_start, -1); 150 stream->position = stream->bound_start; 151 152 return 0; 153 } 154 155 override (GMime:Stream) off_t 156 seek (GMimeStream *stream, off_t offset, GMimeSeekWhence whence) 157 { 158 Self *self = SELF(stream); 159 off_t real = stream->position; 160 161 switch (whence) 162 { 163 case GMIME_STREAM_SEEK_SET: 164 real = offset; 165 break; 166 167 case GMIME_STREAM_SEEK_CUR: 168 real = stream->position + offset; 169 break; 170 171 case GMIME_STREAM_SEEK_END: 172 if (stream->bound_end == -1) 173 { 174 GnomeVFSFileSize current_position; 175 176 VFS_SEEK(self, GNOME_VFS_SEEK_END, offset, -1); 177 VFS_TELL(self, ¤t_position, -1); 178 179 real = current_position; 180 if (real < stream->bound_start) 181 real = stream->bound_start; 182 stream->position = real; 183 184 return real; 185 } 186 real = stream->bound_end + offset; 187 break; 188 } 189 190 if (stream->bound_end != -1) 191 real = MIN(real, stream->bound_end); 192 real = MAX(real, stream->bound_start); 193 194 VFS_SEEK(self, GNOME_VFS_SEEK_START, real, -1); 195 stream->position = real; 196 197 return real; 198 } 199 200 override (GMime:Stream) off_t 201 tell (GMimeStream *stream) 202 { 203 return stream->position; 204 } 205 206 override (GMime:Stream) ssize_t 207 length (GMimeStream *stream) 208 { 209 Self *self = SELF(stream); 210 GnomeVFSFileSize bound_end; 211 212 if (stream->bound_start != -1 && stream->bound_end != -1) 213 return stream->bound_end - stream->bound_start; 214 215 VFS_SEEK(self, GNOME_VFS_SEEK_END, 0, -1); 216 VFS_TELL(self, &bound_end, -1); 217 VFS_SEEK(self, GNOME_VFS_SEEK_START, stream->position, -1); 218 219 if (bound_end < stream->bound_start) 220 return -1; 221 222 return bound_end - stream->bound_start; 223 } 224 225 override (GMime:Stream) GMimeStream * 226 substream (GMimeStream *stream, off_t start, off_t end) 227 { 228 Self *self; 229 230 self = GET_NEW; 231 selfp->handle = SELF(stream)->_priv->handle; 232 /* handle of the substream is not owned */ 233 234 g_mime_stream_construct(GMIME_STREAM(self), start, end); 235 236 return GMIME_STREAM(self); 237 } 238 239 /* 240 * Follows the GMime convention of owning the handle (even on error). 241 */ 242 public GMimeStream * 243 new (GnomeVFSHandle *handle (check null), 244 GnomeVFSURI *uri (check null), 245 GnomeVFSResult *result) 246 { 247 GMimeStream *stream; 248 GnomeVFSResult _result; 249 GnomeVFSFileSize current_position; 250 251 if (gnome_vfs_seek(handle, GNOME_VFS_SEEK_CURRENT, 0) != GNOME_VFS_OK 252 || gnome_vfs_tell(handle, ¤t_position) != GNOME_VFS_OK) 253 { 254 char *buf; 255 int size; 256 257 /* unseekable or untellable file, use a GMimeStreamMem */ 258 259 _result = mn_vfs_read_entire_file_uri(uri, &size, &buf); 260 if (_result == GNOME_VFS_OK) 261 { 262 stream = g_mime_stream_mem_new_with_buffer(buf, size); 263 g_free(buf); 264 } 265 else 266 stream = NULL; 267 268 gnome_vfs_close(handle); 269 } 270 else 271 { 272 Self *self; 273 274 _result = GNOME_VFS_OK; 275 276 self = GET_NEW; 277 selfp->handle = handle; 278 selfp->handle_owned = TRUE; 279 selfp->uri = gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE); 280 281 stream = GMIME_STREAM(self); 282 g_mime_stream_construct(stream, current_position, -1); 283 284 /* check for EOF */ 285 if (g_mime_stream_length(stream) <= 0) 286 selfp->eof = TRUE; 287 } 288 289 if (result) 290 *result = _result; 291 292 return stream; 293 } 294 }