aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog23
-rw-r--r--camel/camel-mime-message.c10
-rw-r--r--camel/camel-mime-message.h8
-rw-r--r--camel/camel-mime-part-utils.c8
-rw-r--r--camel/camel-mime-part.c6
-rw-r--r--camel/camel-mime-utils.c299
-rw-r--r--camel/camel-mime-utils.h38
-rw-r--r--camel/providers/mbox/camel-mbox-summary.c20
8 files changed, 364 insertions, 48 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index a7b0e30621..1760e032a4 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,25 @@
2000-04-24 NotZed <NotZed@HelixCode.com>
+ * camel-mime-message.c (construct_from_parser): Allow MESSAGE_END
+ _or_ EOF as valid termination conditions.
+
+ * providers/mbox/camel-mbox-summary.c (message_struct_new): Decode
+ and then re-encode the addresses, so they are consistently
+ formatted.
+
+ * camel-mime-utils.c (header_decode_mailbox): Store the address in
+ a _header_address. And try to get a comment-stored name if there
+ is one.
+ (header_decode_address): Actually return an address.
+ (header_to_decode): Renamed to header_address_decode()
+ (header_mailbox_decode): New function to get a single mailbox.
+ (header_mime_decode): Return the major/minor value, as
+ appropriate.
+ (header_address_new, and friends): Whole bunch of utility
+ functions for working with the address thingies.
+ (header_decode_domain): Free the string header, and dont expand
+ '.' into ' . '.
+
* camel.c (camel_init): No longer call
data_wrapper_repository_init.
@@ -23,6 +43,9 @@
* camel-mime-part-utils.c
(camel_mime_part_construct_content_from_parser): Create the
contents of multipart and simple messages.
+ (camel_mime_part_construct_content_from_parser): Oops, this was
+ totally screwed up, try creating the right cotnent on the right
+ object.
* camel-multipart.c (construct_from_parser): Moved to
camel-mime-part-utils.
diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c
index f63548e5a5..25c1c667e2 100644
--- a/camel/camel-mime-message.c
+++ b/camel/camel-mime-message.c
@@ -485,17 +485,23 @@ construct_from_parser(CamelMimePart *dw, CamelMimeParser *mp)
{
char *buf;
int len;
+ int state;
d(printf("constructing mime-message\n"));
+ d(printf("mime_message::construct_from_parser()\n"));
+
/* let the mime-part construct the guts ... */
((CamelMimePartClass *)parent_class)->construct_from_parser(dw, mp);
/* ... then clean up the follow-on state */
- if (camel_mime_parser_step(mp, &buf, &len) != HSCAN_MESSAGE_END) {
- g_warning("Bad parser state: Expecing MESSAGE_END, got: %d", camel_mime_parser_state(mp));
+ state = camel_mime_parser_step(mp, &buf, &len);
+ if (!(state == HSCAN_MESSAGE_END || state == HSCAN_EOF)) {
+ g_warning("Bad parser state: Expecing MESSAGE_END or EOF, got: %d", camel_mime_parser_state(mp));
camel_mime_parser_unstep(mp);
}
+
+ d(printf("mime_message::construct_from_parser() leaving\n"));
}
#ifdef WHPT
diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h
index ddcf846c20..7142d876de 100644
--- a/camel/camel-mime-message.h
+++ b/camel/camel-mime-message.h
@@ -35,10 +35,10 @@ extern "C" {
#endif /* __cplusplus }*/
#include <gtk/gtk.h>
-#include "camel-types.h"
-#include "camel-mime-part.h"
-#include "camel-recipient.h"
-
+#include <camel/camel-types.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-recipient.h>
+#include <camel/camel-mime-utils.h>
#define CAMEL_RECIPIENT_TYPE_TO "To"
#define CAMEL_RECIPIENT_TYPE_CC "Cc"
diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c
index 460a6c7d03..50e9fd29d5 100644
--- a/camel/camel-mime-part-utils.c
+++ b/camel/camel-mime-part-utils.c
@@ -104,7 +104,6 @@ simple_data_wrapper_construct_from_parser(CamelDataWrapper *dw, CamelMimeParser
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) {
@@ -174,11 +173,12 @@ camel_mime_part_construct_content_from_parser(CamelMimePart *dw, CamelMimeParser
case HSCAN_HEADER:
d(printf("Creating body part\n"));
content = (CamelDataWrapper *)camel_simple_data_wrapper_new();
+ simple_data_wrapper_construct_from_parser(content, mp);
break;
case HSCAN_MESSAGE:
d(printf("Creating message part\n"));
content = (CamelDataWrapper *)camel_mime_message_new();
- simple_data_wrapper_construct_from_parser(content, mp);
+ camel_mime_part_construct_from_parser((CamelMimePart *)content, mp);
break;
case HSCAN_MULTIPART: {
CamelDataWrapper *bodypart;
@@ -193,8 +193,10 @@ camel_mime_part_construct_content_from_parser(CamelMimePart *dw, CamelMimeParser
camel_mime_parser_unstep(mp);
bodypart = (CamelDataWrapper *)camel_mime_body_part_new();
camel_mime_part_construct_from_parser((CamelMimePart *)bodypart, mp);
- camel_multipart_add_part((CamelMultipart *)dw, (CamelMimeBodyPart *)bodypart);
+ camel_multipart_add_part((CamelMultipart *)content, (CamelMimeBodyPart *)bodypart);
}
+
+ d(printf("Created multi-part\n"));
break; }
default:
g_warning("Invalid state encountered???: %d", camel_mime_parser_state(mp));
diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c
index d84d560eff..9d4b98a07e 100644
--- a/camel/camel-mime-part.c
+++ b/camel/camel-mime-part.c
@@ -546,7 +546,7 @@ construct_from_parser(CamelMimePart *dw, CamelMimeParser *mp)
char *buf;
int len;
- d(printf("constructing mime-part\n"));
+ d(printf("mime_part::construct_from_parser()\n"));
switch (camel_mime_parser_step(mp, &buf, &len)) {
case HSCAN_HEADER:
@@ -563,6 +563,8 @@ construct_from_parser(CamelMimePart *dw, CamelMimeParser *mp)
default:
g_warning("Invalid state encountered???: %d", camel_mime_parser_state(mp));
}
+
+ d(printf("mime_part::construct_from_parser() leaving\n"));
}
void
@@ -576,6 +578,8 @@ construct_from_stream(CamelDataWrapper *dw, CamelStream *s)
{
CamelMimeParser *mp;
+ printf("mime_part::construct_from_stream()\n");
+
mp = camel_mime_parser_new();
if (camel_mime_parser_init_with_stream(mp, s) == -1) {
g_warning("Cannot create parser for stream");
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
index f9e2389fee..ceb528ce28 100644
--- a/camel/camel-mime-utils.c
+++ b/camel/camel-mime-utils.c
@@ -1195,6 +1195,7 @@ header_decode_domain(const char **in)
{
const char *inptr = *in, *start;
int go = TRUE;
+ char *ret;
GString *domain = g_string_new("");
/* domain ref | domain literal */
@@ -1226,7 +1227,7 @@ header_decode_domain(const char **in)
}
header_decode_lwsp(&inptr);
if (*inptr == '.') { /* next sub-domain? */
- g_string_append(domain, " . ");
+ g_string_append_c(domain, '.');
inptr++;
header_decode_lwsp(&inptr);
} else
@@ -1235,8 +1236,9 @@ header_decode_domain(const char **in)
*in = inptr;
- /* FIXME:L free string header */
- return domain->str;
+ ret = domain->str;
+ g_string_free(domain, FALSE);
+ return ret;
}
static char *
@@ -1301,15 +1303,15 @@ header_decode_addrspec(const char **in)
*(word) '<' [ *('@' domain ) ':' ] word *( '.' word) @ domain
*/
-/* FIXME: what does this return? */
-
-static void
+static struct _header_address *
header_decode_mailbox(const char **in)
{
const char *inptr = *in;
char *pre;
int closeme = FALSE;
GString *addr;
+ GString *name = NULL;
+ struct _header_address *address = NULL;
addr = g_string_new("");
@@ -1317,10 +1319,18 @@ header_decode_mailbox(const char **in)
pre = header_decode_word(&inptr);
header_decode_lwsp(&inptr);
if (!(*inptr == '.' || *inptr == '@' || *inptr==',' || *inptr=='\0')) { /* ',' and '\0' required incase it is a simple address, no @ domain part (buggy writer) */
- /* FIXME: rfc 2047 decode each word */
+ name = g_string_new("");
while (pre) {
+ char *text;
+
+ text = header_decode_string(pre);
+ g_string_append(name, text);
+ g_free(pre);
+
/* rfc_decode(pre) */
pre = header_decode_word(&inptr);
+ if (pre)
+ g_string_append_c(name, ' ');
}
header_decode_lwsp(&inptr);
if (*inptr == '<') {
@@ -1359,11 +1369,13 @@ header_decode_mailbox(const char **in)
/* should be at word '.' localpart */
while (*inptr == '.' && pre) {
inptr++;
+ g_free(pre);
pre = header_decode_word(&inptr);
g_string_append_c(addr, '.');
g_string_append(addr, pre);
header_decode_lwsp(&inptr);
}
+ g_free(pre);
/* now at '@' domain part */
if (*inptr == '@') {
@@ -1384,20 +1396,41 @@ header_decode_mailbox(const char **in)
} else {
g_warning("invalid route address, no closing '>': %s", *in);
}
+ } else if (name == NULL) { /* check for comment after address */
+ char *text, *tmp;
+ const char *comment = inptr;
+
+ header_decode_lwsp(&inptr);
+ if (inptr-comment > 3) { /* just guess ... */
+ tmp = g_strndup(comment, inptr-comment);
+ text = header_decode_string(tmp);
+ name = g_string_new(text);
+ g_free(tmp);
+ g_free(text);
+ }
}
*in = inptr;
+ if (addr->len > 0) {
+ address = header_address_new_name(name?name->str:"", addr->str);
+ }
+
+ g_string_free(addr, TRUE);
+ if (name)
+ g_string_free(name, TRUE);
+
d(printf("got mailbox: %s\n", addr->str));
+ return address;
}
-/* FIXME: what does this return? */
-static void
+static struct _header_address *
header_decode_address(const char **in)
{
const char *inptr = *in;
char *pre;
GString *group = g_string_new("");
+ struct _header_address *addr = NULL, *member;
/* pre-scan, trying to work out format, discard results */
header_decode_lwsp(&inptr);
@@ -1409,6 +1442,7 @@ header_decode_address(const char **in)
header_decode_lwsp(&inptr);
if (*inptr == ':') {
d(printf("group detected: %s\n", group->str));
+ addr = header_address_new_group(group->str);
/* that was a group spec, scan mailbox's */
inptr++;
/* FIXME: check rfc 2047 encodings of words, here or above in the loop */
@@ -1416,7 +1450,9 @@ header_decode_address(const char **in)
if (*inptr != ';') {
int go = TRUE;
do {
- header_decode_mailbox(&inptr);
+ member = header_decode_mailbox(&inptr);
+ if (member)
+ header_address_add_member(addr, member);
header_decode_lwsp(&inptr);
if (*inptr == ',')
inptr++;
@@ -1432,17 +1468,13 @@ header_decode_address(const char **in)
inptr++;
}
*in = inptr;
-/* } else if (*inptr == '.' || *inptr == '<' || *inptr == '@') {*/
} else {
- /* back-track, and rescan. not worth the code duplication to do this faster */
- /* this will detect invalid input */
- header_decode_mailbox(in);
- }/* else {
- g_warning("Cannot scan address at '%c': %s", *inptr, *in);
- }*/
-
- /* FIXME: store gropu somewhere */
+ addr = header_decode_mailbox(in);
+ }
+
g_string_free(group, TRUE);
+
+ return addr;
}
char *
@@ -1481,21 +1513,33 @@ header_msgid_decode(const char *in)
return msgid;
}
-void
-header_to_decode(const char *in)
+struct _header_address *
+header_mailbox_decode(const char *in)
+{
+ if (in == NULL)
+ return NULL;
+
+ return header_decode_mailbox(&in);
+}
+
+struct _header_address *
+header_address_decode(const char *in)
{
const char *inptr = in, *last;
+ struct _header_address *list = NULL, *addr;
d(printf("decoding To: '%s'\n", in));
#warning header_to_decode needs to return some structure
if (in == NULL)
- return;
+ return NULL;
do {
last = inptr;
- header_decode_address(&inptr);
+ addr = header_decode_address(&inptr);
+ if (addr)
+ header_address_list_append(&list, addr);
header_decode_lwsp(&inptr);
if (*inptr == ',')
inptr++;
@@ -1510,33 +1554,37 @@ header_to_decode(const char *in)
if (inptr == last) {
g_warning("detected invalid input loop at : %s", last);
}
+
+ return list;
}
void
-header_mime_decode(const char *in)
+header_mime_decode(const char *in, int *maj, int *min)
{
const char *inptr = in;
int major=-1, minor=-1;
d(printf("decoding MIME-Version: '%s'\n", in));
-#warning header_mime_decode needs to return the version
-
- if (in == NULL)
- return;
-
- header_decode_lwsp(&inptr);
- if (isdigit(*inptr)) {
- major = header_decode_int(&inptr);
+ if (in != NULL) {
header_decode_lwsp(&inptr);
- if (*inptr == '.') {
- inptr++;
+ if (isdigit(*inptr)) {
+ major = header_decode_int(&inptr);
header_decode_lwsp(&inptr);
- if (isdigit(*inptr))
- minor = header_decode_int(&inptr);
+ if (*inptr == '.') {
+ inptr++;
+ header_decode_lwsp(&inptr);
+ if (isdigit(*inptr))
+ minor = header_decode_int(&inptr);
+ }
}
}
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+
d(printf("major = %d, minor = %d\n", major, minor));
}
@@ -2081,6 +2129,185 @@ header_raw_clear(struct _header_raw **list)
}
+/* ok, here's the address stuff, what a mess ... */
+struct _header_address *header_address_new(void)
+{
+ struct _header_address *h;
+ h = g_malloc0(sizeof(*h));
+ h->type = HEADER_ADDRESS_NONE;
+ h->refcount = 1;
+ return h;
+}
+
+struct _header_address *header_address_new_name(const char *name, const char *addr)
+{
+ struct _header_address *h;
+
+ h = header_address_new();
+ h->type = HEADER_ADDRESS_NAME;
+ h->name = g_strdup(name);
+ h->v.addr = g_strdup(addr);
+ return h;
+}
+
+struct _header_address *header_address_new_group(const char *name)
+{
+ struct _header_address *h;
+
+ h = header_address_new();
+ h->type = HEADER_ADDRESS_GROUP;
+ h->name = g_strdup(name);
+ return h;
+}
+
+void header_address_ref(struct _header_address *h)
+{
+ if (h)
+ h->refcount++;
+}
+
+void header_address_unref(struct _header_address *h)
+{
+ if (h) {
+ if (h->refcount <= 1) {
+ if (h->type == HEADER_ADDRESS_GROUP) {
+ header_address_list_clear(&h->v.members);
+ } else if (h->type == HEADER_ADDRESS_NAME) {
+ g_free(h->v.addr);
+ }
+ g_free(h->name);
+ g_free(h);
+ } else {
+ h->refcount--;
+ }
+ }
+}
+
+void header_address_set_name(struct _header_address *h, const char *name)
+{
+ if (h) {
+ g_free(h->name);
+ h->name = g_strdup(name);
+ }
+}
+
+void header_address_set_addr(struct _header_address *h, const char *addr)
+{
+ if (h) {
+ if (h->type == HEADER_ADDRESS_NAME
+ || h->type == HEADER_ADDRESS_NONE) {
+ h->type = HEADER_ADDRESS_NAME;
+ g_free(h->v.addr);
+ h->v.addr = g_strdup(addr);
+ } else {
+ g_warning("Trying to set the address on a group");
+ }
+ }
+}
+
+void header_address_set_members(struct _header_address *h, struct _header_address *group)
+{
+ if (h) {
+ if (h->type == HEADER_ADDRESS_GROUP
+ || h->type == HEADER_ADDRESS_NONE) {
+ h->type = HEADER_ADDRESS_GROUP;
+ header_address_list_clear(&h->v.members);
+ /* should this ref them? */
+ h->v.members = group;
+ } else {
+ g_warning("Trying to set the members on a name, not group");
+ }
+ }
+}
+
+void header_address_add_member(struct _header_address *h, struct _header_address *member)
+{
+ if (h) {
+ if (h->type == HEADER_ADDRESS_GROUP
+ || h->type == HEADER_ADDRESS_NONE) {
+ h->type = HEADER_ADDRESS_GROUP;
+ header_address_list_append(&h->v.members, member);
+ }
+ }
+}
+
+void header_address_list_append_list(struct _header_address **l, struct _header_address **h)
+{
+ if (l) {
+ struct _header_address *n = (struct _header_address *)l;
+
+ while (n->next)
+ n = n->next;
+ n->next = *h;
+ }
+}
+
+
+void header_address_list_append(struct _header_address **l, struct _header_address *h)
+{
+ if (h) {
+ header_address_list_append_list(l, &h);
+ h->next = NULL;
+ }
+}
+
+void header_address_list_clear(struct _header_address **l)
+{
+ struct _header_address *a, *n;
+ a = (struct _header_address *)l;
+ while (a && a->next) {
+ n = a->next;
+ a = n->next;
+ header_address_unref(n);
+ }
+}
+
+static void
+header_address_list_format_append(GString *out, struct _header_address *a)
+{
+ char *text;
+
+ while (a) {
+ switch (a->type) {
+ case HEADER_ADDRESS_NAME:
+#warning needs to rfc2047 encode address phrase
+ /* FIXME: 2047 encoding?? */
+ if (a->name)
+ g_string_sprintfa(out, "\"%s\" <%s>", a->name, a->v.addr);
+ else
+ g_string_sprintfa(out, "<%s>", a->v.addr);
+ break;
+ case HEADER_ADDRESS_GROUP:
+ text = header_encode_string(a->name);
+ g_string_sprintfa(out, "%s:\n ", text);
+ header_address_list_format_append(out, a->v.members);
+ g_string_sprintfa(out, ";");
+ break;
+ default:
+ g_warning("Invalid address type");
+ break;
+ }
+ a = a->next;
+ }
+}
+
+/* FIXME: need a 'display friendly' version, as well as a 'rfc friendly' version? */
+char *
+header_address_list_format(struct _header_address *a)
+{
+ GString *out;
+ char *ret;
+
+ if (a == NULL)
+ return NULL;
+
+ out = g_string_new("");
+
+ header_address_list_format_append(out, a);
+ ret = out->str;
+ g_string_free(out, FALSE);
+ return ret;
+}
#ifdef BUILD_TABLE
diff --git a/camel/camel-mime-utils.h b/camel/camel-mime-utils.h
index febd0f8dbe..f95f76363c 100644
--- a/camel/camel-mime-utils.h
+++ b/camel/camel-mime-utils.h
@@ -52,6 +52,41 @@ typedef struct _CamelMimeDisposition {
unsigned int refcount;
} CamelMimeDisposition;
+enum _header_address_type {
+ HEADER_ADDRESS_NONE, /* uninitialised */
+ HEADER_ADDRESS_NAME,
+ HEADER_ADDRESS_GROUP
+};
+
+struct _header_address {
+ struct _header_address *next;
+ enum _header_address_type type;
+ char *name;
+ union {
+ char *addr;
+ struct _header_address *members;
+ } v;
+ unsigned int refcount;
+};
+
+/* Address lists */
+struct _header_address *header_address_new(void);
+struct _header_address *header_address_new_name(const char *name, const char *addr);
+struct _header_address *header_address_new_group(const char *name);
+void header_address_ref(struct _header_address *);
+void header_address_unref(struct _header_address *);
+void header_address_set_name(struct _header_address *, const char *name);
+void header_address_set_addr(struct _header_address *, const char *addr);
+void header_address_set_members(struct _header_address *, struct _header_address *group);
+void header_address_add_member(struct _header_address *, struct _header_address *member);
+void header_address_list_append_list(struct _header_address **l, struct _header_address **h);
+void header_address_list_append(struct _header_address **, struct _header_address *);
+void header_address_list_clear(struct _header_address **);
+
+struct _header_address *header_address_decode(const char *in);
+struct _header_address *header_mailbox_decode(const char *in);
+char *header_address_list_format(struct _header_address *a);
+
/* structured header prameters */
char *header_param(struct _header_param *p, const char *name);
struct _header_param *header_set_param(struct _header_param **l, const char *name, const char *value);
@@ -102,6 +137,9 @@ char *header_format_date(time_t time, int offset);
/* decode a message id */
char *header_msgid_decode(const char *in);
+/* decode the mime-type header */
+void header_mime_decode(const char *in, int *maj, int *min);
+
/* do incremental base64/quoted-printable (de/en)coding */
int base64_decode_step(unsigned char *in, int len, unsigned char *out, int *state, unsigned int *save);
diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c
index 22060bf8fe..f1d4a41b7d 100644
--- a/camel/providers/mbox/camel-mbox-summary.c
+++ b/camel/providers/mbox/camel-mbox-summary.c
@@ -345,13 +345,29 @@ static CamelMboxMessageInfo *
message_struct_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int start, int body, off_t xev_offset)
{
CamelMboxMessageInfo *ms;
+ struct _header_address *addr;
+ const char *text;
ms = g_malloc0(sizeof(*ms));
/* FIXME: what about cc, sender vs from? */
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));
+ text = camel_mime_parser_header(mp, "from", NULL);
+ addr = header_address_decode(text);
+ if (addr) {
+ ms->info.from = header_address_list_format(addr);
+ header_address_list_clear(&addr);
+ } else {
+ ms->info.from = g_strdup(text);
+ }
+ text = camel_mime_parser_header(mp, "to", NULL);
+ addr = header_address_decode(text);
+ if (addr) {
+ ms->info.to = header_address_list_format(addr);
+ header_address_list_clear(&addr);
+ } else {
+ ms->info.to = g_strdup(text);
+ }
ms->info.date_sent = header_decode_date(camel_mime_parser_header(mp, "date", NULL), NULL);
ms->info.date_received = 0;