aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNotZed <NotZed@HelixCode.com>2000-04-23 18:10:44 +0800
committerMichael Zucci <zucchi@src.gnome.org>2000-04-23 18:10:44 +0800
commit5fcb83b5fb1294a781e3f7139200aa3486650db4 (patch)
treea890998dfce162ec25eb55b238e537f506abb6c1
parentf229f08168b0666469e0fc35d065860f2da58303 (diff)
downloadgsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar.gz
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar.bz2
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar.lz
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar.xz
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.tar.zst
gsoc2013-evolution-5fcb83b5fb1294a781e3f7139200aa3486650db4.zip
Whole swag of changes. Still lots of cleanup remaining ...
2000-04-23 NotZed <NotZed@HelixCode.com> * camel-data-wrapper.c (set_mime_type_field): Ref the content_field when we get it? * camel-mime-parser.c (camel_mime_parser_unstep): New function. Cause a subsequent call to mime_parser_step() to return the same state over again. * providers/mbox/camel-mbox-folder.c (_get_message_by_uid): Initial test code using the mime parser to construct the message. * camel-mime-part.c (construct_from_parser): part constructor. (camel_mime_part_construct_content): Basically a simpler replacement for the datawrapper repository. (camel_mime_part_init): Set the default type to text/plain. * camel-simple-data-wrapper.c (construct_from_parser): Initial implementation of a content constructor. * camel-multipart.c (construct_from_parser): Multipart construction routine. (camel_multipart_init): Set the default multipart type to multipart/mixed. Duh, no subtype is not allowed anyway. 2000-04-22 NotZed <NotZed@HelixCode.com> * camel-mime-message.h (struct _CamelMimeMessage): Removed send_date, and received_date, and replaced it with a time_t 'date' (this is what the header is called), and date_offset to store the GMT offset of the date. * camel-mime-message.c (camel_mime_message_set_from): Update raw header as we go. (_set_from): Removed. (_get_from): Removed. (camel_mime_message_get_from): Moved implementation here. (camel_mime_message_get_subject): Move implementation here. (_get_subject): Nuked. (camel_mime_message_set_subject): Handle utf-8 input, and also update raw header when changed. (_set_subject): Removed. (_set_received_date): Removed. (camel_mime_message_set_received_date): Removed. (_get_received_date): Removed. (camel_mime_message_get_received_date): Removed. (_get_sent_date): Removed. (camel_mime_message_get_sent_date): Removed. (camel_mime_message_get_date): New function to get the date as a time_t/offset. (camel_mime_message_set_date): Set the date as a time_t/offset. (camel_mime_message_get_date_string): Get the date as a string. (camel_mime_message_init): Initialise the current date as 'CMAEL_MESSAGE_DATE_CURRENT'. (_set_reply_to): Removed. (camel_mime_message_set_reply_to): Moved implementation here. This is still broken, reply-to can have multiple addresses. (_get_reply_to): Removed. (_set_field): Removed, no longer used anywhere. (_get_field): Also removed. (_init_header_name_table): Add the Date header. (process_header): Also handle snooping of Date header here. * camel-stream-filter.c (finalise): Unref the source stream on finalise, and also call the parent class (oops). * camel-mime-parser.c (camel_mime_parser_state): New function to get the current parser state. (camel_mime_parser_stream): Allow you to get the stream back from the mime_parser. (camel_mime_parser_fd): Alternative to allow you to get the fd back from the mime_parser. (folder_scan_init_with_stream): Properly ref/unref the stream. (folder_scan_close): Properly unref the stream/close the fd on exit. (folder_scan_init_with_fd): Close the old fd if there is one. * camel-data-wrapper.c (camel_data_wrapper_construct_from_parser): New method, construct a data wrapper from an initialised parser. (construct_from_parser): Empty implementation. * providers/mbox/camel-mbox-summary.c (message_struct_new): Convert subject line to unicode, before storing in the summary. (strdup_trim): Removed, no longer needed. * providers/mbox/camel-mbox-folder.c (_get_message_by_uid): Ref the folder after setting it in the new message. * camel-mime-part.c (my_set_content_object): Have the headers follow the content-type change here too. (my_write_to_stream): Dont write content-type here, automatically stored in the headers ... (my_write_to_stream): Use header_disposition_format() to format the content-disposition header. (my_write_to_stream): Removed old code, all headers are now stored in the camel-medium level, always. Need to do the same with camel-mime-message i suppose ... (my_write_to_stream): Write the content using the parent class, not some weird function. (camel_mime_part_class_init): Dont override get_output_stream. (camel_mime_part_encoding_from_string): Bleh, make it case-insensitive. * camel-mime-utils.c (header_content_type_is): Handle empty types. (header_encode_string): Start of an implementation of the rfc2047 encoder. It does iso-8859-1, and us-ascii, and utf-8 (others get tricky *sigh*) (rfc2047_encode_word): Convert a single word/string into rfc2047 encoding. (quoted_encode): Different quoted-printable encoding for rfc2047 encoding of headers. * gmime-content-field.c (gmime_content_field_write_to_stream): Use header_content_type_format() to format it. svn path=/trunk/; revision=2560
-rw-r--r--camel/ChangeLog95
-rw-r--r--camel/camel-data-wrapper.c28
-rw-r--r--camel/camel-data-wrapper.h8
-rw-r--r--camel/camel-mime-message.c254
-rw-r--r--camel/camel-mime-message.h13
-rw-r--r--camel/camel-mime-parser.c51
-rw-r--r--camel/camel-mime-parser.h6
-rw-r--r--camel/camel-mime-part.c119
-rw-r--r--camel/camel-mime-utils.c152
-rw-r--r--camel/camel-mime-utils.h3
-rw-r--r--camel/camel-multipart.c60
-rw-r--r--camel/camel-simple-data-wrapper.c150
-rw-r--r--camel/camel-stream-filter.c3
-rw-r--r--camel/providers/mbox/camel-mbox-folder.c13
-rw-r--r--camel/providers/mbox/camel-mbox-summary.c21
15 files changed, 765 insertions, 211 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 52a729deae..57def807c2 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,28 @@
+2000-04-23 NotZed <NotZed@HelixCode.com>
+
+ * camel-data-wrapper.c (set_mime_type_field): Ref the
+ content_field when we get it?
+
+ * camel-mime-parser.c (camel_mime_parser_unstep): New function.
+ Cause a subsequent call to mime_parser_step() to return the same
+ state over again.
+
+ * providers/mbox/camel-mbox-folder.c (_get_message_by_uid):
+ Initial test code using the mime parser to construct the message.
+
+ * camel-mime-part.c (construct_from_parser): part constructor.
+ (camel_mime_part_construct_content): Basically a simpler
+ replacement for the datawrapper repository.
+ (camel_mime_part_init): Set the default type to text/plain.
+
+ * camel-simple-data-wrapper.c (construct_from_parser): Initial
+ implementation of a content constructor.
+
+ * camel-multipart.c (construct_from_parser): Multipart
+ construction routine.
+ (camel_multipart_init): Set the default multipart type to
+ multipart/mixed. Duh, no subtype is not allowed anyway.
+
2000-04-22 Dan Winship <danw@helixcode.com>
* camel-multipart.[ch]: clean, document, etc.
@@ -6,6 +31,64 @@
2000-04-22 NotZed <NotZed@HelixCode.com>
+ * camel-mime-message.h (struct _CamelMimeMessage): Removed
+ send_date, and received_date, and replaced it with a time_t
+ 'date' (this is what the header is called), and date_offset to
+ store the GMT offset of the date.
+
+ * camel-mime-message.c (camel_mime_message_set_from): Update raw
+ header as we go.
+ (_set_from): Removed.
+ (_get_from): Removed.
+ (camel_mime_message_get_from): Moved implementation here.
+ (camel_mime_message_get_subject): Move implementation here.
+ (_get_subject): Nuked.
+ (camel_mime_message_set_subject): Handle utf-8 input, and also
+ update raw header when changed.
+ (_set_subject): Removed.
+ (_set_received_date): Removed.
+ (camel_mime_message_set_received_date): Removed.
+ (_get_received_date): Removed.
+ (camel_mime_message_get_received_date): Removed.
+ (_get_sent_date): Removed.
+ (camel_mime_message_get_sent_date): Removed.
+ (camel_mime_message_get_date): New function to get the date as a
+ time_t/offset.
+ (camel_mime_message_set_date): Set the date as a time_t/offset.
+ (camel_mime_message_get_date_string): Get the date as a string.
+ (camel_mime_message_init): Initialise the current date as
+ 'CMAEL_MESSAGE_DATE_CURRENT'.
+ (_set_reply_to): Removed.
+ (camel_mime_message_set_reply_to): Moved implementation here.
+ This is still broken, reply-to can have multiple addresses.
+ (_get_reply_to): Removed.
+ (_set_field): Removed, no longer used anywhere.
+ (_get_field): Also removed.
+ (_init_header_name_table): Add the Date header.
+ (process_header): Also handle snooping of Date header here.
+
+ * camel-stream-filter.c (finalise): Unref the source stream on
+ finalise, and also call the parent class (oops).
+
+ * camel-mime-parser.c (camel_mime_parser_state): New function to
+ get the current parser state.
+ (camel_mime_parser_stream): Allow you to get the stream back from
+ the mime_parser.
+ (camel_mime_parser_fd): Alternative to allow you to get the fd
+ back from the mime_parser.
+ (folder_scan_init_with_stream): Properly ref/unref the stream.
+ (folder_scan_close): Properly unref the stream/close the fd on
+ exit.
+ (folder_scan_init_with_fd): Close the old fd if there is one.
+
+ * camel-data-wrapper.c (camel_data_wrapper_construct_from_parser):
+ New method, construct a data wrapper from an initialised parser.
+ (construct_from_parser): Empty implementation.
+
+ * providers/mbox/camel-mbox-summary.c (message_struct_new):
+ Convert subject line to unicode, before storing in the summary.
+ (strdup_trim): Removed, no longer needed.
+
* providers/mbox/camel-mbox-folder.c (_get_message_by_uid): Ref
the folder after setting it in the new message.
@@ -18,8 +101,20 @@
(my_write_to_stream): Removed old code, all headers are now stored
in the camel-medium level, always. Need to do the same with
camel-mime-message i suppose ...
+ (my_write_to_stream): Write the content using the parent class,
+ not some weird function.
+ (camel_mime_part_class_init): Dont override get_output_stream.
+ (camel_mime_part_encoding_from_string): Bleh, make it
+ case-insensitive.
* camel-mime-utils.c (header_content_type_is): Handle empty types.
+ (header_encode_string): Start of an implementation of the rfc2047
+ encoder. It does iso-8859-1, and us-ascii, and utf-8 (others get
+ tricky *sigh*)
+ (rfc2047_encode_word): Convert a single word/string into rfc2047
+ encoding.
+ (quoted_encode): Different quoted-printable encoding for rfc2047
+ encoding of headers.
* gmime-content-field.c (gmime_content_field_write_to_stream): Use
header_content_type_format() to format it.
diff --git a/camel/camel-data-wrapper.c b/camel/camel-data-wrapper.c
index 4f071e9063..1cff54a7c1 100644
--- a/camel/camel-data-wrapper.c
+++ b/camel/camel-data-wrapper.c
@@ -29,6 +29,8 @@
#include <config.h>
#include "camel-data-wrapper.h"
+#define d(x)
+
static GtkObjectClass *parent_class = NULL;
/* Returns the class for a CamelDataWrapper */
@@ -44,6 +46,7 @@ static CamelStream *get_output_stream (CamelDataWrapper *data_wrapper);
static void construct_from_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
+static void construct_from_parser(CamelDataWrapper *, CamelMimeParser *);
static void write_to_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
static void set_mime_type (CamelDataWrapper *data_wrapper,
@@ -65,6 +68,7 @@ camel_data_wrapper_class_init (CamelDataWrapperClass *camel_data_wrapper_class)
/* virtual method definition */
camel_data_wrapper_class->write_to_stream = write_to_stream;
camel_data_wrapper_class->construct_from_stream = construct_from_stream;
+ camel_data_wrapper_class->construct_from_parser = construct_from_parser;
camel_data_wrapper_class->set_mime_type = set_mime_type;
camel_data_wrapper_class->get_mime_type = get_mime_type;
camel_data_wrapper_class->get_mime_type_field = get_mime_type_field;
@@ -207,6 +211,7 @@ set_output_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
gtk_object_ref (GTK_OBJECT (stream));
gtk_object_sink (GTK_OBJECT (stream));
}
+ d(printf("data_wrapper:: set_output_stream(%p)\n", stream));
}
/**
@@ -236,6 +241,7 @@ camel_data_wrapper_set_output_stream (CamelDataWrapper *data_wrapper,
static CamelStream *
get_output_stream (CamelDataWrapper *data_wrapper)
{
+ d(printf("data_wrapper:: get_output_stream(%p) = %p\n", data_wrapper, data_wrapper->output_stream));
return data_wrapper->output_stream;
}
@@ -262,14 +268,19 @@ write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
gint nb_written;
CamelStream *output_stream;
+ d(printf("data_wrapper::write_to_stream\n"));
+
output_stream = camel_data_wrapper_get_output_stream (data_wrapper);
- if (!output_stream)
+ if (!output_stream) {
+ g_warning("write to stream with no stream");
return;
+ }
camel_stream_reset (output_stream);
while (!camel_stream_eos (output_stream)) {
nb_read = camel_stream_read (output_stream, tmp_buf, 4096);
+ d(printf("copying %d bytes\n", nb_read));
nb_written = 0;
while (nb_written < nb_read)
nb_written += camel_stream_write (stream, tmp_buf + nb_written, nb_read - nb_written);
@@ -418,6 +429,8 @@ set_mime_type_field (CamelDataWrapper *data_wrapper,
if (data_wrapper->mime_type)
gmime_content_field_unref (data_wrapper->mime_type);
data_wrapper->mime_type = mime_type;
+ if (mime_type)
+ gmime_content_field_ref (data_wrapper->mime_type);
}
void
@@ -427,3 +440,16 @@ camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
CDW_CLASS (data_wrapper)->set_mime_type_field (data_wrapper,
mime_type);
}
+
+static void construct_from_parser(CamelDataWrapper *d, CamelMimeParser *mp)
+{
+ /* do nothing? */
+ g_warning("Construct from parser not implemented for: %s", gtk_type_name(((GtkObject *)d)->klass->type));
+}
+
+void
+camel_data_wrapper_construct_from_parser(CamelDataWrapper *data_wrapper, CamelMimeParser *mp)
+{
+ CDW_CLASS (data_wrapper)->construct_from_parser (data_wrapper, mp);
+}
+
diff --git a/camel/camel-data-wrapper.h b/camel/camel-data-wrapper.h
index 0805bc47ce..0af3e73362 100644
--- a/camel/camel-data-wrapper.h
+++ b/camel/camel-data-wrapper.h
@@ -37,7 +37,7 @@ extern "C" {
#include <gtk/gtk.h>
#include "camel-types.h"
#include "gmime-content-field.h"
-
+#include <camel/camel-mime-parser.h>
#define CAMEL_DATA_WRAPPER_TYPE (camel_data_wrapper_get_type ())
#define CAMEL_DATA_WRAPPER(obj) (GTK_CHECK_CAST((obj), CAMEL_DATA_WRAPPER_TYPE, CamelDataWrapper))
@@ -83,6 +83,9 @@ typedef struct {
void (*construct_from_stream) (CamelDataWrapper *data_wrapper,
CamelStream *stream);
+ void (*construct_from_parser) (CamelDataWrapper *data_wrapper,
+ CamelMimeParser *);
+
} CamelDataWrapperClass;
@@ -110,6 +113,9 @@ void camel_data_wrapper_set_output_stream (CamelDataWrappe
CamelStream * camel_data_wrapper_get_output_stream (CamelDataWrapper *data_wrapper);
+void camel_data_wrapper_construct_from_parser (CamelDataWrapper *data_wrapper,
+ CamelMimeParser *);
+
/* deprecated methods. Left until the new parser scheme is ok */
void camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c
index 7ae14766d5..6561515ec3 100644
--- a/camel/camel-mime-message.c
+++ b/camel/camel-mime-message.c
@@ -1,11 +1,9 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* camelMimeMessage.c : class for a mime_message */
-
/*
- *
- * Author :
- * Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Michael Zucchi <notzed@helixcode.com>
*
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
*
@@ -24,6 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
+
#include <config.h>
#include "camel-mime-message.h"
#include <stdio.h>
@@ -39,30 +38,21 @@ typedef enum {
HEADER_SUBJECT,
HEADER_TO,
HEADER_CC,
- HEADER_BCC
+ HEADER_BCC,
+ HEADER_DATE
} CamelHeaderType;
static GHashTable *header_name_table;
-
-
static CamelMimePartClass *parent_class=NULL;
+/* WTF are these for?? */
static gchar *received_date_str;
static gchar *sent_date_str;
static gchar *reply_to_str;
static gchar *subject_str;
static gchar *from_str;
-static void _set_received_date (CamelMimeMessage *mime_message, const gchar *received_date);
-static const gchar *_get_received_date (CamelMimeMessage *mime_message);
-static const gchar *_get_sent_date (CamelMimeMessage *mime_message);
-static void _set_reply_to (CamelMimeMessage *mime_message, const gchar *reply_to);
-static const gchar *_get_reply_to (CamelMimeMessage *mime_message);
-static void _set_subject (CamelMimeMessage *mime_message, const gchar *subject);
-static const gchar *_get_subject (CamelMimeMessage *mime_message);
-static void _set_from (CamelMimeMessage *mime_message, const gchar *from);
-static const gchar *_get_from (CamelMimeMessage *mime_message);
static void _add_recipient (CamelMimeMessage *mime_message, const gchar *recipient_type, const gchar *recipient);
static void _remove_recipient (CamelMimeMessage *mime_message, const gchar *recipient_type, const gchar *recipient);
static const GList *_get_recipients (CamelMimeMessage *mime_message, const gchar *recipient_type);
@@ -80,6 +70,7 @@ static void remove_header (CamelMedium *medium, const char *header_name);
/* Returns the class for a CamelMimeMessage */
#define CMM_CLASS(so) CAMEL_MIME_MESSAGE_CLASS (GTK_OBJECT(so)->klass)
#define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (GTK_OBJECT(so)->klass)
+#define CMD_CLASS(so) CAMEL_MEDIUM_CLASS (GTK_OBJECT(so)->klass)
static void
@@ -92,7 +83,7 @@ _init_header_name_table()
g_hash_table_insert (header_name_table, "To", (gpointer)HEADER_TO);
g_hash_table_insert (header_name_table, "Cc", (gpointer)HEADER_CC);
g_hash_table_insert (header_name_table, "Bcc", (gpointer)HEADER_BCC);
-
+ g_hash_table_insert (header_name_table, "Date", (gpointer)HEADER_DATE);
}
static void
@@ -113,15 +104,6 @@ camel_mime_message_class_init (CamelMimeMessageClass *camel_mime_message_class)
from_str = "From";
/* virtual method definition */
- camel_mime_message_class->set_received_date = _set_received_date;
- camel_mime_message_class->get_received_date = _get_received_date;
- camel_mime_message_class->get_sent_date = _get_sent_date;
- camel_mime_message_class->set_reply_to = _set_reply_to;
- camel_mime_message_class->get_reply_to = _get_reply_to;
- camel_mime_message_class->set_subject = _set_subject;
- camel_mime_message_class->get_subject = _get_subject;
- camel_mime_message_class->set_from = _set_from;
- camel_mime_message_class->get_from = _get_from;
camel_mime_message_class->add_recipient = _add_recipient;
camel_mime_message_class->remove_recipient = _remove_recipient;
camel_mime_message_class->get_recipients = _get_recipients;
@@ -156,12 +138,13 @@ camel_mime_message_init (gpointer object, gpointer klass)
camel_mime_message->flags =
g_hash_table_new (g_strcase_hash, g_strcase_equal);
- camel_mime_message->received_date = NULL;
- camel_mime_message->sent_date = NULL;
camel_mime_message->subject = NULL;
camel_mime_message->reply_to = NULL;
camel_mime_message->from = NULL;
camel_mime_message->folder = NULL;
+ camel_mime_message->date = CAMEL_MESSAGE_DATE_CURRENT;
+ camel_mime_message->date_offset = 0;
+ camel_mime_message->date_str = NULL;
}
GtkType
@@ -194,8 +177,7 @@ _finalize (GtkObject *object)
{
CamelMimeMessage *message = CAMEL_MIME_MESSAGE (object);
- g_free (message->received_date);
- g_free (message->sent_date);
+ g_free (message->date_str);
g_free (message->subject);
g_free (message->reply_to);
g_free (message->from);
@@ -222,182 +204,118 @@ camel_mime_message_new (void)
}
-/* some utils func */
+/* **** Date: */
-static void
-_set_field (CamelMimeMessage *mime_message, gchar *name, const gchar *value, gchar **variable)
-{
- if (variable) {
- g_free (*variable);
- if (value)
- *variable = g_strdup (value);
- else
- *variable = NULL;
+void
+camel_mime_message_set_date(CamelMimeMessage *message, time_t date, int offset)
+{
+ g_assert(message);
+ if (date == CAMEL_MESSAGE_DATE_CURRENT) {
+ struct tm *local;
+ int tz;
+
+ date = time(0);
+ local = localtime(&date);
+ offset = 0;
+#if defined(HAVE_TIMEZONE)
+ tz = timezone;
+#elif defined(HAVE_TM_GMTOFF)
+ tz = local->tm_gmtoff;
+#endif
+ offset = ((tz/60/60) * 100) + (tz/60 % 60);
}
-}
+ message->date = date;
+ message->date_offset = offset;
+ g_free(message->date_str);
+ message->date_str = header_format_date(date, offset);
-/* for future use */
-/* for the moment, only @variable is used */
-static gchar *
-_get_field (CamelMimeMessage *mime_message, gchar *name, gchar *variable)
-{
- return variable;
-}
-
-/* * */
-
-
-static void
-_set_received_date (CamelMimeMessage *mime_message, const gchar *received_date)
-{
- _set_field (mime_message, received_date_str, received_date, &(mime_message->received_date));
+ CMD_CLASS(parent_class)->set_header((CamelMedium *)message, "Date", message->date_str);
}
void
-camel_mime_message_set_received_date (CamelMimeMessage *mime_message, const gchar *received_date)
-{
- g_assert (mime_message);
- g_return_if_fail (!mime_message->expunged);
- CMM_CLASS (mime_message)->set_received_date (mime_message, received_date);
-}
-
-
-static const gchar *
-_get_received_date (CamelMimeMessage *mime_message)
-{
- return _get_field (mime_message, received_date_str, mime_message->received_date);
-}
-
-const gchar *
-camel_mime_message_get_received_date (CamelMimeMessage *mime_message)
-{
- g_assert (mime_message);
- g_return_val_if_fail (!mime_message->expunged, NULL);
- return CMM_CLASS (mime_message)->get_received_date (mime_message);
-}
-
-
-static const gchar *
-_get_sent_date (CamelMimeMessage *mime_message)
+camel_mime_message_get_date(CamelMimeMessage *message, time_t *date, int *offset)
{
- return _get_field (mime_message, sent_date_str, mime_message->sent_date);
+ if (message->date == CAMEL_MESSAGE_DATE_CURRENT)
+ camel_mime_message_set_date(message, CAMEL_MESSAGE_DATE_CURRENT, 0);
+ if (date)
+ *date = message->date;
+ if (offset)
+ *offset = message->date_offset;
}
-const gchar *
-camel_mime_message_get_sent_date (CamelMimeMessage *mime_message)
+char *
+camel_mime_message_get_date_string(CamelMimeMessage *message)
{
- g_assert (mime_message);
- g_return_val_if_fail (!mime_message->expunged, NULL);
- return CMM_CLASS (mime_message)->get_sent_date (mime_message);
+ if (message->date == CAMEL_MESSAGE_DATE_CURRENT)
+ camel_mime_message_set_date(message, CAMEL_MESSAGE_DATE_CURRENT, 0);
+ return message->date_str;
}
-
-static void
-_set_reply_to (CamelMimeMessage *mime_message, const gchar *reply_to)
-{
- _set_field (mime_message, reply_to_str, reply_to, &(mime_message->reply_to));
-}
+/* **** Reply-To: */
void
camel_mime_message_set_reply_to (CamelMimeMessage *mime_message, const gchar *reply_to)
{
g_assert (mime_message);
- g_return_if_fail (!mime_message->expunged);
- CMM_CLASS (mime_message)->set_reply_to (mime_message, reply_to);
-}
+ /* FIXME: check format of string, handle it nicer ... */
-static const gchar *
-_get_reply_to (CamelMimeMessage *mime_message)
-{
- return _get_field (mime_message, reply_to_str, mime_message->reply_to);
+ g_free(mime_message->reply_to);
+ mime_message->reply_to = g_strdup(reply_to);
+ CMD_CLASS(parent_class)->set_header((CamelMedium *)mime_message, "Reply-To", reply_to);
}
const gchar *
camel_mime_message_get_reply_to (CamelMimeMessage *mime_message)
{
g_assert (mime_message);
- g_return_val_if_fail (!mime_message->expunged, NULL);
- return CMM_CLASS (mime_message)->get_reply_to (mime_message);
-}
-
-
-
-static void
-_set_subject (CamelMimeMessage *mime_message, const gchar *subject)
-{
- _set_field (mime_message, subject_str, subject, &(mime_message->subject));
+ return mime_message->reply_to;
}
void
camel_mime_message_set_subject (CamelMimeMessage *mime_message,
const gchar *subject)
{
+ char *text;
g_assert (mime_message);
- g_return_if_fail (!mime_message->expunged);
- CMM_CLASS (mime_message)->set_subject (mime_message, subject);
-}
-
-static const gchar *
-_get_subject (CamelMimeMessage *mime_message)
-{
- return _get_field (mime_message, subject_str, mime_message->subject);
+ g_free(mime_message->subject);
+ mime_message->subject = g_strdup(subject);
+ text = header_encode_string(subject);
+ CMD_CLASS(parent_class)->set_header((CamelMedium *)mime_message, "Subject", text);
+ g_free(text);
}
const gchar *
camel_mime_message_get_subject (CamelMimeMessage *mime_message)
{
g_assert (mime_message);
- g_return_val_if_fail (!mime_message->expunged, NULL);
- return CMM_CLASS (mime_message)->get_subject (mime_message);
-}
-
-
-
-static void
-_set_from (CamelMimeMessage *mime_message, const gchar *from)
-{
- _set_field (mime_message, from_str, from, &(mime_message->from));
+ return mime_message->subject;
}
+/* *** From: */
void
camel_mime_message_set_from (CamelMimeMessage *mime_message, const gchar *from)
{
g_assert (mime_message);
- g_return_if_fail (!mime_message->expunged);
- CMM_CLASS (mime_message)->set_from (mime_message, from);
-}
-
-static const gchar *
-_get_from (CamelMimeMessage *mime_message)
-{
- return _get_field (mime_message, from_str, mime_message->from);
+ g_free(mime_message->from);
+ mime_message->from = g_strdup(from);
+ CMD_CLASS(parent_class)->set_header((CamelMedium *)mime_message, "From", from);
}
const gchar *
camel_mime_message_get_from (CamelMimeMessage *mime_message)
{
g_assert (mime_message);
- g_return_val_if_fail (!mime_message->expunged, NULL);
- return CMM_CLASS (mime_message)->get_from (mime_message);
-}
-
-
-
-
-
+ return mime_message->from;
+}
/* **** */
-
-
-
-
static void
_add_recipient (CamelMimeMessage *mime_message,
const gchar *recipient_type,
@@ -588,13 +506,33 @@ _write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
{
CamelMimeMessage *mm = CAMEL_MIME_MESSAGE (data_wrapper);
+#if 0
#warning each header should be stored in the raw headers
WHPT (stream, "From", mm->from);
WHPT (stream, "Reply-To", mm->reply_to);
- _write_recipients_to_stream (mm, stream);
WHPT (stream, "Date", mm->received_date);
WHPT (stream, "Subject", mm->subject);
+#endif
+ /* force mandatory headers ... */
+ if (mm->from == NULL) {
+ g_warning("No from set for message");
+ camel_mime_message_set_from(mm, "");
+ }
+ if (mm->date_str == NULL) {
+ g_warning("Application did not set date, using 'now'");
+ camel_mime_message_set_date(mm, CAMEL_MESSAGE_DATE_CURRENT, 0);
+ }
+ if (mm->subject == NULL) {
+ g_warning("Application did not set subject, creating one");
+ camel_mime_message_set_subject(mm, "No Subject");
+ }
+
+#warning need to store receipients lists to headers
+#if 0
+ /* FIXME: remove this snot ... */
+ _write_recipients_to_stream (mm, stream);
+#endif
/* FIXME correct to do it here? */
WHPT (stream, "Mime-Version", "1.0");
@@ -630,13 +568,16 @@ process_header(CamelMedium *medium, const char *header_name, const char *header_
header_type = (CamelHeaderType) g_hash_table_lookup (header_name_table, header_name);
switch (header_type) {
case HEADER_FROM:
- camel_mime_message_set_from (message, header_value);
+ g_free(message->from); /* FIXME: parse the from line into something useful */
+ message->from = g_strdup(header_value);
break;
case HEADER_REPLY_TO:
- camel_mime_message_set_reply_to (message, header_value);
+ g_free(message->reply_to); /* FIXME: parse the from line into something useful */
+ message->reply_to = g_strdup(header_value);
break;
case HEADER_SUBJECT:
- camel_mime_message_set_subject (message, header_value);
+ g_free(message->subject);
+ message->subject = header_decode_string(header_value);
break;
case HEADER_TO:
if (header_value)
@@ -656,6 +597,15 @@ process_header(CamelMedium *medium, const char *header_name, const char *header_
else
camel_recipient_table_remove_type (message->recipients, "Bcc");
break;
+ case HEADER_DATE:
+ g_free(message->date_str);
+ message->date_str = g_strdup(header_value);
+ if (header_value) {
+ message->date = header_decode_date(header_value, &message->date_offset);
+ } else {
+ message->date = CAMEL_MESSAGE_DATE_CURRENT;
+ }
+ break;
default:
return FALSE;
}
diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h
index 691f2e0059..ddcf846c20 100644
--- a/camel/camel-mime-message.h
+++ b/camel/camel-mime-message.h
@@ -51,14 +51,17 @@ extern "C" {
#define CAMEL_IS_MIME_MESSAGE(o) (GTK_CHECK_TYPE((o), CAMEL_MIME_MESSAGE_TYPE))
+/* specify local time */
+#define CAMEL_MESSAGE_DATE_CURRENT (~0)
struct _CamelMimeMessage
{
CamelMimePart parent_object;
/* header fields */
- gchar *received_date;
- gchar *sent_date;
+ time_t date;
+ int date_offset; /* GMT offset */
+ char *date_str; /* cached copy of date string */
gchar *subject;
gchar *reply_to;
@@ -126,8 +129,10 @@ GtkType camel_mime_message_get_type (void);
CamelMimeMessage * camel_mime_message_new (void);
-void camel_mime_message_set_received_date (CamelMimeMessage *mime_message,
- const gchar *received_date);
+void camel_mime_message_set_date (CamelMimeMessage *mime_message, time_t date, int offset);
+void camel_mime_message_get_date (CamelMimeMessage *mime_message, time_t *date, int *offset);
+char *camel_mime_message_get_date_string (CamelMimeMessage *mime_message);
+
const gchar * camel_mime_message_get_received_date (CamelMimeMessage *mime_message);
const gchar * camel_mime_message_get_sent_date (CamelMimeMessage *mime_message);
void camel_mime_message_set_reply_to (CamelMimeMessage *mime_message,
diff --git a/camel/camel-mime-parser.c b/camel/camel-mime-parser.c
index 3ed9dde427..2f1d9fd70d 100644
--- a/camel/camel-mime-parser.c
+++ b/camel/camel-mime-parser.c
@@ -73,6 +73,7 @@ struct _header_scan_state {
int atleast;
int seek; /* current offset to start of buffer */
+ int unstep; /* how many states to 'unstep' (repeat the current state) */
int midline; /* are we mid-line interrupted? */
int scan_from; /* do we care about From lines? */
@@ -323,12 +324,27 @@ camel_mime_parser_content_type(CamelMimeParser *m)
return NULL;
}
+void camel_mime_parser_unstep(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+
+ s->unstep++;
+}
+
enum _header_state
camel_mime_parser_step(CamelMimeParser *m, char **databuffer, int *datalength)
{
struct _header_scan_state *s = _PRIVATE(m);
- folder_scan_step(s, databuffer, datalength);
+ d(printf("OLD STATE: '%s' :\n", states[s->state]));
+
+ if (s->unstep <= 0)
+ folder_scan_step(s, databuffer, datalength);
+ else
+ s->unstep--;
+
+ d(printf("NEW STATE: '%s' :\n", states[s->state]));
+
return s->state;
}
@@ -359,6 +375,24 @@ off_t camel_mime_parser_seek(CamelMimeParser *m, off_t off, int whence)
return folder_seek(s, off, whence);
}
+enum _header_state camel_mime_parser_state(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+ return s->state;
+}
+
+CamelStream *camel_mime_parser_stream(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+ return s->stream;
+}
+
+int camel_mime_parser_fd(CamelMimeParser *m)
+{
+ struct _header_scan_state *s = _PRIVATE(m);
+ return s->fd;
+}
+
/* ********************************************************************** */
/* Implementation */
/* ********************************************************************** */
@@ -613,7 +647,8 @@ retry:
goto header_done;
}
- if (s->outptr[0] == '\n' && s->outptr>s->outbuf)
+ /* we always have at least _1_ char here ... */
+ if (s->outptr[-1] == '\n')
s->outptr--;
s->outptr[0] = 0;
@@ -676,7 +711,7 @@ header_truncated:
memcpy(s->outptr, start, headerlen);
s->outptr += headerlen;
}
- if (s->outptr[0] == '\n' && s->outptr>s->outbuf)
+ if (s->outptr>s->outbuf && s->outptr[-1] == '\n')
s->outptr--;
s->outptr[0] = 0;
@@ -832,6 +867,10 @@ folder_scan_close(struct _header_scan_state *s)
g_free(s->outbuf);
while (s->parts)
folder_pull_part(s);
+ if (s->fd != -1)
+ close(s->fd);
+ if (s->stream)
+ gtk_object_unref((GtkObject *)s->stream);
g_free(s);
}
@@ -857,6 +896,7 @@ folder_scan_init(void)
s->atleast = 0;
s->seek = 0; /* current character position in file of the last read block */
+ s->unstep = 0;
s->header_start = -1;
@@ -883,6 +923,8 @@ folder_scan_init_with_fd(struct _header_scan_state *s, int fd)
len = read(fd, s->inbuf, SCAN_BUF);
if (len>=0) {
s->inend = s->inbuf+len;
+ if (s->fd != -1)
+ close(s->fd);
s->fd = fd;
if (s->stream) {
gtk_object_unref((GtkObject *)s->stream);
@@ -902,7 +944,10 @@ folder_scan_init_with_stream(struct _header_scan_state *s, CamelStream *stream)
len = camel_stream_read(stream, s->inbuf, SCAN_BUF);
if (len>=0) {
s->inend = s->inbuf+len;
+ if (s->stream)
+ gtk_object_unref((GtkObject *)s->stream);
s->stream = stream;
+ gtk_object_ref((GtkObject *)stream);
if (s->fd != -1) {
close(s->fd);
s->fd = -1;
diff --git a/camel/camel-mime-parser.h b/camel/camel-mime-parser.h
index d42ea4709c..f8964ed86c 100644
--- a/camel/camel-mime-parser.h
+++ b/camel/camel-mime-parser.h
@@ -79,11 +79,17 @@ CamelMimeParser *camel_mime_parser_new (void);
int camel_mime_parser_init_with_fd(CamelMimeParser *, int fd);
int camel_mime_parser_init_with_stream(CamelMimeParser *m, CamelStream *stream);
+/* get the stream or fd back of the parser */
+CamelStream *camel_mime_parser_stream(CamelMimeParser *m);
+int camel_mime_parser_fd(CamelMimeParser *m);
+
/* scan 'From' separators? */
void camel_mime_parser_scan_from(CamelMimeParser *, int);
/* normal interface */
enum _header_state camel_mime_parser_step(CamelMimeParser *, char **, int *);
+void camel_mime_parser_unstep(CamelMimeParser *);
+enum _header_state camel_mime_parser_state(CamelMimeParser *);
/* get content type for the current part/header */
struct _header_content_type *camel_mime_parser_content_type(CamelMimeParser *);
diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c
index bda4f932ed..78f1897e8b 100644
--- a/camel/camel-mime-part.c
+++ b/camel/camel-mime-part.c
@@ -37,7 +37,16 @@
#include "camel-seekable-substream.h"
#include "camel-stream-filter.h"
#include "camel-mime-filter-basic.h"
+#include "camel-mime-filter-charset.h"
#include <ctype.h>
+#include "camel-mime-parser.h"
+
+/* ick, this shouldn't need to know about the parent types ... then again the repository does *sigh* */
+#include "camel-mime-message.h"
+#include "camel-multipart.h"
+#include "camel-mime-body-part.h"
+
+#define d(x)
typedef enum {
HEADER_UNKNOWN,
@@ -69,6 +78,7 @@ static void my_write_to_stream (CamelDataWrapper *data_w
CamelStream *stream);
static void my_construct_from_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
+static void construct_from_parser (CamelDataWrapper *, CamelMimeParser *);
static void my_set_input_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
static CamelStream * my_get_output_stream (CamelDataWrapper *data_wrapper);
@@ -122,8 +132,9 @@ camel_mime_part_class_init (CamelMimePartClass *camel_mime_part_class)
camel_data_wrapper_class->write_to_stream = my_write_to_stream;
camel_data_wrapper_class->construct_from_stream = my_construct_from_stream;
+ camel_data_wrapper_class->construct_from_parser = construct_from_parser;
camel_data_wrapper_class->set_input_stream = my_set_input_stream;
- camel_data_wrapper_class->get_output_stream = my_get_output_stream;
+/* camel_data_wrapper_class->get_output_stream = my_get_output_stream;*/
gtk_object_class->finalize = my_finalize;
}
@@ -133,7 +144,7 @@ camel_mime_part_init (gpointer object, gpointer klass)
{
CamelMimePart *camel_mime_part = CAMEL_MIME_PART (object);
- camel_mime_part->content_type = gmime_content_field_new (NULL, NULL);
+ camel_mime_part->content_type = gmime_content_field_new ("text", "plain");
camel_mime_part->description = NULL;
camel_mime_part->disposition = NULL;
camel_mime_part->content_id = NULL;
@@ -224,7 +235,7 @@ process_header(CamelMedium *medium, const char *header_name, const char *header_
break;
case HEADER_ENCODING:
text = header_token_decode(header_value);
- camel_mime_part_set_encoding(mime_part, camel_mime_part_encoding_from_string (text));
+ mime_part->encoding = camel_mime_part_encoding_from_string (text);
g_free(text);
break;
case HEADER_CONTENT_MD5:
@@ -498,10 +509,14 @@ my_get_content_object (CamelMedium *medium)
CamelStream *decoded_stream;
CamelMimeFilter *mf = NULL;
+ d(printf("getting content object? for %p\n", medium));
+
if (!medium->content ) {
stream = mime_part->content_input_stream;
decoded_stream = stream;
+ g_warning("No content object, this old code is probably going to crash ...");
+
switch (mime_part->encoding) {
case CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE:
mf = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_DEC);
@@ -606,8 +621,7 @@ my_write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
CamelMimePart *mp = CAMEL_MIME_PART (data_wrapper);
CamelMedium *medium = CAMEL_MEDIUM (data_wrapper);
- /* FIXME: something needs to be done about this ... */
- gmime_write_header_with_glist_to_stream (stream, "Content-Language", mp->content_languages,", ");
+ d(printf("mime_part::write_to_stream\n"));
#warning This class should NOT BE WRITING the headers out
if (medium->headers) {
@@ -618,8 +632,24 @@ my_write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
}
}
+ /* FIXME: something needs to be done about this ... */
+ gmime_write_header_with_glist_to_stream (stream, "Content-Language", mp->content_languages,", ");
+
camel_stream_write_string(stream,"\n");
- my_write_content_to_stream (mp, stream);
+
+#if 1
+ {
+ CamelDataWrapper *content = camel_medium_get_content_object (CAMEL_MEDIUM (data_wrapper));
+ if (content) {
+ camel_data_wrapper_write_to_stream(content, stream);
+ } else {
+ g_warning("No content for data wrapper");
+ }
+ }
+#else
+ ((CamelDataWrapperClass *)parent_class)->write_to_stream (data_wrapper, stream);
+#endif
+ /*my_write_content_to_stream (mp, stream);*/
}
@@ -636,7 +666,76 @@ my_construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
}
+/* FIXME: this should be in another file ... */
+/* This replaces the data wrapper repository ... and/or could be replaced by it? */
+static void
+camel_mime_part_construct_content(CamelDataWrapper *dw, CamelMimeParser *mp)
+{
+ CamelDataWrapper *content = NULL;
+ int state;
+ switch ((state = camel_mime_parser_state(mp))) {
+ case HSCAN_HEADER:
+ d(printf("Creating body part\n"));
+ content = (CamelDataWrapper *)camel_simple_data_wrapper_new();
+ break;
+ case HSCAN_MESSAGE:
+ d(printf("Creating message part\n"));
+ content = (CamelDataWrapper *)camel_mime_message_new();
+ break;
+ case HSCAN_MULTIPART:
+ d(printf("Creating multi-part\n"));
+ content = (CamelDataWrapper *)camel_multipart_new();
+ break;
+ default:
+ g_warning("Invalid state encountered???: %d", camel_mime_parser_state(mp));
+ }
+ if (content) {
+ camel_data_wrapper_construct_from_parser(content, mp);
+#warning there just has got to be a better way ... to transfer the mime-type to the datawrapper
+ /* would you believe you have to set this BEFORE you set the content object??? oh my god !!!! */
+ camel_data_wrapper_set_mime_type_field (content,
+ camel_mime_part_get_content_type ((CamelMimePart *)dw));
+ camel_medium_set_content_object((CamelMedium *)dw, content);
+ }
+ /* this should probably go into camel-mime-message::construct_from_parser */
+ if (state == HSCAN_MESSAGE) {
+ char *buf;
+ int len;
+
+ if (camel_mime_parser_step(mp, &buf, &len) != HSCAN_MESSAGE_END) {
+ g_warning("Bad parser state: Expecing MESSAGE_EOF, got: %d", camel_mime_parser_state(mp));
+ camel_mime_parser_unstep(mp);
+ }
+ }
+}
+
+/* mime_part */
+static void
+construct_from_parser(CamelDataWrapper *dw, CamelMimeParser *mp)
+{
+ struct _header_raw *headers;
+ char *buf;
+ int len;
+
+ d(printf("constructing mime-part\n"));
+
+ switch (camel_mime_parser_step(mp, &buf, &len)) {
+ case HSCAN_HEADER:
+ case HSCAN_MESSAGE:
+ case HSCAN_MULTIPART:
+ /* we have the headers, build them into 'us' */
+ headers = camel_mime_parser_headers_raw(mp);
+ while (headers) {
+ camel_medium_add_header((CamelMedium *)dw, headers->name, headers->value);
+ headers = headers->next;
+ }
+ camel_mime_part_construct_content(dw, mp);
+ break;
+ default:
+ g_warning("Invalid state encountered???: %d", camel_mime_parser_state(mp));
+ }
+}
static void
my_set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
@@ -734,13 +833,13 @@ camel_mime_part_encoding_from_string (const gchar *string)
{
if (string == NULL)
return CAMEL_MIME_PART_ENCODING_DEFAULT;
- else if (strcmp (string, "7bit") == 0)
+ else if (strcasecmp (string, "7bit") == 0)
return CAMEL_MIME_PART_ENCODING_7BIT;
- else if (strcmp (string, "8bit") == 0)
+ else if (strcasecmp (string, "8bit") == 0)
return CAMEL_MIME_PART_ENCODING_8BIT;
- else if (strcmp (string, "base64") == 0)
+ else if (strcasecmp (string, "base64") == 0)
return CAMEL_MIME_PART_ENCODING_BASE64;
- else if (strcmp (string, "quoted-printable") == 0)
+ else if (strcasecmp (string, "quoted-printable") == 0)
return CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE;
else
/* FIXME? Spit a warning? */
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
index 7b1ad93cd0..25970e58a0 100644
--- a/camel/camel-mime-utils.c
+++ b/camel/camel-mime-utils.c
@@ -34,6 +34,7 @@
#include <time.h>
#include <ctype.h>
+#include <errno.h>
#include "camel-mime-utils.h"
@@ -586,6 +587,35 @@ quoted_decode(const unsigned char *in, int len, unsigned char *out)
return -1;
}
+/* rfc2047 version of quoted-printable */
+static int
+quoted_encode(const unsigned char *in, int len, unsigned char *out)
+{
+ register const unsigned char *inptr, *inend;
+ unsigned char *outptr;
+ unsigned char c;
+
+ inptr = in;
+ inend = in+len;
+ outptr = out;
+ while (inptr<inend) {
+ c = *inptr++;
+ if (is_qpsafe(c) && !(c=='_' || c=='?')) {
+ if (c==' ')
+ c='_';
+ *outptr++=c;
+ } else {
+ *outptr++ = '=';
+ *outptr++ = tohex[(c>>4) & 0xf];
+ *outptr++ = tohex[c & 0xf];
+ }
+ }
+
+ printf("encoding '%.*s' = '%.*s'\n", len, in, outptr-out, out);
+
+ return outptr-out;
+}
+
static void
header_decode_lwsp(const char **in)
@@ -736,6 +766,7 @@ header_decode_text(const char *in, int inlen)
encstart = out->str;
g_string_free(out, FALSE);
+
return encstart;
}
@@ -747,6 +778,125 @@ header_decode_string(const char *in)
return header_decode_text(in, strlen(in));
}
+static char *encoding_map[] = {
+ "US-ASCII",
+ "ISO-8859-1",
+ "UTF-8"
+};
+
+/* FIXME: needs a way to cache iconv opens for different charsets? */
+static
+char *rfc2047_encode_word(const char *in, int len, char *type)
+{
+ unicode_iconv_t ic;
+ char *buffer, *out, *ascii;
+ size_t inlen, outlen, enclen;
+
+ printf("Converting '%.*s' to %s\n", len, in, type);
+
+ /* convert utf8->encoding */
+ outlen = len*6;
+ buffer = alloca(outlen);
+ inlen = len;
+ out = buffer;
+
+ /* if we can't convert from utf-8, just encode as utf-8 */
+ if (!strcasecmp(type, "UTF-8")
+ || (ic = unicode_iconv_open(type, "UTF-8")) == (unicode_iconv_t)-1) {
+ memcpy(buffer, in, len);
+ out = buffer+len;
+ type = "UTF-8";
+ } else {
+ if (unicode_iconv(ic, &in, &inlen, &out, &outlen) == -1) {
+ g_warning("Conversion problem: conversion truncated: %s", strerror(errno));
+ }
+ unicode_iconv_close(ic);
+ }
+ enclen = out-buffer;
+
+ /* now create qp version */
+ ascii = alloca(enclen*3 + strlen(type) + 8);
+ out = ascii;
+ /* should determine which encoding is smaller, and use that? */
+ out += sprintf(out, "=?%s?Q?", type);
+ out += quoted_encode(buffer, enclen, out);
+ sprintf(out, "?=");
+
+ printf("converted = %s\n", ascii);
+ return g_strdup(ascii);
+}
+
+
+/* TODO: Should this worry about quotes?? */
+char *
+header_encode_string(const unsigned char *in)
+{
+ GString *out;
+ const unsigned char *inptr = in, *start;
+ int encoding;
+ char *outstr;
+
+ if (in == NULL)
+ return NULL;
+
+ /* do a quick us-ascii check (the common case?) */
+ while (*inptr) {
+ if (*inptr > 127)
+ break;
+ inptr++;
+ }
+ if (*inptr == 0)
+ return g_strdup(in);
+
+ /* This gets each word out of the input, and checks to see what charset
+ can be used to encode it. */
+ /* TODO: Work out when to merge subsequent words, or across word-parts */
+ /* FIXME: Make sure a converted word is less than the encoding size */
+ out = g_string_new("");
+ inptr = in;
+ encoding = 0;
+ start = inptr;
+ while (inptr && *inptr) {
+ unicode_char_t c;
+ const char *newinptr;
+ newinptr = unicode_get_utf8(inptr, &c);
+ if (newinptr == NULL) {
+ g_warning("Invalid UTF-8 sequence encountered (pos %d, char '%c'): %s", (inptr-in), inptr[0], in);
+ inptr++;
+ continue;
+ }
+ inptr = newinptr;
+ if (unicode_isspace(c)) {
+ if (encoding == 0) {
+ g_string_append_len(out, start, inptr-start);
+ } else {
+ char *text = rfc2047_encode_word(start, inptr-start-1, encoding_map[encoding]);
+ g_string_append(out, text);
+ g_string_append_c(out, c);
+ g_free(text);
+ }
+ start = inptr;
+ encoding = 0;
+ } else if (c>127 && c < 256) {
+ encoding = MAX(encoding, 1);
+ } else if (c >=256) {
+ encoding = MAX(encoding, 2);
+ }
+ }
+ if (inptr-start) {
+ if (encoding == 0) {
+ g_string_append_len(out, start, inptr-start);
+ } else {
+ char *text = rfc2047_encode_word(start, inptr-start, encoding_map[encoding]);
+ g_string_append(out, text);
+ g_free(text);
+ }
+ }
+ outstr = out->str;
+ g_string_free(out, FALSE);
+ return outstr;
+}
+
/* these are all internal parser functions */
@@ -976,8 +1126,6 @@ void header_content_type_set_param(struct _header_content_type *t, const char *n
int
header_content_type_is(struct _header_content_type *ct, const char *type, const char *subtype)
{
- printf("type = %s / %s\n", type, subtype);
-
/* no type == text/plain or text/"*" */
if (ct==NULL) {
return (!strcasecmp(type, "text")
diff --git a/camel/camel-mime-utils.h b/camel/camel-mime-utils.h
index 57d6d3ffb5..febd0f8dbe 100644
--- a/camel/camel-mime-utils.h
+++ b/camel/camel-mime-utils.h
@@ -91,8 +91,9 @@ void header_raw_clear(struct _header_raw **list);
/* decode a header which is a simple token */
char *header_token_decode(const char *in);
-/* decode a string type, like a subject line */
+/* decode/encode a string type, like a subject line */
char *header_decode_string(const char *in);
+char *header_encode_string(const unsigned char *in);
/* decode an email date field into a GMT time, + optional offset */
time_t header_decode_date(const char *in, int *saveoffset);
diff --git a/camel/camel-multipart.c b/camel/camel-multipart.c
index 3292e04b78..94ec8a4dbf 100644
--- a/camel/camel-multipart.c
+++ b/camel/camel-multipart.c
@@ -33,6 +33,7 @@
#include "camel-mime-body-part.h"
#include "camel-multipart.h"
+#define d(x)
static void add_part (CamelMultipart *multipart,
CamelMimeBodyPart *part);
@@ -56,8 +57,9 @@ static void write_to_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
static void set_input_stream (CamelDataWrapper *data_wrapper,
CamelStream *stream);
-
static void finalize (GtkObject *object);
+static void construct_from_parser(CamelDataWrapper *dw, CamelMimeParser *mp);
+
static CamelDataWrapperClass *parent_class = NULL;
@@ -96,6 +98,8 @@ camel_multipart_class_init (CamelMultipartClass *camel_multipart_class)
camel_data_wrapper_class->write_to_stream = write_to_stream;
camel_data_wrapper_class->set_input_stream = set_input_stream;
+ camel_data_wrapper_class->construct_from_parser = construct_from_parser;
+
gtk_object_class->finalize = finalize;
}
@@ -105,7 +109,7 @@ camel_multipart_init (gpointer object, gpointer klass)
CamelMultipart *multipart = CAMEL_MULTIPART (object);
camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart),
- "multipart");
+ "multipart/mixed");
camel_multipart_set_boundary (multipart, "=-=-=-=");
multipart->preface = NULL;
multipart->postface = NULL;
@@ -165,6 +169,7 @@ finalize (GtkObject *object)
}
+
/**
* camel_multipart_new:
*
@@ -408,6 +413,7 @@ camel_multipart_get_parent (CamelMultipart *multipart)
}
+
static void
set_boundary (CamelMultipart *multipart, gchar *boundary)
{
@@ -629,22 +635,44 @@ set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
* set_input_stream.
*/
saved_stream_pos = camel_seekable_stream_get_current_position (seekable_stream);
+ camel_data_wrapper_set_input_stream (CAMEL_DATA_WRAPPER (body_part),
+ CAMEL_STREAM (body_part_input_stream));
+
+ /* restore the stream position */
+ camel_seekable_stream_seek (seekable_stream, saved_stream_pos, CAMEL_STREAM_SET);
+
+ /* add the body part to the multipart object */
+ camel_multipart_add_part (multipart, body_part);
+ }
+
+ /* g_string_assign (new_part, ""); */
+ /* my_localize_part (new_part, stream, real_boundary_line, end_boundary_line); */
+
+ if (multipart->postface) g_free (multipart->postface);
+ /* if ( (new_part->str)[0] != '\0') multipart->postface = g_strdup (new_part->str); */
+
+ /* g_string_free (new_part, TRUE); */
+
+ g_free (real_boundary_line);
+ g_free (end_boundary_line);
+}
- camel_data_wrapper_set_input_stream (
- CAMEL_DATA_WRAPPER (body_part),
- CAMEL_STREAM (body_part_input_stream));
-
- /* Restore the stream position. */
- camel_seekable_stream_seek (seekable_stream, saved_stream_pos,
- CAMEL_STREAM_SET);
+/* multi_part */
+static void
+construct_from_parser(CamelDataWrapper *dw, CamelMimeParser *mp)
+{
+ CamelDataWrapper *bodypart;
+ char *buf;
+ int len;
- /* Add the body part to the multipart object. */
- camel_multipart_add_part (multipart, body_part);
- }
+ d(printf("constructing multipart\n"));
- if (multipart->postface)
- g_free (multipart->postface);
+ /* get/set boundary? */
- g_free (real_boundary_line);
- g_free (end_boundary_line);
+ while (camel_mime_parser_step(mp, &buf, &len) != HSCAN_MULTIPART_END) {
+ camel_mime_parser_unstep(mp);
+ bodypart = (CamelDataWrapper *)camel_mime_body_part_new();
+ camel_data_wrapper_construct_from_parser(bodypart, mp);
+ camel_multipart_add_part((CamelMultipart *)dw, (CamelMimeBodyPart *)bodypart);
+ }
}
diff --git a/camel/camel-simple-data-wrapper.c b/camel/camel-simple-data-wrapper.c
index 7f128116dc..d368a4ddfd 100644
--- a/camel/camel-simple-data-wrapper.c
+++ b/camel/camel-simple-data-wrapper.c
@@ -4,8 +4,8 @@
/*
*
- * Author :
- * Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
+ * Michael Zucchi <notzed@helixcode.com>
*
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
*
@@ -28,6 +28,17 @@
#include "camel-simple-data-wrapper.h"
#include "camel-simple-data-wrapper-stream.h"
+#include <camel/camel-stream-mem.h>
+#include "camel-mime-utils.h"
+#include <camel/camel-mime-filter.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-seekable-substream.h>
+
+#include <string.h>
+
+#define d(x)
static CamelDataWrapperClass *parent_class = NULL;
@@ -40,6 +51,7 @@ static void write_to_stream (CamelDataWrapper *data_wrapper
CamelStream *stream);
static void finalize (GtkObject *object);
static CamelStream * get_output_stream (CamelDataWrapper *data_wrapper);
+static void construct_from_parser(CamelDataWrapper *dw, CamelMimeParser *mp);
@@ -59,6 +71,8 @@ camel_simple_data_wrapper_class_init (CamelSimpleDataWrapperClass *camel_simple_
camel_data_wrapper_class->construct_from_stream = construct_from_stream;
camel_data_wrapper_class->get_output_stream = get_output_stream;
+ camel_data_wrapper_class->construct_from_parser = construct_from_parser;
+
gtk_object_class->finalize = finalize;
}
@@ -210,3 +224,135 @@ get_output_stream (CamelDataWrapper *data_wrapper)
return parent_class->get_output_stream (data_wrapper);
}
+
+/* simple data wrapper */
+static void
+construct_from_parser(CamelDataWrapper *dw, CamelMimeParser *mp)
+{
+ GByteArray *buffer;
+ char *buf;
+ int len;
+ off_t start, end;
+ CamelMimeFilter *fdec = NULL, *fch = NULL;
+ struct _header_content_type *ct;
+ int decid=-1, chrid=-1, cache=FALSE;
+ CamelStream *source;
+ char *encoding;
+
+ d(printf("constructing simple-data-wrapper\n"));
+
+ /* Ok, try and be smart. If we're storing a small message (typical) convert it,
+ and store it in memory as we parse it ... if not, throw away the conversion
+ and scan till the end ... */
+
+ /* if we can't seek, dont have a stream/etc, then we must cache it */
+ source = camel_mime_parser_stream(mp);
+ gtk_object_ref((GtkObject *)source);
+ if (source == NULL
+ || !CAMEL_IS_SEEKABLE_STREAM(source))
+ cache = TRUE;
+
+ /* first, work out conversion, if any, required, we dont care about what we dont know about */
+ encoding = header_content_encoding_decode(camel_mime_parser_header(mp, "content-transfer-encoding", NULL));
+ if (encoding) {
+ if (!strcasecmp(encoding, "base64")) {
+ d(printf("Adding base64 decoder ...\n"));
+ fdec = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
+ decid = camel_mime_parser_filter_add(mp, fdec);
+ } else if (!strcasecmp(encoding, "quoted-printable")) {
+ d(printf("Adding quoted-printable decoder ...\n"));
+ fdec = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_DEC);
+ decid = camel_mime_parser_filter_add(mp, fdec);
+ }
+ g_free(encoding);
+ }
+
+ /* if we're doing text, then see if we have to convert it to UTF8 as well */
+ ct = camel_mime_parser_content_type(mp);
+ if (header_content_type_is(ct, "text", "*")) {
+ const char *charset = header_content_type_param(ct, "charset");
+ if (charset!=NULL
+ && !(strcasecmp(charset, "us-ascii")==0
+ || strcasecmp(charset, "utf-8")==0)) {
+ d(printf("Adding conversion filter from %s to utf-8\n", charset));
+ fch = (CamelMimeFilter *)camel_mime_filter_charset_new_convert(charset, "utf-8");
+ if (fch) {
+ chrid = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)fch);
+ } else {
+ g_warning("Cannot convert '%s' to 'utf-8', message display may be corrupt", charset);
+ }
+ }
+
+ }
+
+ buffer = g_byte_array_new();
+
+ /* write to a memory buffer or something??? */
+ start = camel_mime_parser_tell(mp);
+ while ( camel_mime_parser_step(mp, &buf, &len) != HSCAN_BODY_END ) {
+ if (buffer) {
+ if (buffer->len > 20480 && !cache) {
+ /* is this a 'big' message? Yes? We dont want to convert it all then.*/
+ camel_mime_parser_filter_remove(mp, decid);
+ camel_mime_parser_filter_remove(mp, chrid);
+ decid = -1;
+ chrid = -1;
+ g_byte_array_free(buffer, TRUE);
+ buffer = NULL;
+ } else {
+ g_byte_array_append(buffer, buf, len);
+ }
+ }
+ }
+
+ if (buffer) {
+ CamelStream *mem;
+ d(printf("Small message part, kept in memory!\n"));
+ mem = camel_stream_mem_new_with_byte_array(buffer, CAMEL_STREAM_MEM_READ);
+ camel_data_wrapper_set_output_stream (dw, mem);
+ } else {
+ CamelSeekableSubstream *sub;
+ CamelStreamFilter *filter;
+
+ d(printf("Big message part, left on disk ...\n"));
+
+ end = camel_mime_parser_tell(mp);
+ sub = (CamelSeekableSubstream *)camel_seekable_substream_new_with_seekable_stream_and_bounds ((CamelSeekableStream *)source, start, end);
+ if (fdec || fch) {
+ filter = camel_stream_filter_new_with_stream((CamelStream *)sub);
+ if (fdec) {
+ camel_mime_filter_reset(fdec);
+ camel_stream_filter_add(filter, fdec);
+ }
+ if (fch) {
+ camel_mime_filter_reset(fdec);
+ camel_stream_filter_add(filter, fch);
+ }
+ camel_data_wrapper_set_output_stream (dw, (CamelStream *)filter);
+ } else {
+ camel_data_wrapper_set_output_stream (dw, (CamelStream *)sub);
+ }
+ }
+
+ camel_mime_parser_filter_remove(mp, decid);
+ camel_mime_parser_filter_remove(mp, chrid);
+
+ if (fdec)
+ gtk_object_unref((GtkObject *)fdec);
+ if (fch)
+ gtk_object_unref((GtkObject *)fch);
+ gtk_object_unref((GtkObject *)source);
+
+ /* FIXME: lookup in headers for content-type/encoding */
+#if 0
+ /* trivial, mem-based ... */
+ buffer = g_byte_array_new();
+ start = camel_mime_parser_tell(mp);
+ while ( camel_mime_parser_step(mp, &buf, &len) != HSCAN_BODY_END ) {
+ g_byte_array_append(buffer, buf, len);
+ }
+ end = camel_mime_parser_tell(mp);
+ mem = camel_stream_mem_new_with_byte_array(buffer, CAMEL_STREAM_MEM_READ);
+ camel_data_wrapper_set_output_stream (dw, mem);
+#endif
+}
diff --git a/camel/camel-stream-filter.c b/camel/camel-stream-filter.c
index 9d6c7d11b0..7a8491c1f8 100644
--- a/camel/camel-stream-filter.c
+++ b/camel/camel-stream-filter.c
@@ -99,6 +99,9 @@ finalise(GtkObject *o)
}
g_free(p->realbuffer);
g_free(p);
+ gtk_object_unref((GtkObject *)filter->source);
+
+ GTK_OBJECT_CLASS (camel_stream_filter_parent)->finalize (o);
}
diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c
index 75eb217e74..c1920bdd1c 100644
--- a/camel/providers/mbox/camel-mbox-folder.c
+++ b/camel/providers/mbox/camel-mbox-folder.c
@@ -856,8 +856,19 @@ _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex)
((CamelMboxMessageContentInfo *)info->info.content)->pos,
((CamelMboxMessageContentInfo *)info->info.content)->endpos);
message = camel_mime_message_new();
+#if 1
+ {
+ CamelMimeParser *parser;
+
+ parser = camel_mime_parser_new();
+ camel_mime_parser_init_with_stream(parser, message_stream);
+ camel_data_wrapper_construct_from_parser(message, parser);
+ gtk_object_unref((GtkObject *)parser);
+ gtk_object_unref((GtkObject *)message_stream);
+ }
+#else
camel_data_wrapper_set_input_stream (CAMEL_DATA_WRAPPER (message), message_stream);
-
+#endif
/* init other fields? */
message->folder = folder;
gtk_object_ref((GtkObject *)folder);
diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c
index aa6f85610a..22060bf8fe 100644
--- a/camel/providers/mbox/camel-mbox-summary.c
+++ b/camel/providers/mbox/camel-mbox-summary.c
@@ -341,21 +341,6 @@ body_part_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int star
return bs;
}
-static char *strdup_trim(const char *s)
-{
- const char *end;
-
- if (s == NULL)
- return NULL;
-
- while (isspace(*s))
- s++;
- end = s+strlen(s)-1;
- while (end>s && isspace(*end))
- end--;
- return g_strndup(s, end-s+1);
-}
-
static CamelMboxMessageInfo *
message_struct_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int start, int body, off_t xev_offset)
{
@@ -364,9 +349,9 @@ message_struct_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int
ms = g_malloc0(sizeof(*ms));
/* FIXME: what about cc, sender vs from? */
- ms->info.subject = strdup_trim(camel_mime_parser_header(mp, "subject", NULL));
- ms->info.from = strdup_trim(camel_mime_parser_header(mp, "from", NULL));
- ms->info.to = strdup_trim(camel_mime_parser_header(mp, "to", NULL));
+ ms->info.subject = header_decode_string(camel_mime_parser_header(mp, "subject", NULL));
+ ms->info.from = g_strdup(camel_mime_parser_header(mp, "from", NULL));
+ ms->info.to = g_strdup(camel_mime_parser_header(mp, "to", NULL));
ms->info.date_sent = header_decode_date(camel_mime_parser_header(mp, "date", NULL), NULL);
ms->info.date_received = 0;