2 * Copyright (C) 2000 Ximian Inc.
4 * Authors: Michael Zucchi <notzed@ximian.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
29 #include "camel-mime-filter-bestenc.h"
31 static void camel_mime_filter_bestenc_class_init (CamelMimeFilterBestencClass *klass);
32 static void camel_mime_filter_bestenc_init (CamelMimeFilter *obj);
34 static CamelMimeFilterClass *camel_mime_filter_bestenc_parent;
37 camel_mime_filter_bestenc_get_type (void)
39 static CamelType type = CAMEL_INVALID_TYPE;
41 if (type == CAMEL_INVALID_TYPE) {
42 type = camel_type_register (camel_mime_filter_get_type (), "CamelMimeFilterBestenc",
43 sizeof (CamelMimeFilterBestenc),
44 sizeof (CamelMimeFilterBestencClass),
45 (CamelObjectClassInitFunc) camel_mime_filter_bestenc_class_init,
47 (CamelObjectInitFunc) camel_mime_filter_bestenc_init,
55 reset(CamelMimeFilter *mf)
57 CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;
64 f->crlfnoorder = FALSE;
67 f->startofline = TRUE;
69 camel_charset_init(&f->charset);
73 filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
75 CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;
76 register unsigned char *p, *pend;
81 if (f->flags & CAMEL_BESTENC_GET_ENCODING) {
82 register unsigned int /* hopefully reg's are assinged in the order they appear? */
85 countline=f->countline,
89 /* Check ^From lines first call, or have the start of a new line waiting? */
90 if ((f->flags & CAMEL_BESTENC_NO_FROM) && !f->hadfrom
91 && (f->fromcount > 0 || f->startofline)) {
92 if (f->fromcount + len >=5) {
93 memcpy(&f->fromsave[f->fromcount], in, 5-f->fromcount);
94 f->hadfrom = strncmp(f->fromsave, "From ", 5) == 0;
97 memcpy(&f->fromsave[f->fromcount], in, len);
102 f->startofline = FALSE;
104 /* See rfc2045 section 2 for definitions of 7bit/8bit/binary */
105 p = (unsigned char *) in;
109 /* check for 8 bit characters */
113 /* check for nul's */
117 /* check for wild '\r's in a unix format stream */
118 if (c == '\r' && (f->flags & CAMEL_BESTENC_LF_IS_CRLF)) {
119 f->crlfnoorder = TRUE;
122 /* check for end of line */
124 /* check for wild '\n's in canonical format stream */
125 if (lastc == '\r' || (f->flags & CAMEL_BESTENC_LF_IS_CRLF)) {
126 if (countline > f->maxline)
127 f->maxline = countline;
130 /* Check for "^From " lines */
131 if ((f->flags & CAMEL_BESTENC_NO_FROM) && !f->hadfrom) {
133 f->hadfrom = strncmp((char *) p, (char *) "From ", 5) == 0;
134 } else if (pend-p == 0) {
135 f->startofline = TRUE;
137 f->fromcount = pend-p;
138 memcpy(f->fromsave, p, pend-p);
142 f->crlfnoorder = TRUE;
151 f->countline = countline;
157 if (f->flags & CAMEL_BESTENC_GET_CHARSET)
158 camel_charset_step(&f->charset, in, len);
163 *outprespace = prespace;
167 complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
169 CamelMimeFilterBestenc *f = (CamelMimeFilterBestenc *)mf;
171 filter(mf, in, len, prespace, out, outlen, outprespace);
173 if (f->countline > f->maxline)
174 f->maxline = f->countline;
179 camel_mime_filter_bestenc_class_init (CamelMimeFilterBestencClass *klass)
181 CamelMimeFilterClass *filter_class = (CamelMimeFilterClass *) klass;
183 camel_mime_filter_bestenc_parent = (CamelMimeFilterClass *)(camel_type_get_global_classfuncs (camel_mime_filter_get_type ()));
185 filter_class->reset = reset;
186 filter_class->filter = filter;
187 filter_class->complete = complete;
191 camel_mime_filter_bestenc_init (CamelMimeFilter *f)
197 * camel_mime_filter_bestenc_new:
198 * @flags: a bitmask of data required.
200 * Create a new #CamelMimeFilterBestenc object.
202 * Returns a new #CamelMimeFilterBestenc object
204 CamelMimeFilterBestenc *
205 camel_mime_filter_bestenc_new (unsigned int flags)
207 CamelMimeFilterBestenc *new = (CamelMimeFilterBestenc *)camel_object_new(camel_mime_filter_bestenc_get_type());
214 * camel_mime_filter_bestenc_get_best_encoding:
215 * @filter: a #CamelMimeFilterBestenc object
216 * @required: maximum level of output encoding allowed.
218 * Get the best encoding, given specific constraints, that can be used to
219 * encode a stream of bytes.
221 * Returns the best encoding to use
223 CamelTransferEncoding
224 camel_mime_filter_bestenc_get_best_encoding(CamelMimeFilterBestenc *filter, CamelBestencEncoding required)
226 CamelTransferEncoding bestenc;
229 istext = (required & CAMEL_BESTENC_TEXT) ? 1 : 0;
230 required = required & ~CAMEL_BESTENC_TEXT;
233 printf("count0 = %d, count8 = %d, total = %d\n", filter->count0, filter->count8, filter->total);
234 printf("maxline = %d, crlfnoorder = %s\n", filter->maxline, filter->crlfnoorder?"TRUE":"FALSE");
235 printf(" %d%% require encoding?\n", (filter->count0+filter->count8)*100 / filter->total);
238 /* if we're not allowed to have From lines and we had one, use an encoding
239 that will never let it show. Unfortunately only base64 can at present,
240 although qp could be modified to allow it too */
241 if ((filter->flags & CAMEL_BESTENC_NO_FROM) && filter->hadfrom)
242 return CAMEL_TRANSFER_ENCODING_BASE64;
244 /* if we need to encode, see how we do it */
245 if (required == CAMEL_BESTENC_BINARY)
246 bestenc = CAMEL_TRANSFER_ENCODING_BINARY;
247 else if (istext && (filter->count0 == 0 && filter->count8 < (filter->total * 17 / 100)))
248 bestenc = CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE;
250 bestenc = CAMEL_TRANSFER_ENCODING_BASE64;
252 /* if we have nocrlf order, or long lines, we need to encode always */
253 if (filter->crlfnoorder || filter->maxline >= 998)
256 /* if we have no 8 bit chars or nul's, we can just use 7 bit */
257 if (filter->count8 + filter->count0 == 0)
258 return CAMEL_TRANSFER_ENCODING_7BIT;
260 /* otherwise, we see if we can use 8 bit, or not */
262 case CAMEL_BESTENC_7BIT:
264 case CAMEL_BESTENC_8BIT:
265 case CAMEL_BESTENC_BINARY:
267 if (filter->count0 == 0)
268 return CAMEL_TRANSFER_ENCODING_8BIT;
277 * camel_mime_filter_bestenc_get_best_charset:
278 * @filter: a #CamelMimeFilterBestenc object
280 * Gets the best charset that can be used to contain this content.
282 * Returns the name of the best charset to use to encode the input
283 * text filtered by @filter
286 camel_mime_filter_bestenc_get_best_charset (CamelMimeFilterBestenc *filter)
288 return camel_charset_best_name(&filter->charset);
293 * camel_mime_filter_bestenc_set_flags:
294 * @filter: a #CamelMimeFilterBestenc object
295 * @flags: bestenc filter flags
297 * Set the flags for subsequent operations.
300 camel_mime_filter_bestenc_set_flags(CamelMimeFilterBestenc *filter, unsigned int flags)
302 filter->flags = flags;