diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2001-09-19 08:03:57 +0000 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2001-09-19 08:03:57 +0000 |
commit | 98e7fa7bd7d827e6d49439924e49e91bbfb87b5e (patch) | |
tree | 7653cf1d65cb0d57329a4e3866a073f4f39e636a | |
parent | a6e2e02c93f92b202e7b9cd68c4815889bef39df (diff) | |
download | gmime-98e7fa7bd7d827e6d49439924e49e91bbfb87b5e.tar.gz |
Copy over the filters.
2001-09-19 Jeffrey Stedfast <fejj@ximian.com>
* gmime-stream-filter.c (stream_substream): Copy over the filters.
* gmime-part.c (g_mime_part_verify_content_md5): Updated.
(g_mime_part_set_content_md5): Updated.
(g_mime_part_get_content): Updated.
(write_content): Updated.
* gmime-data-wrapper.c (g_mime_data_wrapper_write_to_stream):
Implemented.
* gmime-filter-basic.[c,h]: A basic filter that does Base64 and QP
encoding/decoding.
* gmime-filter-crlf.[c,h]: A simple filter that does crlf(/dot)
encoding/decoding.
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | gmime-data-wrapper.c | 31 | ||||
-rw-r--r-- | gmime-filter-basic.c | 180 | ||||
-rw-r--r-- | gmime-filter-basic.h | 56 | ||||
-rw-r--r-- | gmime-filter-crlf.c | 175 | ||||
-rw-r--r-- | gmime-filter-crlf.h | 60 | ||||
-rw-r--r-- | gmime-filter.c | 6 | ||||
-rw-r--r-- | gmime-filter.h | 2 | ||||
-rw-r--r-- | gmime-part.c | 93 | ||||
-rw-r--r-- | gmime-stream-filter.c | 88 | ||||
-rw-r--r-- | gmime-stream-filter.h | 2 | ||||
-rw-r--r-- | gmime/gmime-data-wrapper.c | 31 | ||||
-rw-r--r-- | gmime/gmime-filter-basic.c | 180 | ||||
-rw-r--r-- | gmime/gmime-filter-basic.h | 56 | ||||
-rw-r--r-- | gmime/gmime-filter-crlf.c | 175 | ||||
-rw-r--r-- | gmime/gmime-filter-crlf.h | 60 | ||||
-rw-r--r-- | gmime/gmime-filter.c | 6 | ||||
-rw-r--r-- | gmime/gmime-filter.h | 2 | ||||
-rw-r--r-- | gmime/gmime-part.c | 93 | ||||
-rw-r--r-- | gmime/gmime-stream-filter.c | 88 | ||||
-rw-r--r-- | gmime/gmime-stream-filter.h | 2 |
22 files changed, 1224 insertions, 188 deletions
@@ -1,5 +1,23 @@ 2001-09-19 Jeffrey Stedfast <fejj@ximian.com> + * gmime-stream-filter.c (stream_substream): Copy over the filters. + + * gmime-part.c (g_mime_part_verify_content_md5): Updated. + (g_mime_part_set_content_md5): Updated. + (g_mime_part_get_content): Updated. + (write_content): Updated. + + * gmime-data-wrapper.c (g_mime_data_wrapper_write_to_stream): + Implemented. + + * gmime-filter-basic.[c,h]: A basic filter that does Base64 and QP + encoding/decoding. + + * gmime-filter-crlf.[c,h]: A simple filter that does crlf(/dot) + encoding/decoding. + +2001-09-19 Jeffrey Stedfast <fejj@ximian.com> + * gmime-data-wrapper.c (g_mime_data_wrapper_new_with_stream): Ref the stream. (g_mime_data_wrapper_set_stream): Same. diff --git a/Makefile.am b/Makefile.am index aa7176fd..b42f4398 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,9 @@ libgmime_la_SOURCES = \ gmime-charset.c \ gmime-content-type.c \ gmime-data-wrapper.c \ + gmime-filter.c \ + gmime-filter-basic.c \ + gmime-filter-crlf.c \ gmime-header.c \ gmime-message.c \ gmime-param.c \ @@ -26,6 +29,7 @@ libgmime_la_SOURCES = \ gmime-part.c \ gmime-stream.c \ gmime-stream-file.c \ + gmime-stream-filter.c \ gmime-stream-fs.c \ gmime-stream-mem.c \ gmime-utils.c \ @@ -39,6 +43,9 @@ gmimeinc_HEADERS = \ gmime-charset.h \ gmime-content-type.h \ gmime-data-wrapper.h \ + gmime-filter.h \ + gmime-filter-basic.h \ + gmime-filter-crlf.h \ gmime-header.h \ gmime-message.h \ gmime-param.h \ @@ -46,6 +53,7 @@ gmimeinc_HEADERS = \ gmime-part.h \ gmime-stream.h \ gmime-stream-file.h \ + gmime-stream-filter.c \ gmime-stream-fs.h \ gmime-stream-mem.h \ gmime-utils.h \ diff --git a/gmime-data-wrapper.c b/gmime-data-wrapper.c index 50abe035..61cc0d76 100644 --- a/gmime-data-wrapper.c +++ b/gmime-data-wrapper.c @@ -22,7 +22,8 @@ #include "gmime-data-wrapper.h" - +#include "gmime-stream-filter.h" +#include "gmime-filter-basic.h" /** * g_mime_data_wrapper_new: @@ -163,5 +164,31 @@ g_mime_data_wrapper_get_encoding (GMimeDataWrapper *wrapper) ssize_t g_mime_data_wrapper_write_to_stream (GMimeDataWrapper *wrapper, GMimeStream *stream) { - return -1; + GMimeStream *filtered_stream; + GMimeFilter *filter; + ssize_t written; + + g_return_val_if_fail (wrapper != NULL, -1); + g_return_val_if_fail (wrapper->stream != NULL, -1); + + filtered_stream = g_mime_stream_filter_new_with_stream (wrapper->stream); + switch (wrapper->encoding) { + case GMIME_PART_ENCODING_BASE64: + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_BASE64_DEC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); + break; + case GMIME_PART_ENCODING_QUOTEDPRINTABLE: + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_QP_DEC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); + break; + default: + break; + } + + written = g_mime_stream_write_to_stream (filtered_stream, stream); + g_mime_stream_unref (filtered_stream); + + g_mime_stream_reset (wrapper->stream); + + return written; } diff --git a/gmime-filter-basic.c b/gmime-filter-basic.c new file mode 100644 index 00000000..7bbde34c --- /dev/null +++ b/gmime-filter-basic.c @@ -0,0 +1,180 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#include "gmime-filter-basic.h" +#include "gmime-utils.h" + +static void filter_destroy (GMimeFilter *filter); +static GMimeFilter *filter_copy (GMimeFilter *filter); +static void filter_filter (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_complete (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_reset (GMimeFilter *filter); + +static GMimeFilter template = { + NULL, NULL, NULL, NULL, + 0, 0, NULL, 0, 0, + filter_destroy, + filter_copy, + filter_filter, + filter_complete, + filter_reset, +}; + + +/** + * g_mime_filter_basic_new_type: + * @type: + * + * Returns a new basic filter of type @type. + **/ +GMimeFilter * +g_mime_filter_basic_new_type (GMimeFilterBasicType type) +{ + GMimeFilterBasic *new; + + new = g_new (GMimeFilterBasic, 1); + + new->type = type; + new->state = 0; + new->save = 0; + + g_mime_filter_construct (GMIME_FILTER (new), &template); + + filter_reset (GMIME_FILTER (new)); + + return GMIME_FILTER (new); +} + + +static void +filter_destroy (GMimeFilter *filter) +{ + g_free (filter); +} + +static GMimeFilter * +filter_copy (GMimeFilter *filter) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + + return g_mime_filter_basic_new_type (basic->type); +} + +/* here we do all of the basic mime filtering */ +static void +filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + int newlen; + + switch (basic->type) { + case GMIME_FILTER_BASIC_BASE64_ENC: + /* wont go to more than 2x size (overly conservative) */ + g_mime_filter_set_size (filter, len * 2 + 6, FALSE); + newlen = g_mime_utils_base64_encode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 2 + 6); + break; + case GMIME_FILTER_BASIC_QP_ENC: + /* *4 is overly conservative, but will do */ + g_mime_filter_set_size (filter, len * 4 + 4, FALSE); + newlen = g_mime_utils_quoted_encode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 4 + 4); + break; + case GMIME_FILTER_BASIC_BASE64_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len + 3, FALSE); + newlen = g_mime_utils_base64_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len + 3); + break; + case GMIME_FILTER_BASIC_QP_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_quoted_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + } + + *out = filter->outbuf; + *outlen = newlen; + *outprespace = filter->outpre; +} + +static void +filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + int newlen; + + switch (basic->type) { + case GMIME_FILTER_BASIC_BASE64_ENC: + /* wont go to more than 2x size (overly conservative) */ + g_mime_filter_set_size (filter, len*2+6, FALSE); + newlen = g_mime_utils_base64_encode_close (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 2 + 6); + break; + case GMIME_FILTER_BASIC_QP_ENC: + /* *4 is definetly more than needed ... */ + g_mime_filter_set_size (filter, len * 4 + 4, FALSE); + newlen = g_mime_utils_quoted_encode_close (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 4 + 4); + break; + case GMIME_FILTER_BASIC_BASE64_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_base64_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + case GMIME_FILTER_BASIC_QP_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_quoted_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + } + + *out = filter->outbuf; + *outlen = newlen; + *outprespace = filter->outpre; +} + +/* should this 'flush' outstanding state/data bytes? */ +static void +filter_reset (GMimeFilter *filter) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + + switch (basic->type) { + case GMIME_FILTER_BASIC_QP_ENC: + basic->state = -1; + break; + default: + basic->state = 0; + } + basic->save = 0; +} diff --git a/gmime-filter-basic.h b/gmime-filter-basic.h new file mode 100644 index 00000000..f220fd18 --- /dev/null +++ b/gmime-filter-basic.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __G_MIME_FILTER_BASIC_H__ +#define __G_MIME_FILTER_BASIC_H__ + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include "gmime-filter.h" + +typedef enum { + GMIME_FILTER_BASIC_BASE64_ENC = 1, + GMIME_FILTER_BASIC_BASE64_DEC, + GMIME_FILTER_BASIC_QP_ENC, + GMIME_FILTER_BASIC_QP_DEC, +} GMimeFilterBasicType; + +typedef struct _GMimeFilterBasic { + GMimeFilter parent; + + GMimeFilterBasicType type; + + int state; + int save; +} GMimeFilterBasic; + +GMimeFilter *g_mime_filter_basic_new_type (GMimeFilterBasicType type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GMIME_FILTER_BASIC_H__ */ diff --git a/gmime-filter-crlf.c b/gmime-filter-crlf.c new file mode 100644 index 00000000..5954ad3d --- /dev/null +++ b/gmime-filter-crlf.c @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#include "gmime-filter-crlf.h" + +static void filter_destroy (GMimeFilter *filter); +static GMimeFilter *filter_copy (GMimeFilter *filter); +static void filter_filter (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_complete (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_reset (GMimeFilter *filter); + +static GMimeFilter template = { + NULL, NULL, NULL, NULL, + 0, 0, NULL, 0, 0, + filter_destroy, + filter_copy, + filter_filter, + filter_complete, + filter_reset, +}; + + +/** + * g_mime_filter_crlf_new_type: + * @direction: + * @mode: + * + * Returns a new crlf(/dot) filter. + **/ +GMimeFilter * +g_mime_filter_crlf_new (GMimeFilterCRLFDirection direction, GMimeFilterCRLFMode mode) +{ + GMimeFilterCRLF *new; + + new = g_new (GMimeFilterCRLF, 1); + + new->direction = direction; + new->mode = mode; + new->saw_cr = FALSE; + new->saw_lf = FALSE; + new->saw_dot = FALSE; + + g_mime_filter_construct (GMIME_FILTER (new), &template); + + return GMIME_FILTER (new); +} + + +static void +filter_destroy (GMimeFilter *filter) +{ + g_free (filter); +} + +static GMimeFilter * +filter_copy (GMimeFilter *filter) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + + return g_mime_filter_crlf_new (crlf->direction, crlf->mode); +} + +static void +filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + gboolean do_dots; + char *p, *q; + + do_dots = crlf->mode == GMIME_FILTER_CRLF_MODE_CRLF_DOTS; + + if (crlf->direction == GMIME_FILTER_CRLF_ENCODE) { + g_mime_filter_set_size (filter, 3 * len, FALSE); + + p = in; + q = filter->outbuf; + while (p < in + len) { + if (*p == '\n') { + crlf->saw_lf = TRUE; + *q++ = '\r'; + } else { + if (do_dots && *p == '.' && crlf->saw_lf) + *q++ = '.'; + + crlf->saw_lf = FALSE; + } + + *q++ = *p++; + } + } else { + g_mime_filter_set_size (filter, len, FALSE); + + p = in; + q = filter->outbuf; + while (p < in + len) { + if (*p == '\r') { + crlf->saw_cr = TRUE; + } else { + if (crlf->saw_cr) { + crlf->saw_cr = FALSE; + + if (*p == '\n') { + crlf->saw_lf = TRUE; + *q++ = *p++; + continue; + } else + *q++ = '\r'; + } + + *q++ = *p; + } + + if (do_dots && *p == '.') { + if (crlf->saw_lf) { + crlf->saw_dot = TRUE; + crlf->saw_lf = FALSE; + p++; + } else if (crlf->saw_dot) { + crlf->saw_dot = FALSE; + } + } + + crlf->saw_lf = FALSE; + + p++; + } + } + + *out = filter->outbuf; + *outlen = q - filter->outbuf; + *outprespace = filter->outpre; +} + +static void +filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + if (in && len) + filter_filter (filter, in, len, prespace, out, outlen, outprespace); +} + +static void +filter_reset (GMimeFilter *filter) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + + crlf->saw_cr = FALSE; + crlf->saw_lf = TRUE; + crlf->saw_dot = FALSE; +} diff --git a/gmime-filter-crlf.h b/gmime-filter-crlf.h new file mode 100644 index 00000000..52bcb5cc --- /dev/null +++ b/gmime-filter-crlf.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __G_MIME_FILTER_CRLF_H__ +#define __G_MIME_FILTER_CRLF_H__ + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include "gmime-filter.h" + +typedef enum { + GMIME_FILTER_CRLF_ENCODE, + GMIME_FILTER_CRLF_DECODE +} GMimeFilterCRLFDirection; + +typedef enum { + GMIME_FILTER_CRLF_MODE_CRLF_DOTS, + GMIME_FILTER_CRLF_MODE_CRLF_ONLY, +} GMimeFilterCRLFMode; + +typedef struct _GMimeFilterCRLF { + GMimeFilter parent; + + GMimeFilterCRLFDirection direction; + GMimeFilterCRLFMode mode; + gboolean saw_cr; + gboolean saw_lf; + gboolean saw_dot; +} GMimeFilterCRLF; + +GMimeFilter *g_mime_filter_crlf_new_type (GMimeFilterCRLFDirection direction, GMimeFilterCRLFMode mode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GMIME_FILTER_CRLF_H__ */ diff --git a/gmime-filter.c b/gmime-filter.c index 00709db3..aaf9fa2f 100644 --- a/gmime-filter.c +++ b/gmime-filter.c @@ -192,10 +192,10 @@ g_mime_filter_reset (GMimeFilter *filter) { g_return_if_fail (filter != NULL); - filter->reset (f); + filter->reset (filter); /* could free some buffers, if they are really big? */ - f->backlen = 0; + filter->backlen = 0; } @@ -255,6 +255,6 @@ g_mime_filter_set_size (GMimeFilter *filter, size_t size, gboolean keep) /* this could be offset from the end of the structure, but this should be good enough */ - f->outpre = PRE_HEAD * 4; + filter->outpre = PRE_HEAD * 4; } } diff --git a/gmime-filter.h b/gmime-filter.h index 09bd145b..2d55922f 100644 --- a/gmime-filter.h +++ b/gmime-filter.h @@ -30,6 +30,7 @@ extern "C" { #endif /* __cplusplus */ #include <glib.h> +#include <sys/types.h> typedef struct _GMimeFilter GMimeFilter; @@ -62,6 +63,7 @@ struct _GMimeFilter { void (*reset) (GMimeFilter *filter); }; +#define GMIME_FILTER(filter) ((GMimeFilter *) filter) void g_mime_filter_construct (GMimeFilter *filter, GMimeFilter *template); diff --git a/gmime-part.c b/gmime-part.c index 6b1b3dd3..c1dd7f13 100644 --- a/gmime-part.c +++ b/gmime-part.c @@ -31,12 +31,18 @@ #include <unistd.h> #include <string.h> #include <ctype.h> + #include "gmime-part.h" #include "gmime-utils.h" #include "gmime-stream-mem.h" +#include "gmime-stream-filter.h" +#include "gmime-filter-basic.h" #include "md5-utils.h" +#define NEEDS_DECODING(encoding) (((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_BASE64 || \ + ((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_QUOTEDPRINTABLE) + /** * g_mime_part_new: Create a new MIME Part object * @@ -235,19 +241,19 @@ g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5) if (content_md5) { mime_part->content_md5 = g_strdup (content_md5); - } else if (mime_part->content) { + } else if (mime_part->content->stream) { char digest[16], b64digest[32]; int len, state, save; GMimeStream *stream; GByteArray *buf; - if (GMIME_IS_STREAM_MEM (mime_part->content->stream)) { - stream = mime_part->content->stream; - g_mime_stream_ref (mime_part->content->stream); - } else { + stream = mime_part->content->stream; + if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { stream = g_mime_stream_mem_new (); - g_mime_stream_write_to_stream (mime_part->content->stream, stream); - g_mime_stream_reset (mime_part->content->stream); + g_mime_data_wrapper_write_to_stream (mime_part->content, stream); + } else { + stream = mime_part->content->stream; + g_mime_stream_ref (stream); } buf = GMIME_STREAM_MEM (stream)->buffer; @@ -285,15 +291,16 @@ g_mime_part_verify_content_md5 (GMimePart *mime_part) GByteArray *buf; g_return_val_if_fail (mime_part != NULL, FALSE); + g_return_val_if_fail (mime_part->content != NULL, FALSE); g_return_val_if_fail (mime_part->content_md5 != NULL, FALSE); - if (GMIME_IS_STREAM_MEM (mime_part->content)) { + stream = mime_part->content->stream; + if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { + stream = g_mime_stream_mem_new (); + g_mime_data_wrapper_write_to_stream (mime_part->content, stream); + } else { stream = mime_part->content->stream; g_mime_stream_ref (stream); - } else { - stream = g_mime_stream_mem_new (); - g_mime_stream_write_to_stream (mime_part->content->stream, GMIME_STREAM (stream)); - g_mime_stream_reset (mime_part->content->stream); } buf = GMIME_STREAM_MEM (stream)->buffer; @@ -844,9 +851,6 @@ g_mime_part_set_content_object (GMimePart *mime_part, GMimeDataWrapper *content) } -#define NEEDS_DECODING(encoding) (((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_BASE64 || \ - ((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_QUOTEDPRINTABLE) - /** * g_mime_part_get_content: * @mime_part: the GMimePart to be decoded. @@ -858,6 +862,7 @@ g_mime_part_set_content_object (GMimePart *mime_part, GMimeDataWrapper *content) const char * g_mime_part_get_content (const GMimePart *mime_part, guint *len) { + GMimeStream *stream; GByteArray *buf; g_return_val_if_fail (mime_part != NULL, NULL); @@ -869,34 +874,12 @@ g_mime_part_get_content (const GMimePart *mime_part, guint *len) if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { /* Decode and cache this mime part's contents... */ GMimeStream *cache; - int len, save = 0, state = 0; - char inbuf[4096], outbuf[4096]; - ssize_t nread; buf = g_byte_array_new (); - - while (!g_mime_stream_eos (stream)) { - nread = g_mime_stream_read (stream, inbuf, sizeof (inbuf)); - if (nread > 0) { - switch (mime_part->content->encoding) { - case GMIME_PART_ENCODING_BASE64: - len = g_mime_utils_base64_decode_step (inbuf, nread, outbuf, - &state, &save); - g_byte_array_append (buf, outbuf, len); - break; - case GMIME_PART_ENCODING_QUOTEDPRINTABLE: - len = g_mime_utils_quoted_decode_step (inbuf, nread, outbuf, - &state, &save); - g_byte_array_append (buf, outbuf, len); - break; - default: - g_byte_array_append (buf, inbuf, nread); - } - } - } - cache = g_mime_stream_mem_new_with_byte_array (buf); + g_mime_data_wrapper_write_to_stream (mime_part->content, cache); + g_mime_data_wrapper_set_stream (mime_part->content, cache); g_mime_data_wrapper_set_encoding (mime_part->content, GMIME_PART_ENCODING_DEFAULT); g_mime_stream_unref (cache); @@ -1022,38 +1005,32 @@ get_content_type (GMimeContentType *mime_type) static void write_content (GMimePart *part, GMimeStream *stream) { - const char *content; - int save = 0, state = 0; - char *outbuf; - int len; + GMimeStream *filtered_stream; + GMimeFilter *filter; + ssize_t written; if (!part->content || !part->content->stream) return; - content = g_mime_part_get_content (part, &len); - if (!content) - return; - + filtered_stream = g_mime_stream_filter_new_with_stream (stream); switch (part->encoding) { case GMIME_PART_ENCODING_BASE64: - outbuf = g_malloc (BASE64_ENCODE_LEN (len)); - len = g_mime_utils_base64_encode_close (content, len, outbuf, &state, &save); + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_BASE64_ENC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); break; case GMIME_PART_ENCODING_QUOTEDPRINTABLE: - state = -1; - outbuf = g_malloc (QP_ENCODE_LEN (len)); - len = g_mime_utils_quoted_encode_close (content, len, outbuf, &state, &save); + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_QP_ENC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); break; default: - outbuf = g_malloc (len); - memcpy (outbuf, content, len); + break; } - g_warning ("write_content(): writing outbuf...%.*s", 20, outbuf); - g_mime_stream_write (stream, outbuf, len); - g_warning ("write_content(): done."); + written = g_mime_data_wrapper_write_to_stream (part->content, filtered_stream); + g_mime_stream_unref (filtered_stream); - g_free (outbuf); + /* this is just so that I get a warning on fail... */ + g_return_if_fail (written != -1); } diff --git a/gmime-stream-filter.c b/gmime-stream-filter.c index 62bdf03e..9d4bf5f8 100644 --- a/gmime-stream-filter.c +++ b/gmime-stream-filter.c @@ -73,7 +73,7 @@ static void stream_destroy (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *fn, *f; f = p->filters; @@ -96,7 +96,7 @@ static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _CamelStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; ssize_t size; @@ -137,7 +137,7 @@ stream_read (GMimeStream *stream, char *buf, size_t len) } size = MIN (len, p->filteredlen); - memcpy (buffer, p->filtered, size); + memcpy (buf, p->filtered, size); p->filteredlen -= size; p->filtered += size; @@ -148,7 +148,7 @@ static ssize_t stream_write (GMimeStream *stream, char *buf, size_t len) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; char *buffer; int presize; @@ -162,12 +162,12 @@ stream_write (GMimeStream *stream, char *buf, size_t len) f = p->filters; presize = 0; while (f) { - g_mime_mime_filter_filter (f->filter, buffer, n, presize, &buffer, &n, &presize); + g_mime_filter_filter (f->filter, buffer, n, presize, &buffer, &n, &presize); f = f->next; } - if (gmime_stream_write (filter->source, buffer, n) != n) + if (g_mime_stream_write (filter->source, buffer, n) != n) return -1; /* return 'len' because that's what our caller expects */ @@ -178,7 +178,7 @@ static int stream_flush (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; int len, presize; char *buffer; @@ -209,7 +209,7 @@ static int stream_close (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; if (!p->last_was_read) { stream_flush (stream); @@ -222,7 +222,7 @@ static gboolean stream_eos (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; if (p->filteredlen > 0) return FALSE; @@ -234,7 +234,7 @@ static int stream_reset (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; p->filteredlen = 0; @@ -272,33 +272,56 @@ stream_length (GMimeStream *stream) static GMimeStream * stream_substream (GMimeStream *stream, off_t start, off_t end) { - GMimeStreamFilter *filter; - struct _filters *f, *fn; + GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; + GMimeStreamFilter *sub; + struct _filter *f, *fn; - filter = g_new (GMimeStreamFilter, 1); - filter->source = GMIME_STREAM_FILTER (stream)->source; - g_mime_stream_ref (filter->source); + sub = g_new (GMimeStreamFilter, 1); + sub->source = filter->source; + g_mime_stream_ref (sub->source); - filter->priv = g_new (struct _GMimeStreamFilterPrivate, 1); - filter->priv->filters = NULL; - filter->priv->filterid = 0; - filter->priv->realbuffer = g_malloc (READ_SIZE + READ_PAD); - filter->priv->buffer = filter->priv->realbuffer + READ_PAD; - filter->priv->last_was_read = TRUE; - filter->priv->filteredlen = 0; + sub->priv = g_new (struct _GMimeStreamFilterPrivate, 1); + sub->priv->filters = NULL; + sub->priv->filterid = 0; + sub->priv->realbuffer = g_malloc (READ_SIZE + READ_PAD); + sub->priv->buffer = sub->priv->realbuffer + READ_PAD; + sub->priv->last_was_read = TRUE; + sub->priv->filteredlen = 0; - /* FIXME: copy the filters... */ + if (filter->priv->filters) { + struct _filter *f, *sn, *s = NULL; + + f = filter->priv->filters; + while (f) { + sn = g_new (struct _filter, 1); + sn->filter = g_mime_filter_copy (f->filter); + sn->id = f->id; + + if (s) { + s->next = sn; + s = sn; + } else { + s = sub->priv->filters = sn; + } + + f = f->next; + } + + s->next = NULL; + + sub->priv->filterid = filter->priv->filterid; + } g_mime_stream_construct (GMIME_STREAM (filter), &template, GMIME_STREAM_FILTER_TYPE, - filter->source->bound_start, - filter->source->bound_end); + sub->source->bound_start, + sub->source->bound_end); - return GMIME_STREAM (filter); + return GMIME_STREAM (sub); } -GMimeStreamFilter * +GMimeStream * g_mime_stream_filter_new_with_stream (GMimeStream *stream) { GMimeStreamFilter *filter; @@ -329,11 +352,14 @@ g_mime_stream_filter_new_with_stream (GMimeStream *stream) int g_mime_stream_filter_add (GMimeStreamFilter *fstream, GMimeFilter *filter) { - struct _GMimeStreamFilterPrivate *p = _PRIVATE (fstream); + struct _GMimeStreamFilterPrivate *p; struct _filter *f, *fn; + g_return_val_if_fail (fstream != NULL, -1); g_return_val_if_fail (filter != NULL, -1); + p = fstream->priv; + fn = g_new (struct _filter, 1); fn->next = NULL; fn->filter = filter; @@ -353,10 +379,12 @@ g_mime_stream_filter_add (GMimeStreamFilter *fstream, GMimeFilter *filter) void g_mime_stream_filter_remove (GMimeStreamFilter *fstream, int id) { - struct _GMimeStreamFilterPrivate *p = _PRIVATE (fstream); + struct _GMimeStreamFilterPrivate *p; struct _filter *f, *fn; - g_return_val_if_fail (filter != NULL, -1); + g_return_if_fail (fstream != NULL); + + p = fstream->priv; if (id == -1) return; diff --git a/gmime-stream-filter.h b/gmime-stream-filter.h index c30f07f4..93da9931 100644 --- a/gmime-stream-filter.h +++ b/gmime-stream-filter.h @@ -42,7 +42,7 @@ typedef struct _GMimeStreamFilter { #define GMIME_STREAM_FILTER_TYPE g_str_hash ("GMimeStreamFilter") #define GMIME_IS_STREAM_FILTER(stream) (((GMimeStream *) stream)->type == GMIME_STREAM_FILTER_TYPE) -#define GMIME_STREAM_FILTER(stream) ((GMimeStreamMem *) stream) +#define GMIME_STREAM_FILTER(stream) ((GMimeStreamFilter *) stream) GMimeStream *g_mime_stream_filter_new_with_stream (GMimeStream *stream); diff --git a/gmime/gmime-data-wrapper.c b/gmime/gmime-data-wrapper.c index 50abe035..61cc0d76 100644 --- a/gmime/gmime-data-wrapper.c +++ b/gmime/gmime-data-wrapper.c @@ -22,7 +22,8 @@ #include "gmime-data-wrapper.h" - +#include "gmime-stream-filter.h" +#include "gmime-filter-basic.h" /** * g_mime_data_wrapper_new: @@ -163,5 +164,31 @@ g_mime_data_wrapper_get_encoding (GMimeDataWrapper *wrapper) ssize_t g_mime_data_wrapper_write_to_stream (GMimeDataWrapper *wrapper, GMimeStream *stream) { - return -1; + GMimeStream *filtered_stream; + GMimeFilter *filter; + ssize_t written; + + g_return_val_if_fail (wrapper != NULL, -1); + g_return_val_if_fail (wrapper->stream != NULL, -1); + + filtered_stream = g_mime_stream_filter_new_with_stream (wrapper->stream); + switch (wrapper->encoding) { + case GMIME_PART_ENCODING_BASE64: + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_BASE64_DEC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); + break; + case GMIME_PART_ENCODING_QUOTEDPRINTABLE: + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_QP_DEC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); + break; + default: + break; + } + + written = g_mime_stream_write_to_stream (filtered_stream, stream); + g_mime_stream_unref (filtered_stream); + + g_mime_stream_reset (wrapper->stream); + + return written; } diff --git a/gmime/gmime-filter-basic.c b/gmime/gmime-filter-basic.c new file mode 100644 index 00000000..7bbde34c --- /dev/null +++ b/gmime/gmime-filter-basic.c @@ -0,0 +1,180 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#include "gmime-filter-basic.h" +#include "gmime-utils.h" + +static void filter_destroy (GMimeFilter *filter); +static GMimeFilter *filter_copy (GMimeFilter *filter); +static void filter_filter (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_complete (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_reset (GMimeFilter *filter); + +static GMimeFilter template = { + NULL, NULL, NULL, NULL, + 0, 0, NULL, 0, 0, + filter_destroy, + filter_copy, + filter_filter, + filter_complete, + filter_reset, +}; + + +/** + * g_mime_filter_basic_new_type: + * @type: + * + * Returns a new basic filter of type @type. + **/ +GMimeFilter * +g_mime_filter_basic_new_type (GMimeFilterBasicType type) +{ + GMimeFilterBasic *new; + + new = g_new (GMimeFilterBasic, 1); + + new->type = type; + new->state = 0; + new->save = 0; + + g_mime_filter_construct (GMIME_FILTER (new), &template); + + filter_reset (GMIME_FILTER (new)); + + return GMIME_FILTER (new); +} + + +static void +filter_destroy (GMimeFilter *filter) +{ + g_free (filter); +} + +static GMimeFilter * +filter_copy (GMimeFilter *filter) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + + return g_mime_filter_basic_new_type (basic->type); +} + +/* here we do all of the basic mime filtering */ +static void +filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + int newlen; + + switch (basic->type) { + case GMIME_FILTER_BASIC_BASE64_ENC: + /* wont go to more than 2x size (overly conservative) */ + g_mime_filter_set_size (filter, len * 2 + 6, FALSE); + newlen = g_mime_utils_base64_encode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 2 + 6); + break; + case GMIME_FILTER_BASIC_QP_ENC: + /* *4 is overly conservative, but will do */ + g_mime_filter_set_size (filter, len * 4 + 4, FALSE); + newlen = g_mime_utils_quoted_encode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 4 + 4); + break; + case GMIME_FILTER_BASIC_BASE64_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len + 3, FALSE); + newlen = g_mime_utils_base64_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len + 3); + break; + case GMIME_FILTER_BASIC_QP_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_quoted_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + } + + *out = filter->outbuf; + *outlen = newlen; + *outprespace = filter->outpre; +} + +static void +filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + int newlen; + + switch (basic->type) { + case GMIME_FILTER_BASIC_BASE64_ENC: + /* wont go to more than 2x size (overly conservative) */ + g_mime_filter_set_size (filter, len*2+6, FALSE); + newlen = g_mime_utils_base64_encode_close (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 2 + 6); + break; + case GMIME_FILTER_BASIC_QP_ENC: + /* *4 is definetly more than needed ... */ + g_mime_filter_set_size (filter, len * 4 + 4, FALSE); + newlen = g_mime_utils_quoted_encode_close (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len * 4 + 4); + break; + case GMIME_FILTER_BASIC_BASE64_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_base64_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + case GMIME_FILTER_BASIC_QP_DEC: + /* output can't possibly exceed the input size */ + g_mime_filter_set_size (filter, len, FALSE); + newlen = g_mime_utils_quoted_decode_step (in, len, filter->outbuf, &basic->state, &basic->save); + g_assert (newlen <= len); + break; + } + + *out = filter->outbuf; + *outlen = newlen; + *outprespace = filter->outpre; +} + +/* should this 'flush' outstanding state/data bytes? */ +static void +filter_reset (GMimeFilter *filter) +{ + GMimeFilterBasic *basic = (GMimeFilterBasic *) filter; + + switch (basic->type) { + case GMIME_FILTER_BASIC_QP_ENC: + basic->state = -1; + break; + default: + basic->state = 0; + } + basic->save = 0; +} diff --git a/gmime/gmime-filter-basic.h b/gmime/gmime-filter-basic.h new file mode 100644 index 00000000..f220fd18 --- /dev/null +++ b/gmime/gmime-filter-basic.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __G_MIME_FILTER_BASIC_H__ +#define __G_MIME_FILTER_BASIC_H__ + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include "gmime-filter.h" + +typedef enum { + GMIME_FILTER_BASIC_BASE64_ENC = 1, + GMIME_FILTER_BASIC_BASE64_DEC, + GMIME_FILTER_BASIC_QP_ENC, + GMIME_FILTER_BASIC_QP_DEC, +} GMimeFilterBasicType; + +typedef struct _GMimeFilterBasic { + GMimeFilter parent; + + GMimeFilterBasicType type; + + int state; + int save; +} GMimeFilterBasic; + +GMimeFilter *g_mime_filter_basic_new_type (GMimeFilterBasicType type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GMIME_FILTER_BASIC_H__ */ diff --git a/gmime/gmime-filter-crlf.c b/gmime/gmime-filter-crlf.c new file mode 100644 index 00000000..5954ad3d --- /dev/null +++ b/gmime/gmime-filter-crlf.c @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#include "gmime-filter-crlf.h" + +static void filter_destroy (GMimeFilter *filter); +static GMimeFilter *filter_copy (GMimeFilter *filter); +static void filter_filter (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_complete (GMimeFilter *filter, char *in, size_t len, + size_t prespace, char **out, + size_t *outlen, size_t *outprespace); +static void filter_reset (GMimeFilter *filter); + +static GMimeFilter template = { + NULL, NULL, NULL, NULL, + 0, 0, NULL, 0, 0, + filter_destroy, + filter_copy, + filter_filter, + filter_complete, + filter_reset, +}; + + +/** + * g_mime_filter_crlf_new_type: + * @direction: + * @mode: + * + * Returns a new crlf(/dot) filter. + **/ +GMimeFilter * +g_mime_filter_crlf_new (GMimeFilterCRLFDirection direction, GMimeFilterCRLFMode mode) +{ + GMimeFilterCRLF *new; + + new = g_new (GMimeFilterCRLF, 1); + + new->direction = direction; + new->mode = mode; + new->saw_cr = FALSE; + new->saw_lf = FALSE; + new->saw_dot = FALSE; + + g_mime_filter_construct (GMIME_FILTER (new), &template); + + return GMIME_FILTER (new); +} + + +static void +filter_destroy (GMimeFilter *filter) +{ + g_free (filter); +} + +static GMimeFilter * +filter_copy (GMimeFilter *filter) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + + return g_mime_filter_crlf_new (crlf->direction, crlf->mode); +} + +static void +filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + gboolean do_dots; + char *p, *q; + + do_dots = crlf->mode == GMIME_FILTER_CRLF_MODE_CRLF_DOTS; + + if (crlf->direction == GMIME_FILTER_CRLF_ENCODE) { + g_mime_filter_set_size (filter, 3 * len, FALSE); + + p = in; + q = filter->outbuf; + while (p < in + len) { + if (*p == '\n') { + crlf->saw_lf = TRUE; + *q++ = '\r'; + } else { + if (do_dots && *p == '.' && crlf->saw_lf) + *q++ = '.'; + + crlf->saw_lf = FALSE; + } + + *q++ = *p++; + } + } else { + g_mime_filter_set_size (filter, len, FALSE); + + p = in; + q = filter->outbuf; + while (p < in + len) { + if (*p == '\r') { + crlf->saw_cr = TRUE; + } else { + if (crlf->saw_cr) { + crlf->saw_cr = FALSE; + + if (*p == '\n') { + crlf->saw_lf = TRUE; + *q++ = *p++; + continue; + } else + *q++ = '\r'; + } + + *q++ = *p; + } + + if (do_dots && *p == '.') { + if (crlf->saw_lf) { + crlf->saw_dot = TRUE; + crlf->saw_lf = FALSE; + p++; + } else if (crlf->saw_dot) { + crlf->saw_dot = FALSE; + } + } + + crlf->saw_lf = FALSE; + + p++; + } + } + + *out = filter->outbuf; + *outlen = q - filter->outbuf; + *outprespace = filter->outpre; +} + +static void +filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace) +{ + if (in && len) + filter_filter (filter, in, len, prespace, out, outlen, outprespace); +} + +static void +filter_reset (GMimeFilter *filter) +{ + GMimeFilterCRLF *crlf = (GMimeFilterCRLF *) filter; + + crlf->saw_cr = FALSE; + crlf->saw_lf = TRUE; + crlf->saw_dot = FALSE; +} diff --git a/gmime/gmime-filter-crlf.h b/gmime/gmime-filter-crlf.h new file mode 100644 index 00000000..52bcb5cc --- /dev/null +++ b/gmime/gmime-filter-crlf.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * 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 of the License, 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 Street #330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __G_MIME_FILTER_CRLF_H__ +#define __G_MIME_FILTER_CRLF_H__ + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include "gmime-filter.h" + +typedef enum { + GMIME_FILTER_CRLF_ENCODE, + GMIME_FILTER_CRLF_DECODE +} GMimeFilterCRLFDirection; + +typedef enum { + GMIME_FILTER_CRLF_MODE_CRLF_DOTS, + GMIME_FILTER_CRLF_MODE_CRLF_ONLY, +} GMimeFilterCRLFMode; + +typedef struct _GMimeFilterCRLF { + GMimeFilter parent; + + GMimeFilterCRLFDirection direction; + GMimeFilterCRLFMode mode; + gboolean saw_cr; + gboolean saw_lf; + gboolean saw_dot; +} GMimeFilterCRLF; + +GMimeFilter *g_mime_filter_crlf_new_type (GMimeFilterCRLFDirection direction, GMimeFilterCRLFMode mode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GMIME_FILTER_CRLF_H__ */ diff --git a/gmime/gmime-filter.c b/gmime/gmime-filter.c index 00709db3..aaf9fa2f 100644 --- a/gmime/gmime-filter.c +++ b/gmime/gmime-filter.c @@ -192,10 +192,10 @@ g_mime_filter_reset (GMimeFilter *filter) { g_return_if_fail (filter != NULL); - filter->reset (f); + filter->reset (filter); /* could free some buffers, if they are really big? */ - f->backlen = 0; + filter->backlen = 0; } @@ -255,6 +255,6 @@ g_mime_filter_set_size (GMimeFilter *filter, size_t size, gboolean keep) /* this could be offset from the end of the structure, but this should be good enough */ - f->outpre = PRE_HEAD * 4; + filter->outpre = PRE_HEAD * 4; } } diff --git a/gmime/gmime-filter.h b/gmime/gmime-filter.h index 09bd145b..2d55922f 100644 --- a/gmime/gmime-filter.h +++ b/gmime/gmime-filter.h @@ -30,6 +30,7 @@ extern "C" { #endif /* __cplusplus */ #include <glib.h> +#include <sys/types.h> typedef struct _GMimeFilter GMimeFilter; @@ -62,6 +63,7 @@ struct _GMimeFilter { void (*reset) (GMimeFilter *filter); }; +#define GMIME_FILTER(filter) ((GMimeFilter *) filter) void g_mime_filter_construct (GMimeFilter *filter, GMimeFilter *template); diff --git a/gmime/gmime-part.c b/gmime/gmime-part.c index 6b1b3dd3..c1dd7f13 100644 --- a/gmime/gmime-part.c +++ b/gmime/gmime-part.c @@ -31,12 +31,18 @@ #include <unistd.h> #include <string.h> #include <ctype.h> + #include "gmime-part.h" #include "gmime-utils.h" #include "gmime-stream-mem.h" +#include "gmime-stream-filter.h" +#include "gmime-filter-basic.h" #include "md5-utils.h" +#define NEEDS_DECODING(encoding) (((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_BASE64 || \ + ((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_QUOTEDPRINTABLE) + /** * g_mime_part_new: Create a new MIME Part object * @@ -235,19 +241,19 @@ g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5) if (content_md5) { mime_part->content_md5 = g_strdup (content_md5); - } else if (mime_part->content) { + } else if (mime_part->content->stream) { char digest[16], b64digest[32]; int len, state, save; GMimeStream *stream; GByteArray *buf; - if (GMIME_IS_STREAM_MEM (mime_part->content->stream)) { - stream = mime_part->content->stream; - g_mime_stream_ref (mime_part->content->stream); - } else { + stream = mime_part->content->stream; + if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { stream = g_mime_stream_mem_new (); - g_mime_stream_write_to_stream (mime_part->content->stream, stream); - g_mime_stream_reset (mime_part->content->stream); + g_mime_data_wrapper_write_to_stream (mime_part->content, stream); + } else { + stream = mime_part->content->stream; + g_mime_stream_ref (stream); } buf = GMIME_STREAM_MEM (stream)->buffer; @@ -285,15 +291,16 @@ g_mime_part_verify_content_md5 (GMimePart *mime_part) GByteArray *buf; g_return_val_if_fail (mime_part != NULL, FALSE); + g_return_val_if_fail (mime_part->content != NULL, FALSE); g_return_val_if_fail (mime_part->content_md5 != NULL, FALSE); - if (GMIME_IS_STREAM_MEM (mime_part->content)) { + stream = mime_part->content->stream; + if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { + stream = g_mime_stream_mem_new (); + g_mime_data_wrapper_write_to_stream (mime_part->content, stream); + } else { stream = mime_part->content->stream; g_mime_stream_ref (stream); - } else { - stream = g_mime_stream_mem_new (); - g_mime_stream_write_to_stream (mime_part->content->stream, GMIME_STREAM (stream)); - g_mime_stream_reset (mime_part->content->stream); } buf = GMIME_STREAM_MEM (stream)->buffer; @@ -844,9 +851,6 @@ g_mime_part_set_content_object (GMimePart *mime_part, GMimeDataWrapper *content) } -#define NEEDS_DECODING(encoding) (((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_BASE64 || \ - ((GMimePartEncodingType) encoding) == GMIME_PART_ENCODING_QUOTEDPRINTABLE) - /** * g_mime_part_get_content: * @mime_part: the GMimePart to be decoded. @@ -858,6 +862,7 @@ g_mime_part_set_content_object (GMimePart *mime_part, GMimeDataWrapper *content) const char * g_mime_part_get_content (const GMimePart *mime_part, guint *len) { + GMimeStream *stream; GByteArray *buf; g_return_val_if_fail (mime_part != NULL, NULL); @@ -869,34 +874,12 @@ g_mime_part_get_content (const GMimePart *mime_part, guint *len) if (stream && (!GMIME_IS_STREAM_MEM (stream) || NEEDS_DECODING (mime_part->content->encoding))) { /* Decode and cache this mime part's contents... */ GMimeStream *cache; - int len, save = 0, state = 0; - char inbuf[4096], outbuf[4096]; - ssize_t nread; buf = g_byte_array_new (); - - while (!g_mime_stream_eos (stream)) { - nread = g_mime_stream_read (stream, inbuf, sizeof (inbuf)); - if (nread > 0) { - switch (mime_part->content->encoding) { - case GMIME_PART_ENCODING_BASE64: - len = g_mime_utils_base64_decode_step (inbuf, nread, outbuf, - &state, &save); - g_byte_array_append (buf, outbuf, len); - break; - case GMIME_PART_ENCODING_QUOTEDPRINTABLE: - len = g_mime_utils_quoted_decode_step (inbuf, nread, outbuf, - &state, &save); - g_byte_array_append (buf, outbuf, len); - break; - default: - g_byte_array_append (buf, inbuf, nread); - } - } - } - cache = g_mime_stream_mem_new_with_byte_array (buf); + g_mime_data_wrapper_write_to_stream (mime_part->content, cache); + g_mime_data_wrapper_set_stream (mime_part->content, cache); g_mime_data_wrapper_set_encoding (mime_part->content, GMIME_PART_ENCODING_DEFAULT); g_mime_stream_unref (cache); @@ -1022,38 +1005,32 @@ get_content_type (GMimeContentType *mime_type) static void write_content (GMimePart *part, GMimeStream *stream) { - const char *content; - int save = 0, state = 0; - char *outbuf; - int len; + GMimeStream *filtered_stream; + GMimeFilter *filter; + ssize_t written; if (!part->content || !part->content->stream) return; - content = g_mime_part_get_content (part, &len); - if (!content) - return; - + filtered_stream = g_mime_stream_filter_new_with_stream (stream); switch (part->encoding) { case GMIME_PART_ENCODING_BASE64: - outbuf = g_malloc (BASE64_ENCODE_LEN (len)); - len = g_mime_utils_base64_encode_close (content, len, outbuf, &state, &save); + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_BASE64_ENC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); break; case GMIME_PART_ENCODING_QUOTEDPRINTABLE: - state = -1; - outbuf = g_malloc (QP_ENCODE_LEN (len)); - len = g_mime_utils_quoted_encode_close (content, len, outbuf, &state, &save); + filter = g_mime_filter_basic_new_type (GMIME_FILTER_BASIC_QP_ENC); + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), filter); break; default: - outbuf = g_malloc (len); - memcpy (outbuf, content, len); + break; } - g_warning ("write_content(): writing outbuf...%.*s", 20, outbuf); - g_mime_stream_write (stream, outbuf, len); - g_warning ("write_content(): done."); + written = g_mime_data_wrapper_write_to_stream (part->content, filtered_stream); + g_mime_stream_unref (filtered_stream); - g_free (outbuf); + /* this is just so that I get a warning on fail... */ + g_return_if_fail (written != -1); } diff --git a/gmime/gmime-stream-filter.c b/gmime/gmime-stream-filter.c index 62bdf03e..9d4bf5f8 100644 --- a/gmime/gmime-stream-filter.c +++ b/gmime/gmime-stream-filter.c @@ -73,7 +73,7 @@ static void stream_destroy (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *fn, *f; f = p->filters; @@ -96,7 +96,7 @@ static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _CamelStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; ssize_t size; @@ -137,7 +137,7 @@ stream_read (GMimeStream *stream, char *buf, size_t len) } size = MIN (len, p->filteredlen); - memcpy (buffer, p->filtered, size); + memcpy (buf, p->filtered, size); p->filteredlen -= size; p->filtered += size; @@ -148,7 +148,7 @@ static ssize_t stream_write (GMimeStream *stream, char *buf, size_t len) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; char *buffer; int presize; @@ -162,12 +162,12 @@ stream_write (GMimeStream *stream, char *buf, size_t len) f = p->filters; presize = 0; while (f) { - g_mime_mime_filter_filter (f->filter, buffer, n, presize, &buffer, &n, &presize); + g_mime_filter_filter (f->filter, buffer, n, presize, &buffer, &n, &presize); f = f->next; } - if (gmime_stream_write (filter->source, buffer, n) != n) + if (g_mime_stream_write (filter->source, buffer, n) != n) return -1; /* return 'len' because that's what our caller expects */ @@ -178,7 +178,7 @@ static int stream_flush (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; int len, presize; char *buffer; @@ -209,7 +209,7 @@ static int stream_close (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; if (!p->last_was_read) { stream_flush (stream); @@ -222,7 +222,7 @@ static gboolean stream_eos (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; if (p->filteredlen > 0) return FALSE; @@ -234,7 +234,7 @@ static int stream_reset (GMimeStream *stream) { GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; - struct _GMimeStreamFilterPrivate *p = _PRIVATE (filter); + struct _GMimeStreamFilterPrivate *p = filter->priv; struct _filter *f; p->filteredlen = 0; @@ -272,33 +272,56 @@ stream_length (GMimeStream *stream) static GMimeStream * stream_substream (GMimeStream *stream, off_t start, off_t end) { - GMimeStreamFilter *filter; - struct _filters *f, *fn; + GMimeStreamFilter *filter = (GMimeStreamFilter *) stream; + GMimeStreamFilter *sub; + struct _filter *f, *fn; - filter = g_new (GMimeStreamFilter, 1); - filter->source = GMIME_STREAM_FILTER (stream)->source; - g_mime_stream_ref (filter->source); + sub = g_new (GMimeStreamFilter, 1); + sub->source = filter->source; + g_mime_stream_ref (sub->source); - filter->priv = g_new (struct _GMimeStreamFilterPrivate, 1); - filter->priv->filters = NULL; - filter->priv->filterid = 0; - filter->priv->realbuffer = g_malloc (READ_SIZE + READ_PAD); - filter->priv->buffer = filter->priv->realbuffer + READ_PAD; - filter->priv->last_was_read = TRUE; - filter->priv->filteredlen = 0; + sub->priv = g_new (struct _GMimeStreamFilterPrivate, 1); + sub->priv->filters = NULL; + sub->priv->filterid = 0; + sub->priv->realbuffer = g_malloc (READ_SIZE + READ_PAD); + sub->priv->buffer = sub->priv->realbuffer + READ_PAD; + sub->priv->last_was_read = TRUE; + sub->priv->filteredlen = 0; - /* FIXME: copy the filters... */ + if (filter->priv->filters) { + struct _filter *f, *sn, *s = NULL; + + f = filter->priv->filters; + while (f) { + sn = g_new (struct _filter, 1); + sn->filter = g_mime_filter_copy (f->filter); + sn->id = f->id; + + if (s) { + s->next = sn; + s = sn; + } else { + s = sub->priv->filters = sn; + } + + f = f->next; + } + + s->next = NULL; + + sub->priv->filterid = filter->priv->filterid; + } g_mime_stream_construct (GMIME_STREAM (filter), &template, GMIME_STREAM_FILTER_TYPE, - filter->source->bound_start, - filter->source->bound_end); + sub->source->bound_start, + sub->source->bound_end); - return GMIME_STREAM (filter); + return GMIME_STREAM (sub); } -GMimeStreamFilter * +GMimeStream * g_mime_stream_filter_new_with_stream (GMimeStream *stream) { GMimeStreamFilter *filter; @@ -329,11 +352,14 @@ g_mime_stream_filter_new_with_stream (GMimeStream *stream) int g_mime_stream_filter_add (GMimeStreamFilter *fstream, GMimeFilter *filter) { - struct _GMimeStreamFilterPrivate *p = _PRIVATE (fstream); + struct _GMimeStreamFilterPrivate *p; struct _filter *f, *fn; + g_return_val_if_fail (fstream != NULL, -1); g_return_val_if_fail (filter != NULL, -1); + p = fstream->priv; + fn = g_new (struct _filter, 1); fn->next = NULL; fn->filter = filter; @@ -353,10 +379,12 @@ g_mime_stream_filter_add (GMimeStreamFilter *fstream, GMimeFilter *filter) void g_mime_stream_filter_remove (GMimeStreamFilter *fstream, int id) { - struct _GMimeStreamFilterPrivate *p = _PRIVATE (fstream); + struct _GMimeStreamFilterPrivate *p; struct _filter *f, *fn; - g_return_val_if_fail (filter != NULL, -1); + g_return_if_fail (fstream != NULL); + + p = fstream->priv; if (id == -1) return; diff --git a/gmime/gmime-stream-filter.h b/gmime/gmime-stream-filter.h index c30f07f4..93da9931 100644 --- a/gmime/gmime-stream-filter.h +++ b/gmime/gmime-stream-filter.h @@ -42,7 +42,7 @@ typedef struct _GMimeStreamFilter { #define GMIME_STREAM_FILTER_TYPE g_str_hash ("GMimeStreamFilter") #define GMIME_IS_STREAM_FILTER(stream) (((GMimeStream *) stream)->type == GMIME_STREAM_FILTER_TYPE) -#define GMIME_STREAM_FILTER(stream) ((GMimeStreamMem *) stream) +#define GMIME_STREAM_FILTER(stream) ((GMimeStreamFilter *) stream) GMimeStream *g_mime_stream_filter_new_with_stream (GMimeStream *stream); |