diff options
Diffstat (limited to 'camel/camel-mime-filter-canon.c')
-rw-r--r-- | camel/camel-mime-filter-canon.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/camel/camel-mime-filter-canon.c b/camel/camel-mime-filter-canon.c new file mode 100644 index 0000000000..0fd48fb7b3 --- /dev/null +++ b/camel/camel-mime-filter-canon.c @@ -0,0 +1,226 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002 Ximian, Inc. + * + * Authors: Jeffrey Stedfast <fejj@ximian.com> + * Michael Zucchi <notzed@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* canonicalisation filter, used for secure mime incoming and outgoing */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <ctype.h> + +#include "camel-mime-filter-canon.h" + +static void filter (CamelMimeFilter *f, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace); +static void complete (CamelMimeFilter *f, char *in, size_t len, + size_t prespace, char **out, size_t *outlen, + size_t *outprespace); +static void reset (CamelMimeFilter *f); + + +static void +camel_mime_filter_canon_class_init (CamelMimeFilterCanonClass *klass) +{ + CamelMimeFilterClass *mime_filter_class = (CamelMimeFilterClass *) klass; + + mime_filter_class->filter = filter; + mime_filter_class->complete = complete; + mime_filter_class->reset = reset; +} + +CamelType +camel_mime_filter_canon_get_type (void) +{ + static CamelType type = CAMEL_INVALID_TYPE; + + if (type == CAMEL_INVALID_TYPE) { + type = camel_type_register (camel_mime_filter_get_type(), "CamelMimeFilterCanon", + sizeof (CamelMimeFilterCanon), + sizeof (CamelMimeFilterCanonClass), + (CamelObjectClassInitFunc) camel_mime_filter_canon_class_init, + NULL, + NULL, + NULL); + } + + return type; +} + +static void +filter(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace) +{ + register unsigned char *inptr, c; + const unsigned char *inend, *start; + char *starto; + register char *o; + int lf = 0; + guint32 flags; + + flags = ((CamelMimeFilterCanon *)f)->flags; + + /* first, work out how much space we need */ + inptr = in; + inend = in+len; + while (inptr < inend) + if (*inptr++ == '\n') + lf++; + + /* worst case, extra 3 chars per line + "From \n" -> "=46rom \r\n" + We add 1 extra incase we're called from complete, when we didn't end in \n */ + + camel_mime_filter_set_size(f, len+lf*3+4, FALSE); + + o = f->outbuf; + inptr = in; + start = inptr; + starto = o; + while (inptr < inend) { + /* first, check start of line, we always start at the start of the line */ + c = *inptr; + if (flags & CAMEL_MIME_FILTER_CANON_FROM && c == 'F') { + inptr++; + if (inptr < inend-4) { + if (strncmp(inptr, "rom ", 4) == 0) { + *o++ = '='; + *o++ = '4'; + *o++ = '6'; + } else + *o++ = 'F'; + *o++ = *inptr++; + *o++ = *inptr++; + *o++ = *inptr++; + *o++ = *inptr++; + } else { + break; + } + } + + /* now scan for end of line */ + while (inptr < inend) { + c = *inptr++; + if (c == '\n') { + /* check to strip trailing space */ + if (flags & CAMEL_MIME_FILTER_CANON_STRIP) { + while (o>starto && (o[-1] == ' ' || o[-1] == '\t' || o[-1]=='\r')) + o--; + } + /* check end of line canonicalisation */ + if (o>starto) { + if (flags & CAMEL_MIME_FILTER_CANON_CRLF) { + if (o[-1] != '\r') + *o++ = '\r'; + } else { + if (o[-1] == '\r') + o--; + } + } + *o++ = c; + start = inptr; + starto = o; + break; + } else + *o++ = c; + } + } + + /* TODO: We should probably track if we end somewhere in the middle of a line, + otherwise we potentially backup a full line, which could be large */ + + /* we got to the end of the data without finding anything, backup to start and re-process next time around */ + camel_mime_filter_backup(f, start, inend - start); + + *out = f->outbuf; + *outlen = starto - f->outbuf; + *outprespace = f->outpre; +} + +static void +complete(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace) +{ + unsigned char *inptr, *inend; + char *o, *starto; + guint32 flags; + + if (len) + filter(f, in, len, prespace, out, outlen, outprespace); + + /* the data didn't contain an eol or was too short for "From ", we only need to check for "From" and add an eol */ + if (f->backlen) { + inptr = (unsigned char *)f->backbuf; + inend = (unsigned char *)f->backbuf + f->backlen; + starto = o = *out + *outlen; + flags = ((CamelMimeFilterCanon *)f)->flags; + + /* Check any embedded "From " */ + if (f->backlen >= 5 + && (flags & CAMEL_MIME_FILTER_CANON_FROM) + && strcmp(inptr, "From ") == 0) { + strcpy(o, "=46rom "); + o += 7; + inptr += 5; + } + + /* copy the rest of it */ + while (inptr < inend) + *o++ = *inptr++; + + /* check to strip trailing space */ + if (flags & CAMEL_MIME_FILTER_CANON_STRIP) { + while (o>starto && (o[-1] == ' ' || o[-1] == '\t' || o[-1]=='\r')) + o--; + } + /* check end of line canonicalisation */ + if (o>starto) { + if (flags & CAMEL_MIME_FILTER_CANON_CRLF) { + if (o[-1] != '\r') + *o++ = '\r'; + } else { + if (o[-1] == '\r') + o--; + } + } + + /* and always finish with an eol */ + *o++ = '\n'; + + *outlen = o - *out; + } +} + +static void +reset (CamelMimeFilter *f) +{ + /* no-op */ +} + +CamelMimeFilter * +camel_mime_filter_canon_new(guint32 flags) +{ + CamelMimeFilterCanon *chomp = CAMEL_MIME_FILTER_CANON (camel_object_new (CAMEL_MIME_FILTER_CANON_TYPE)); + + chomp->flags = flags; + + return (CamelMimeFilter *) chomp; +} |