/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*
* Authors: Matt Brown
* Jeffrey Stedfast
*/
/* Strips PGP message headers from the input stream and also performs
* pgp decoding as described in section 7.1 of RFC2440 */
#include "evolution-data-server-config.h"
#include
#include
#include "camel-mime-filter-pgp.h"
#include "camel-mime-utils.h"
#define BEGIN_PGP_SIGNED_MESSAGE "-----BEGIN PGP SIGNED MESSAGE-----"
#define BEGIN_PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
#define END_PGP_SIGNATURE "-----END PGP SIGNATURE-----"
#define BEGIN_PGP_SIGNED_MESSAGE_LEN (sizeof (BEGIN_PGP_SIGNED_MESSAGE) - 1)
#define BEGIN_PGP_SIGNATURE_LEN (sizeof (BEGIN_PGP_SIGNATURE) - 1)
#define END_PGP_SIGNATURE_LEN (sizeof (END_PGP_SIGNATURE) - 1)
struct _CamelMimeFilterPgpPrivate {
gint state;
};
enum {
PGP_PREFACE,
PGP_HEADER,
PGP_MESSAGE,
PGP_FOOTER
};
G_DEFINE_TYPE_WITH_PRIVATE (CamelMimeFilterPgp, camel_mime_filter_pgp, CAMEL_TYPE_MIME_FILTER)
static void
mime_filter_pgp_run (CamelMimeFilter *mime_filter,
const gchar *in,
gsize inlen,
gsize prespace,
gchar **out,
gsize *outlen,
gsize *outprespace,
gint last)
{
CamelMimeFilterPgpPrivate *priv;
const gchar *start, *inend = in + inlen;
register const gchar *inptr = in;
register gchar *o;
gboolean blank;
gsize len;
priv = CAMEL_MIME_FILTER_PGP (mime_filter)->priv;
/* only need as much space as the input, we're stripping chars */
camel_mime_filter_set_size (mime_filter, inlen, FALSE);
o = mime_filter->outbuf;
while (inptr < inend) {
start = inptr;
blank = TRUE;
while (inptr < inend && *inptr != '\n') {
if (blank && !strchr (" \t\r", *inptr))
blank = FALSE;
inptr++;
}
if (inptr == inend) {
if (!last)
camel_mime_filter_backup (mime_filter, start, inend - start);
break;
}
len = inptr - start;
if (len > 0 && inptr[-1] == '\r')
len--;
while (len > 0 && camel_mime_is_lwsp (start[len - 1]))
len--;
inptr++;
switch (priv->state) {
case PGP_PREFACE:
/* check for the beginning of the pgp block */
if (len == BEGIN_PGP_SIGNED_MESSAGE_LEN && !strncmp (start, BEGIN_PGP_SIGNED_MESSAGE, len)) {
priv->state++;
break;
}
memcpy (o, start, inptr - start);
o += (inptr - start);
break;
case PGP_HEADER:
/* pgp headers (Hash: SHA1, etc) end with a blank (zero-length,
* or containing only whitespace) line; see RFC2440 */
if (blank)
priv->state++;
break;
case PGP_MESSAGE:
/* check for beginning of the pgp signature block */
if (len == BEGIN_PGP_SIGNATURE_LEN && !strncmp (start, BEGIN_PGP_SIGNATURE, len)) {
priv->state++;
break;
}
/* do dash decoding */
if (!strncmp (start, "- ", 2)) {
/* Dash encoded line found, skip encoding */
start += 2;
}
memcpy (o, start, inptr - start);
o += (inptr - start);
break;
case PGP_FOOTER:
if (len == END_PGP_SIGNATURE_LEN && !strncmp (start, END_PGP_SIGNATURE, len))
priv->state = PGP_PREFACE;
break;
}
}
*out = mime_filter->outbuf;
*outlen = o - mime_filter->outbuf;
*outprespace = mime_filter->outpre;
}
static void
mime_filter_pgp_filter (CamelMimeFilter *mime_filter,
const gchar *in,
gsize len,
gsize prespace,
gchar **out,
gsize *outlen,
gsize *outprespace)
{
mime_filter_pgp_run (
mime_filter, in, len, prespace,
out, outlen, outprespace, FALSE);
}
static void
mime_filter_pgp_complete (CamelMimeFilter *mime_filter,
const gchar *in,
gsize len,
gsize prespace,
gchar **out,
gsize *outlen,
gsize *outprespace)
{
mime_filter_pgp_run (
mime_filter, in, len, prespace,
out, outlen, outprespace, TRUE);
}
static void
mime_filter_pgp_reset (CamelMimeFilter *mime_filter)
{
CamelMimeFilterPgpPrivate *priv;
priv = CAMEL_MIME_FILTER_PGP (mime_filter)->priv;
priv->state = PGP_PREFACE;
}
static void
camel_mime_filter_pgp_class_init (CamelMimeFilterPgpClass *class)
{
CamelMimeFilterClass *mime_filter_class;
mime_filter_class = CAMEL_MIME_FILTER_CLASS (class);
mime_filter_class->filter = mime_filter_pgp_filter;
mime_filter_class->complete = mime_filter_pgp_complete;
mime_filter_class->reset = mime_filter_pgp_reset;
}
static void
camel_mime_filter_pgp_init (CamelMimeFilterPgp *filter)
{
filter->priv = camel_mime_filter_pgp_get_instance_private (filter);
}
CamelMimeFilter *
camel_mime_filter_pgp_new (void)
{
return g_object_new (CAMEL_TYPE_MIME_FILTER_PGP, NULL);
}