aboutsummaryrefslogblamecommitdiffstats
path: root/camel/camel-mime-filter-bestenc.c
blob: d3db9a2a3f7f62263a3f45f767ddc5e3617f7cf2 (plain) (tree)





















































































































































































































































                                                                                                                                      
/*
 *  Copyright (C) 2000 Helix Code Inc.
 *
 *  Authors: Michael Zucchi <notzed@helixcode.com>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "camel-mime-filter-bestenc.h"

static void camel_mime_filter_bestenc_class_init (CamelMimeFilterBestencClass *klass);
static void camel_mime_filter_bestenc_init       (CamelMimeFilter *obj);

static CamelMimeFilterClass *camel_mime_filter_bestenc_parent;

CamelType
camel_mime_filter_bestenc_get_type (void)
{
    static CamelType type = CAMEL_INVALID_TYPE;
    
    if (type == CAMEL_INVALID_TYPE) {
        type = camel_type_register (camel_mime_filter_get_type (), "CamelMimeFilterBestenc",
                        sizeof (CamelMimeFilterBestenc),
                        sizeof (CamelMimeFilterBestencClass),
                        (CamelObjectClassInitFunc) camel_mime_filter_bestenc_class_init,
                        NULL,
                        (CamelObjectInitFunc) camel_mime_filter_bestenc_init,
                        NULL);
    }
    
    return type;
}

static void
reset(CamelMimeFilter *mf)
{
    CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;

    f->count0 = 0;
    f->count8 = 0;
    f->countline = 0;
    f->total = 0;
    f->lastc = ~0;
    f->crlfnoorder = FALSE;
    camel_charset_init(&f->charset);
}

static void
filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
    CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;
    register unsigned char *p, *pend;

    f->total += len;

    if (f->flags & CAMEL_BESTENC_GET_ENCODING) {
        register unsigned int /* hopefully reg's are assinged in the order they appear? */
            c,
            lastc=f->lastc, 
            countline=f->countline,
            count0=f->count0,
            count8 = f->count8;

        /* See rfc2045 section 2 for definitions of 7bit/8bit/binary */
        p = in;
        pend = p + len;
        while (p<pend) {
            c = *p++;
            /* check for 8 bit characters */
            if (c & 0x80)
                count8++;

            /* check for nul's */
            if (c == 0)
                count0++;

            /* check for wild '\r's in a unix format stream */
            if (c == '\r' && (f->flags & CAMEL_BESTENC_LF_IS_CRLF)) {
                f->crlfnoorder = TRUE;
            }

            /* check for end of line */
            if (c == '\n') {
                /* check for wild '\n's in canonical format stream */
                if (lastc == '\r' || (f->flags & CAMEL_BESTENC_LF_IS_CRLF)) {
                    if (countline > f->maxline)
                        f->maxline = countline;
                    countline = 0;
                } else {
                    f->crlfnoorder = TRUE;
                }
            } else {
                countline++;
            }
            lastc = c;
        }
        f->count8 = count8;
        f->count0 = count0;
        f->countline = countline;
        f->lastc = lastc;
    }

    if (f->flags & CAMEL_BESTENC_GET_CHARSET)
        camel_charset_step(&f->charset, in, len);

    *out = in;
    *outlen = len;
    *outprespace = prespace;
}

static void
complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
    CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;

    filter(mf, in, len, prespace, out, outlen, outprespace);

    if (f->countline > f->maxline)
        f->maxline = f->countline;
    f->countline = 0;
}

static void
camel_mime_filter_bestenc_class_init (CamelMimeFilterBestencClass *klass)
{
    CamelMimeFilterClass *filter_class = (CamelMimeFilterClass *) klass;

    camel_mime_filter_bestenc_parent = (CamelMimeFilterClass *)(camel_type_get_global_classfuncs (camel_mime_filter_get_type ()));

    filter_class->reset = reset;
    filter_class->filter = filter;
    filter_class->complete = complete;
}

static void
camel_mime_filter_bestenc_init (CamelMimeFilter *f)
{
    reset(f);
}

/**
 * camel_mime_filter_bestenc_new:
 * @flags: A bitmask of data required.
 *
 * Create a new CamelMimeFilterBestenc object. 
 * 
 * Return value:
 **/
CamelMimeFilterBestenc *
camel_mime_filter_bestenc_new (unsigned int flags)
{
    CamelMimeFilterBestenc *new = (CamelMimeFilterBestenc *)camel_object_new(camel_mime_filter_bestenc_get_type());
    new->flags = flags;
    return new;
}

/**
 * camel_mime_filter_bestenc_get_best_encoding:
 * @f: 
 * @required: maximum level of output encoding allowed.
 * 
 * Return the best encoding, given specific constraints, that can be used to
 * encode a stream of bytes.
 * 
 * Return value: 
 **/
CamelMimePartEncodingType
camel_mime_filter_bestenc_get_best_encoding(CamelMimeFilterBestenc *f, CamelBestencEncoding required)
{
    CamelMimePartEncodingType bestenc;

#if 0
    printf("count0 = %d, count8 = %d, total = %d\n", f->count0, f->count8, f->total);
    printf("maxline = %d, crlfnoorder = %s\n", f->maxline, f->crlfnoorder?"TRUE":"FALSE");
    printf(" %d%% require encoding?\n", (f->count0+f->count8)*100 / f->total);
#endif

    /* if we need to encode, see how we do it */
    if (required == CAMEL_BESTENC_BINARY)
        bestenc = CAMEL_MIME_PART_ENCODING_BINARY;
    else if (f->count8 + f->count0 >= (f->total*17/100))
        bestenc = CAMEL_MIME_PART_ENCODING_BASE64;
    else
        bestenc = CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE;
    
    /* if we have nocrlf order, or long lines, we need to encode always */
    if (f->crlfnoorder || f->maxline >= 998)
        return bestenc;

    /* if we have no 8 bit chars or nul's, we can just use 7 bit */
    if (f->count8 + f->count0 == 0)
        return CAMEL_MIME_PART_ENCODING_7BIT;

    /* otherwise, we see if we can use 8 bit, or not */
    switch(required) {
    case CAMEL_BESTENC_7BIT:
        return bestenc;
    case CAMEL_BESTENC_8BIT:
    case CAMEL_BESTENC_BINARY:
        if (f->count0 == 0)
            return CAMEL_MIME_PART_ENCODING_8BIT;
        else
            return bestenc;
    }

    return CAMEL_MIME_PART_ENCODING_DEFAULT;
}

/**
 * camel_mime_filter_bestenc_get_best_charset:
 * @f: 
 * 
 * Gets the best charset that can be used to contain this content.
 * 
 * Return value: 
 **/
const char *
camel_mime_filter_bestenc_get_best_charset(CamelMimeFilterBestenc *f)
{
    return camel_charset_best_name(&f->charset);
}

/**
 * camel_mime_filter_bestenc_set_flags:
 * @f: 
 * @flags: 
 * 
 * Set the flags for subsequent operations.
 **/
void
camel_mime_filter_bestenc_set_flags(CamelMimeFilterBestenc *f, unsigned int flags)
{
    f->flags = flags;
}