Enable GUI option for 'custom command' connection. Don't g_free strings in
[platform/upstream/evolution-data-server.git] / camel / camel-seekable-substream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-fs.c : file system based stream
3  *
4  * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
5  *          Michael Zucchi <notzed@ximian.com>
6  *
7  * Copyright 1999-2003 Ximian, Inc. (www.ximian.com)
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU General Public
11  * License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "camel-seekable-substream.h"
29
30 static CamelSeekableStreamClass *parent_class = NULL;
31
32 /* Returns the class for a CamelSeekableSubStream */
33 #define CSS_CLASS(so) CAMEL_SEEKABLE_SUBSTREAM_CLASS (CAMEL_OBJECT(so)->klass)
34
35 static  ssize_t  stream_read  (CamelStream *stream, char *buffer, size_t n);
36 static  ssize_t  stream_write (CamelStream *stream, const char *buffer, size_t n);
37 static  int      stream_flush (CamelStream *stream);
38 static  int      stream_close (CamelStream *stream);
39 static  gboolean eos          (CamelStream *stream);
40 static  off_t    stream_seek  (CamelSeekableStream *stream, off_t offset,
41                                CamelStreamSeekPolicy policy);
42
43 static void
44 camel_seekable_substream_class_init (CamelSeekableSubstreamClass *camel_seekable_substream_class)
45 {
46         CamelSeekableStreamClass *camel_seekable_stream_class =
47                 CAMEL_SEEKABLE_STREAM_CLASS (camel_seekable_substream_class);
48         CamelStreamClass *camel_stream_class =
49                 CAMEL_STREAM_CLASS (camel_seekable_substream_class);
50
51         parent_class = CAMEL_SEEKABLE_STREAM_CLASS (camel_type_get_global_classfuncs (camel_seekable_stream_get_type ()));
52
53         /* virtual method definition */
54
55         /* virtual method overload */
56         camel_stream_class->read = stream_read;
57         camel_stream_class->write = stream_write;
58         camel_stream_class->flush = stream_flush;
59         camel_stream_class->close = stream_close;
60         camel_stream_class->eos = eos;
61
62         camel_seekable_stream_class->seek = stream_seek;
63
64 }
65
66 static void
67 camel_seekable_substream_finalize (CamelObject *object)
68 {
69         CamelSeekableSubstream *seekable_substream =
70                 CAMEL_SEEKABLE_SUBSTREAM (object);
71
72         if (seekable_substream->parent_stream)
73                 camel_object_unref (seekable_substream->parent_stream);
74 }
75
76
77 CamelType
78 camel_seekable_substream_get_type (void)
79 {
80         static CamelType camel_seekable_substream_type = CAMEL_INVALID_TYPE;
81
82         if (camel_seekable_substream_type == CAMEL_INVALID_TYPE) {
83                 camel_seekable_substream_type = camel_type_register (camel_seekable_stream_get_type (), "CamelSeekableSubstream",
84                                                                      sizeof (CamelSeekableSubstream),
85                                                                      sizeof (CamelSeekableSubstreamClass),
86                                                                      (CamelObjectClassInitFunc) camel_seekable_substream_class_init,
87                                                                      NULL,
88                                                                      NULL,
89                                                                      (CamelObjectFinalizeFunc) camel_seekable_substream_finalize);
90         }
91
92         return camel_seekable_substream_type;
93 }
94
95 /**
96  * camel_seekable_substream_new:
97  * @parent_stream: a seekable parent stream
98  * @inf_bound: a lower bound
99  * @sup_bound: an upper bound
100  *
101  * Creates a new CamelSeekableSubstream that references the portion
102  * of @parent_stream from @inf_bound to @sup_bound. (If @sup_bound is
103  * #CAMEL_STREAM_UNBOUND, it references to the end of stream, even if
104  * the stream grows.)
105  *
106  * While the substream is open, the caller cannot assume anything about
107  * the current position of @parent_stream. After the substream has been
108  * closed, @parent_stream will stabilize again.
109  *
110  * Return value: the substream
111  **/
112 CamelStream *
113 camel_seekable_substream_new(CamelSeekableStream *parent_stream, off_t start, off_t end)
114 {
115         CamelSeekableSubstream *seekable_substream;
116
117         g_return_val_if_fail (CAMEL_IS_SEEKABLE_STREAM (parent_stream), NULL);
118
119         /* Create the seekable substream. */
120         seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (camel_object_new (camel_seekable_substream_get_type ()));
121
122         /* Initialize it. */
123         seekable_substream->parent_stream = parent_stream;
124         camel_object_ref (parent_stream);
125
126         /* Set the bound of the substream. We can ignore any possible error
127          * here, because if we fail to seek now, it will try again later.
128          */
129         camel_seekable_stream_set_bounds ((CamelSeekableStream *)seekable_substream, start, end);
130
131         return CAMEL_STREAM (seekable_substream);
132 }
133
134 static gboolean
135 parent_reset (CamelSeekableSubstream *seekable_substream, CamelSeekableStream *parent)
136 {
137         CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (seekable_substream);
138
139         if (camel_seekable_stream_tell (parent) == seekable_stream->position)
140                 return TRUE;
141
142         return camel_seekable_stream_seek (parent, seekable_stream->position, CAMEL_STREAM_SET) == seekable_stream->position;
143 }
144
145 static ssize_t
146 stream_read (CamelStream *stream, char *buffer, size_t n)
147 {
148         CamelSeekableStream *parent;
149         CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream);
150         CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream);
151         ssize_t v;
152
153         if (n == 0)
154                 return 0;
155
156         parent = seekable_substream->parent_stream;
157
158         /* Go to our position in the parent stream. */
159         if (!parent_reset (seekable_substream, parent)) {
160                 stream->eos = TRUE;
161                 return 0;
162         }
163
164         /* Compute how many bytes should be read. */
165         if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
166                 n = MIN (seekable_stream->bound_end -  seekable_stream->position, n);
167
168         if (n == 0) {
169                 stream->eos = TRUE;
170                 return 0;
171         }
172
173         v = camel_stream_read (CAMEL_STREAM (parent), buffer, n);
174
175         /* ignore <0 - it's an error, let the caller deal */
176         if (v > 0)
177                 seekable_stream->position += v;
178
179         return v;
180 }
181
182 static ssize_t
183 stream_write (CamelStream *stream, const char *buffer, size_t n)
184 {
185         CamelSeekableStream *parent;
186         CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM(stream);
187         CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(stream);
188         ssize_t v;
189
190         if (n == 0)
191                 return 0;
192
193         parent = seekable_substream->parent_stream;
194
195         /* Go to our position in the parent stream. */
196         if (!parent_reset (seekable_substream, parent)) {
197                 stream->eos = TRUE;
198                 return 0;
199         }
200
201         /* Compute how many bytes should be written. */
202         if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
203                 n = MIN (seekable_stream->bound_end -  seekable_stream->position, n);
204
205         if (n == 0) {
206                 stream->eos = TRUE;
207                 return 0;
208         }
209
210         v = camel_stream_write((CamelStream *)parent, buffer, n);
211
212         /* ignore <0 - it's an error, let the caller deal */
213         if (v > 0)
214                 seekable_stream->position += v;
215
216         return v;
217
218 }
219
220 static int
221 stream_flush (CamelStream *stream)
222 {
223         CamelSeekableSubstream *sus = (CamelSeekableSubstream *)stream;
224
225         return camel_stream_flush(CAMEL_STREAM(sus->parent_stream));
226 }
227
228 static int
229 stream_close (CamelStream *stream)
230 {
231         /* we dont really want to close the substream ... */
232         return 0;
233 }
234
235 static gboolean
236 eos (CamelStream *stream)
237 {
238         CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(stream);
239         CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM(stream);
240         CamelSeekableStream *parent;
241         gboolean eos;
242
243         if (stream->eos)
244                 eos = TRUE;
245         else {
246                 parent = seekable_substream->parent_stream;
247                 if (!parent_reset (seekable_substream, parent))
248                         return TRUE;
249
250                 eos = camel_stream_eos (CAMEL_STREAM (parent));
251                 if (!eos && (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)) {
252                         eos = seekable_stream->position >= seekable_stream->bound_end;
253                 }
254         }
255
256         return eos;
257 }
258
259 static off_t
260 stream_seek (CamelSeekableStream *seekable_stream, off_t offset,
261              CamelStreamSeekPolicy policy)
262 {
263         CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(seekable_stream);
264         CamelStream *stream = CAMEL_STREAM(seekable_stream);
265         off_t real_offset = 0;
266
267         stream->eos = FALSE;
268
269         switch (policy) {
270         case CAMEL_STREAM_SET:
271                 real_offset = offset;
272                 break;
273
274         case CAMEL_STREAM_CUR:
275                 real_offset = seekable_stream->position + offset;
276                 break;
277
278         case CAMEL_STREAM_END:
279                 if (seekable_stream->bound_end == CAMEL_STREAM_UNBOUND) {
280                         real_offset = camel_seekable_stream_seek(seekable_substream->parent_stream,
281                                                                  offset,
282                                                                  CAMEL_STREAM_END);
283                         if (real_offset != -1) {
284                                 if (real_offset<seekable_stream->bound_start)
285                                         real_offset = seekable_stream->bound_start;
286                                 seekable_stream->position = real_offset;
287                         }
288                         return real_offset;
289                 }
290                 real_offset = seekable_stream->bound_end + offset;
291                 break;
292         }
293
294         if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
295                 real_offset = MIN (real_offset, seekable_stream->bound_end);
296
297         if (real_offset<seekable_stream->bound_start)
298                 real_offset = seekable_stream->bound_start;
299
300         seekable_stream->position = real_offset;
301         return real_offset;
302 }