sync
svn path=/trunk/; revision=1099
This commit is contained in:
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
/*
|
||||
|
||||
|
||||
99
devel-docs/misc/ref_and_id_proposition.txt
Normal file
99
devel-docs/misc/ref_and_id_proposition.txt
Normal file
@ -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
|
||||
Reference in New Issue
Block a user