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 }