1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
3 * Copyright (C) 2000 Ximian Inc.
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
30 #include "camel-stream-filter.h"
34 /* use my malloc debugger? */
35 /*extern void g_check(void *mp);*/
41 CamelMimeFilter *filter;
44 struct _CamelStreamFilterPrivate {
45 struct _filter *filters;
46 int filterid; /* next filter id */
48 char *realbuffer; /* buffer - READ_PAD */
49 char *buffer; /* READ_SIZE bytes */
51 char *filtered; /* the filtered data */
54 guint last_was_read:1; /* was the last op read or write? */
55 guint flushed:1; /* were the filters flushed? */
58 #define READ_PAD (128) /* bytes padded before buffer */
59 #define READ_SIZE (4096)
61 #define _PRIVATE(o) (((CamelStreamFilter *)(o))->priv)
63 static void camel_stream_filter_class_init (CamelStreamFilterClass *klass);
64 static void camel_stream_filter_init (CamelStreamFilter *obj);
66 static ssize_t do_read (CamelStream *stream, char *buffer, size_t n);
67 static ssize_t do_write (CamelStream *stream, const char *buffer, size_t n);
68 static int do_flush (CamelStream *stream);
69 static int do_close (CamelStream *stream);
70 static gboolean do_eos (CamelStream *stream);
71 static int do_reset (CamelStream *stream);
73 static CamelStreamClass *camel_stream_filter_parent;
76 camel_stream_filter_class_init (CamelStreamFilterClass *klass)
78 CamelStreamClass *camel_stream_class = (CamelStreamClass *) klass;
80 camel_stream_filter_parent = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (camel_stream_get_type ()));
82 camel_stream_class->read = do_read;
83 camel_stream_class->write = do_write;
84 camel_stream_class->flush = do_flush;
85 camel_stream_class->close = do_close;
86 camel_stream_class->eos = do_eos;
87 camel_stream_class->reset = do_reset;
92 camel_stream_filter_init (CamelStreamFilter *obj)
94 struct _CamelStreamFilterPrivate *p;
96 _PRIVATE(obj) = p = g_malloc0(sizeof(*p));
97 p->realbuffer = g_malloc(READ_SIZE + READ_PAD);
98 p->buffer = p->realbuffer + READ_PAD;
99 p->last_was_read = TRUE;
104 camel_stream_filter_finalize(CamelObject *o)
106 CamelStreamFilter *filter = (CamelStreamFilter *)o;
107 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
108 struct _filter *fn, *f;
113 camel_object_unref((CamelObject *)f->filter);
117 g_free(p->realbuffer);
119 camel_object_unref((CamelObject *)filter->source);
123 camel_stream_filter_get_type (void)
125 static CamelType type = CAMEL_INVALID_TYPE;
127 if (type == CAMEL_INVALID_TYPE) {
128 type = camel_type_register (CAMEL_STREAM_TYPE, "CamelStreamFilter",
129 sizeof (CamelStreamFilter),
130 sizeof (CamelStreamFilterClass),
131 (CamelObjectClassInitFunc) camel_stream_filter_class_init,
133 (CamelObjectInitFunc) camel_stream_filter_init,
134 (CamelObjectFinalizeFunc) camel_stream_filter_finalize);
141 * camel_stream_filter_new:
143 * Create a new #CamelStreamFilter object.
145 * Returns a new #CamelStreamFilter object.
148 camel_stream_filter_new_with_stream(CamelStream *stream)
150 CamelStreamFilter *new = CAMEL_STREAM_FILTER ( camel_object_new (camel_stream_filter_get_type ()));
152 new->source = stream;
153 camel_object_ref ((CamelObject *)stream);
159 * camel_stream_filter_add:
160 * @stream: a #CamelStreamFilter object
161 * @filter: a #CamelMimeFilter object
163 * Add a new #CamelMimeFilter to execute during the processing of this
164 * stream. Each filter added is processed after the previous one.
166 * Note that a filter should only be added to a single stream
167 * at a time, otherwise unpredictable results may occur.
169 * Returns a filter id for the added @filter.
172 camel_stream_filter_add (CamelStreamFilter *stream, CamelMimeFilter *filter)
174 struct _CamelStreamFilterPrivate *p = _PRIVATE(stream);
175 struct _filter *fn, *f;
177 fn = g_malloc(sizeof(*fn));
178 fn->id = p->filterid++;
180 camel_object_ref (filter);
182 /* sure, we could use a GList, but we wouldn't save much */
183 f = (struct _filter *)&p->filters;
192 * camel_stream_filter_remove:
193 * @stream: a #CamelStreamFilter object
194 * @id: Filter id, as returned from #camel_stream_filter_add
196 * Remove a processing filter from the stream by id.
199 camel_stream_filter_remove(CamelStreamFilter *stream, int id)
201 struct _CamelStreamFilterPrivate *p = _PRIVATE(stream);
202 struct _filter *fn, *f;
204 f = (struct _filter *)&p->filters;
205 while (f && f->next) {
209 camel_object_unref(fn->filter);
217 do_read (CamelStream *stream, char *buffer, size_t n)
219 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
220 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
224 p->last_was_read = TRUE;
226 g_check(p->realbuffer);
228 if (p->filteredlen<=0) {
229 size_t presize = READ_PAD;
231 size = camel_stream_read(filter->source, p->buffer, READ_SIZE);
233 /* this is somewhat untested */
234 if (camel_stream_eos(filter->source)) {
236 p->filtered = p->buffer;
239 camel_mime_filter_complete(f->filter, p->filtered, p->filteredlen,
240 presize, &p->filtered, &p->filteredlen, &presize);
241 g_check(p->realbuffer);
244 size = p->filteredlen;
251 p->filtered = p->buffer;
252 p->filteredlen = size;
254 d(printf ("\n\nOriginal content (%s): '", ((CamelObject *)filter->source)->klass->name));
255 d(fwrite(p->filtered, sizeof(char), p->filteredlen, stdout));
259 camel_mime_filter_filter(f->filter, p->filtered, p->filteredlen, presize,
260 &p->filtered, &p->filteredlen, &presize);
261 g_check(p->realbuffer);
263 d(printf ("Filtered content (%s): '", ((CamelObject *)f->filter)->klass->name));
264 d(fwrite(p->filtered, sizeof(char), p->filteredlen, stdout));
272 size = MIN(n, p->filteredlen);
273 memcpy(buffer, p->filtered, size);
274 p->filteredlen -= size;
277 g_check(p->realbuffer);
282 /* Note: Since the caller expects to write out as much as they asked us to
283 write (for 'success'), we return what they asked us to write (for 'success')
284 rather than the true number of written bytes */
286 do_write (CamelStream *stream, const char *buf, size_t n)
288 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
289 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
291 size_t presize, len, left = n;
292 char *buffer, realbuffer[READ_SIZE+READ_PAD];
294 p->last_was_read = FALSE;
296 d(printf ("\n\nWriting: Original content (%s): '", ((CamelObject *)filter->source)->klass->name));
297 d(fwrite(buf, sizeof(char), n, stdout));
300 g_check(p->realbuffer);
303 /* Sigh, since filters expect non const args, copy the input first, we do this in handy sized chunks */
304 len = MIN(READ_SIZE, left);
305 buffer = realbuffer + READ_PAD;
306 memcpy(buffer, buf, len);
313 camel_mime_filter_filter(f->filter, buffer, len, presize, &buffer, &len, &presize);
315 g_check(p->realbuffer);
317 d(printf ("Filtered content (%s): '", ((CamelObject *)f->filter)->klass->name));
318 d(fwrite(buffer, sizeof(char), len, stdout));
324 if (camel_stream_write(filter->source, buffer, len) != len)
328 g_check(p->realbuffer);
334 do_flush (CamelStream *stream)
336 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
337 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
343 if (p->last_was_read)
351 d(printf ("\n\nFlushing: Original content (%s): '", ((CamelObject *)filter->source)->klass->name));
352 d(fwrite(buffer, sizeof(char), len, stdout));
356 camel_mime_filter_complete(f->filter, buffer, len, presize, &buffer, &len, &presize);
358 d(printf ("Filtered content (%s): '", ((CamelObject *)f->filter)->klass->name));
359 d(fwrite(buffer, sizeof(char), len, stdout));
364 if (len > 0 && camel_stream_write(filter->source, buffer, len) == -1)
366 return camel_stream_flush(filter->source);
370 do_close (CamelStream *stream)
372 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
373 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
375 if (!p->last_was_read) {
378 return camel_stream_close(filter->source);
382 do_eos (CamelStream *stream)
384 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
385 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
387 if (p->filteredlen > 0)
393 return camel_stream_eos(filter->source);
397 do_reset (CamelStream *stream)
399 CamelStreamFilter *filter = (CamelStreamFilter *)stream;
400 struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
406 /* and reset filters */
409 camel_mime_filter_reset(f->filter);
413 return camel_stream_reset(filter->source);