From 0a4dd21b9b2c843ca3bc22df5e67767bcb8a86f4 Mon Sep 17 00:00:00 2001 From: Bertrand Guiheneuf Date: Mon, 9 Aug 1999 16:48:02 +0000 Subject: sync svn path=/trunk/; revision=1099 --- camel/camel-folder.h | 1 + camel/gmime-rfc2047.c | 117 +++++++++++++++-------------- devel-docs/misc/ref_and_id_proposition.txt | 99 ++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 55 deletions(-) create mode 100644 devel-docs/misc/ref_and_id_proposition.txt diff --git a/camel/camel-folder.h b/camel/camel-folder.h index 2fd40a2591..b678631eea 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -125,6 +125,7 @@ const gchar *camel_folder_get_name (CamelFolder *folder); const gchar *camel_folder_get_full_name (CamelFolder *folder); CamelMimeMessage *camel_folder_get_message (CamelFolder *folder, gint number); gboolean camel_folder_exists (CamelFolder *folder); +gint camel_get_message_count (CamelFolder *folder); diff --git a/camel/gmime-rfc2047.c b/camel/gmime-rfc2047.c index 6130526c94..72f376d00c 100644 --- a/camel/gmime-rfc2047.c +++ b/camel/gmime-rfc2047.c @@ -50,8 +50,10 @@ hexval (gchar c) { } static gchar * -decode_quoted(const gchar *text, const gchar *end) { +decode_quoted (const gchar *text, const gchar *end) +{ gchar *to = malloc(end - text + 1), *to_2 = to; + if (!to) return NULL; while (*text && text < end) { if (*text == '=') { @@ -75,7 +77,8 @@ decode_quoted(const gchar *text, const gchar *end) { } static gchar * -decode_base64(const gchar *data, const gchar *end) { +decode_base64 (const gchar *data, const gchar *end) +{ unsigned short pattern = 0; int bits = 0; int delimiter = '='; @@ -119,76 +122,77 @@ build_base64_rank_table (void) } -gchar* +gchar * rfc2047_decode_word (const gchar *data, const gchar *into_what) { - const char *charset = strstr(data, "=?"), *encoding, *text, *end; + const char *charset = strstr (data, "=?"), *encoding, *text, *end; char *buffer, *b, *cooked_data; - buffer = g_malloc(strlen(data) * 2); + buffer = g_malloc (strlen(data) * 2); b = buffer; - if (!charset) return strdup(data); + if (!charset) return strdup (data); charset+=2; - encoding = strchr(charset, '?'); - if (!encoding) return strdup(data); + encoding = strchr (charset, '?'); + if (!encoding) return strdup (data); encoding++; text = strchr(encoding, '?'); - if (!text) return strdup(data); + if (!text) return strdup (data); text++; end = strstr(text, "?="); - if (!end) return strdup(data); + if (!end) return strdup (data); b[0] = 0; if (toupper(*encoding)=='Q') - cooked_data = decode_quoted(text, end); - else if (toupper(*encoding)=='B') - cooked_data = decode_base64(text, end); + cooked_data = decode_quoted (text, end); + else if (toupper (*encoding)=='B') + cooked_data = decode_base64 (text, end); else return g_strdup(data); { - char *c = strchr(charset, '?'); - char *q = g_malloc(c - charset + 1); + char *c = strchr (charset, '?'); + char *q = g_malloc (c - charset + 1); char *cook_2 = cooked_data; - int cook_len = strlen(cook_2); + int cook_len = strlen (cook_2); int b_len = 4096; iconv_t i; - strncpy(q, charset, c - charset); + strncpy (q, charset, c - charset); q[c - charset] = 0; - i = unicode_iconv_open(into_what, q); + i = unicode_iconv_open (into_what, q); if (!i) { - g_free(q); - return g_strdup(buffer); + g_free (q); + return g_strdup (buffer); } - if (unicode_iconv(i, &cook_2, &cook_len, &b, &b_len)==-1) + if (unicode_iconv (i, &cook_2, &cook_len, &b, &b_len)==-1) /* FIXME : use approximation code if we can't convert it properly. */ ; - unicode_iconv_close(i); + unicode_iconv_close (i); *b = 0; } - return g_strdup(buffer); + return g_strdup (buffer); } static const gchar * -find_end_of_encoded_word(const gchar *data) { +find_end_of_encoded_word (const gchar *data) +{ /* We can't just search for ?=, because of the case : "=?charset?q?=ff?=" :( */ if (!data) return NULL; - data = strstr(data, "=?"); + data = strstr (data, "=?"); if (!data) return NULL; data = strchr(data+2, '?'); if (!data) return NULL; - data = strchr(data+1, '?'); + data = strchr (data+1, '?'); if (!data) return NULL; - data = strstr(data+1, "?="); + data = strstr (data+1, "?="); if (!data) return NULL; return data + 2; } @@ -196,34 +200,34 @@ find_end_of_encoded_word(const gchar *data) { gchar * gmime_rfc2047_decode (const gchar *data, const gchar *into_what) { - char *buffer = malloc(strlen(data) * 4), *b = buffer; + char *buffer = malloc (strlen(data) * 4), *b = buffer; int was_encoded_word = 0; build_base64_rank_table (); while (data && *data) { - char *word_start = strstr(data, "=?"), *decoded; + char *word_start = strstr (data, "=?"), *decoded; if (!word_start) { - strcpy(b, data); - b[strlen(data)] = 0; + strcpy (b, data); + b[strlen (data)] = 0; return buffer; } if (word_start != data) { - if (strspn(data, " \t\n\r") != (word_start - data)) { - strncpy(b, data, word_start - data); + if (strspn (data, " \t\n\r") != (word_start - data)) { + strncpy (b, data, word_start - data); b += word_start - data; *b = 0; } } - decoded = rfc2047_decode_word(word_start, into_what); - strcpy(b, decoded); - b += strlen(decoded); + decoded = rfc2047_decode_word (word_start, into_what); + strcpy (b, decoded); + b += strlen (decoded); *b = 0; - g_free(decoded); + g_free (decoded); - data = find_end_of_encoded_word(data); + data = find_end_of_encoded_word (data); } *b = 0; @@ -232,34 +236,37 @@ gmime_rfc2047_decode (const gchar *data, const gchar *into_what) #define isnt_ascii(a) ((a) <= 0x1f || (a) >= 0x7f) -static int rfc2047_clean(const gchar *string) { - if (strstr(string, "?=")) return 1; +static int +rfc2047_clean (const gchar *string) { + if (strstr (string, "?=")) return 1; while (*string) { - if (!isnt_ascii((unsigned char)*string)) + if (!isnt_ascii ((unsigned char)*string)) return 0; string++; } return 1; } -static gchar *encode_word (const gchar *string, const gchar *said_charset) { +static gchar * +encode_word (const gchar *string, const gchar *said_charset) +{ if (rfc2047_clean(string)) /* don't bother encoding it if it has no odd characters in it */ - return g_strdup(string); + return g_strdup (string); { - char *temp = malloc(strlen(string) * 4 + 1), *t = temp; - t += sprintf(t, "=?%s?q?", said_charset); + char *temp = malloc (strlen(string) * 4 + 1), *t = temp; + t += sprintf (t, "=?%s?q?", said_charset); while (*string) { if (*string == ' ') *(t++) = '_'; - else if (*string <= 0x1f || *string >= 0x7f || *string == '=' || *string == '?') - t += sprintf(t, "=%2x", (unsigned char)*string); + else if ((*string <= 0x1f) || (*string >= 0x7f) || (*string == '=') || (*string == '?')) + t += sprintf (t, "=%2x", (unsigned char)*string); else *(t++) = *string; string++; } - t += sprintf(t, "?="); + t += sprintf (t, "?="); *t = 0; return temp; } @@ -268,21 +275,21 @@ static gchar *encode_word (const gchar *string, const gchar *said_charset) { gchar * gmime_rfc2047_encode (const gchar *string, const gchar *charset) { - int temp_len = strlen(string)*4 + 1; - char *temp = g_malloc(temp_len), *temp_2 = temp; - int string_length = strlen(string); + int temp_len = strlen (string)*4 + 1; + char *temp = g_malloc (temp_len), *temp_2 = temp; + int string_length = strlen (string); char *encoded = NULL; /* first, let us convert to UTF-8 */ - iconv_t i = unicode_iconv_open("UTF-8", charset); - unicode_iconv(i, &string, &string_length, &temp_2, &temp_len); - unicode_iconv_close(i); + iconv_t i = unicode_iconv_open ("UTF-8", charset); + unicode_iconv (i, &string, &string_length, &temp_2, &temp_len); + unicode_iconv_close (i); /* null terminate it */ *temp_2 = 0; /* now encode it as if it were a single word */ - encoded = encode_word(temp, "UTF-8"); + encoded = encode_word (temp, "UTF-8"); /* diff --git a/devel-docs/misc/ref_and_id_proposition.txt b/devel-docs/misc/ref_and_id_proposition.txt new file mode 100644 index 0000000000..757fa7b2cd --- /dev/null +++ b/devel-docs/misc/ref_and_id_proposition.txt @@ -0,0 +1,99 @@ +Hi everyone, + +This mail talks about problems related to message referencing in +Camel. I would like to get people thoughts about two specific issues: + +1) How to identify reliably messages within folders. +2) How to handle references in folders to messages physically stored + in other folders. + + + + +Currently, in Camel there is only one way to retrieve a message from a +mail store: + CamelMimeMessage * + get_message (CamelFolder *folder, gint number) + +where number is an integer representing the message rank within its +parent folder. + +This is a traditional method (JavaMail, MAPI) and it is very useful +because this is often the only way to get a message from a classical +store (pop3 for example). + +Moreover, various documents ([1], [2]) proposed to generalize the URL +scheme used in Camel ([3]) to access mail stores to identify +messages. For instance: + +pop3://po.myisp.com:1 + + +However, referencing a message with its number within a folder is a +very unreliable method: + +1) Message order in a folder can change during a session: + + The user can move or remove messages from the folder, thus + completely changing message numbers. We could however imagine to + follow message operations in order to keep camel in a coherent + state at each time instant. This could be quite complex but may + be feasible using gtk signal system. + +2) Message order can change between sessions: + + Gnome-mailer was designed from the begining to allow messages to be + stored in classical mailboxes (mbox, maildir, MH, IMAP ...), in + order to allow users to run other MUA on their mailboxes if + necessary. These other MUA can change message order within folders + without any chance for Camel to trace the operations. + +These two scenarii show that it is quite impossible to use reliable +folder caching or message referencing if messages are referenced only +with their position within their parent folder. + + +We thus have to find a general way to identify and retreive a message +within its folder. One thing is sure, however: all folders +implementation won't allow this method. Pop3 stores will always access +messages using their rank on the server. MUA using will thus have to be +prepared to access some stores providing only the old fashionned message +number access method. + +Basically, we have two choices: + +1) Accessing messages using (mailbox) Unique ID (UID) + + A UID is a string identifier associated to a message, which is + guaranteed to be unique within its parent folder and which will not + to change between sessions. + +2) Accessing messages using Message ID + + A Message ID is a string identifier associated to a messages which + is guaranteed to be unique in the world, that is, no other message + can have the same Message ID. The message ID is defined and RFC 822, and + is stored as a message header + Message-id: ... + +(1) Already exists in IMAP. It is quite simple to define on local +stores (MH, mbox, ....) but may not resist to message modification by +other MUA. Methods based on Message-id matching or message +content-checksum seem to be the best one. Using an "X-" header is +another possibility on non-read only headers. A combination of these +three methods may be the most reliable solution. +Impossible to implement on POP3 + +(2) Can be used with IMAP, but would be very ineficient. The main +issue with this method is its dependancy upon other MUAs and +MTAs. Message-id is set during message transport. Moreover, some +messages may even not have anay Message-id header. These are major +issues when accessing read-only stores. +Impossible to implement on POP3 + + + + +[1] : http://www.selequa.com/%7epurp/gnomail/mail2db.html +[2] : http://www.selequa.com/%7epurp/gnomail/dbRecFmt.html +[3] : http://www.gnome.org/mailing-lists/archives/gnome-mailer-list/1999-April/0248.shtml \ No newline at end of file -- cgit