Patch: set of fixes for Bodystruct backend
- From: José Dapena Paz <jdapena igalia com>
- To: tinymail-devel-list <tinymail-devel-list gnome org>
- Subject: Patch: set of fixes for Bodystruct backend
- Date: Mon, 30 Nov 2009 15:54:52 +0100
Hi,
This patch is a set of fixes for bodystruct support in tinymail:
* Enables bodystruct usage for IMAP by default.
* Fixes charset handling for text/plain bodies in bodystruct backend.
* Method tny_camel_bs_mime_part_is_fetched, to know if an specific mime
part has been already retrieved.
* Added global filter to bodystructure retrieve strategy, so that
get_msg downloads not only the headers strutcture, but also the parts
that we expect to be bodies.
* Fixes in imap message cache reload
* Fixed fetching the header (as it won't be a TnyCamelMsgHeader in some
cases it was expected to be that).
* Fix storing "allow external images" flag in bodystructure backend.
* In bodystruct mime parts, "generate" some flags if the part is not
retrieved. I.e., mime part size, so that we can offer this number even
when the mime part is not fetched.
Though the patch is for modest-3-2 branch, I would ask for careful
review, as the goal is having this both in tinymail trunk and our
modest-3-2 branch.
--
José Dapena Paz <jdapena igalia com>
Igalia
diff --git a/configure.ac b/configure.ac
index faf607c..73b7c72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -220,6 +220,7 @@ esac],[build_demoui=$build_demoui])
AM_CONDITIONAL(BUILD_DEMOUI, test x$build_demoui = xtrue)
dnl ### Enable IMAP part-fetch feature ##
+build_imapp=true
AC_ARG_ENABLE(imap-part-fetch,
AC_HELP_STRING([--enable-imap-part-fetch],
[Build using imap part fetch]),
@@ -654,6 +655,7 @@ echo " Enable GNOME features: $build_gnome"
echo " Enable ACAP features: $build_acap"
echo " Enable Telepathy features: $build_tp"
echo " HTML component: ${with_html_component}"
+echo " Enable Bodystruct support: ${build_imapp}"
echo " Python language bindings: $build_pytinymail"
echo " API tests: $build_apitests"
echo " Unit tests: $build_unittests"
diff --git a/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-message-cache.c b/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-message-cache.c
index 7bf6b01..5479cad 100644
--- a/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-message-cache.c
+++ b/libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-message-cache.c
@@ -184,10 +184,10 @@ camel_imap_message_cache_new (const char *path, CamelFolderSummary *summary,
while ((dname = g_dir_read_name (dir))) {
if (!isdigit (dname[0]))
continue;
- p = strchr (dname, '.');
+ p = strchr (dname, '_');
if (p)
uid = g_strndup (dname, p - dname);
- else if ((p = strchr (dname, '_')))
+ else if ((p = strchr (dname, '.')))
uid = g_strndup (dname, p - dname);
else {
g_warning("Cache file name Invalid\n");
@@ -351,14 +351,18 @@ cachefile_get(const char *path, const char *uid, const char *part_spec)
} else {
char tmp [512];
- snprintf(tmp, 512, "%s.~", uid);
- file = g_build_filename(path, tmp, NULL);
- if (!g_file_test(tmp, G_FILE_TEST_IS_REGULAR)) {
- /* Test if old cache file exists (like "uid."*/
- int len = strlen(file);
- file [len -1] = '\0';
+ snprintf(tmp, 512, "%s_bodystructure", uid);
+ file = g_build_filename (path, tmp, NULL);
+ if (!g_file_test (file, G_FILE_TEST_IS_REGULAR)) {
+ snprintf(tmp, 512, "%s.~", uid);
+ file = g_build_filename(path, tmp, NULL);
if (!g_file_test(file, G_FILE_TEST_IS_REGULAR)) {
- file [len -1] = '~';
+ /* Test if old cache file exists (like "uid."*/
+ int len = strlen(file);
+ file [len -1] = '\0';
+ if (!g_file_test(file, G_FILE_TEST_IS_REGULAR)) {
+ file [len -1] = '~';
+ }
}
}
}
diff --git a/libtinymail-camel/tny-camel-bs-mime-part.c b/libtinymail-camel/tny-camel-bs-mime-part.c
index 9a73de1..c991367 100644
--- a/libtinymail-camel/tny-camel-bs-mime-part.c
+++ b/libtinymail-camel/tny-camel-bs-mime-part.c
@@ -178,7 +178,9 @@ decode_from_stream_to (TnyMimePart *self, TnyStream *from_stream, TnyStream *str
gssize bytes_written = -1;
TnyCamelBsMimePartPriv *priv = TNY_CAMEL_BS_MIME_PART_GET_PRIVATE (self);
- if (decode_text && camel_strcase_equal (priv->bodystructure->content.type, "TEXT"))
+ if (decode_text &&
+ camel_strcase_equal (priv->bodystructure->content.type, "TEXT") &&
+ camel_strcase_equal (priv->bodystructure->content.subtype, "PLAIN"))
{
gchar *encoding = NULL;
gchar *charset = (gchar *) mimeparam_get_value_for (priv->bodystructure->content.params, "CHARSET");
@@ -259,39 +261,120 @@ tny_camel_bs_mime_part_get_header_pairs (TnyMimePart *self, TnyList *list)
return;
}
+static gchar *
+create_content_type_string (bodystruct_t *bs)
+{
+ GString *buffer;
+ mimeparam_t *current;
+
+ buffer = g_string_new ("");
+ g_string_append_printf (buffer, "%s/%s",
+ bs->content.type,
+ bs->content.subtype);
+ buffer = g_string_ascii_down (buffer);
+
+ for (current = bs->content.params; current != NULL; current = current->next) {
+ gchar *down;
+ buffer = g_string_append (buffer, "; ");
+ down = g_ascii_strdown (current->name, -1);
+ buffer = g_string_append (buffer, down);
+ g_free (down);
+ buffer = g_string_append (buffer, "=");
+ buffer = g_string_append (buffer, current->value);
+ }
+
+ if (bs->content.cid != NULL ) {
+ g_string_append_printf (buffer, "; cid=%s", bs->content.cid);
+ }
+ if (bs->content.md5 != NULL ) {
+ g_string_append_printf (buffer, "; md5=%s", bs->content.md5);
+ }
+
+ return g_string_free (buffer, FALSE);
+}
+
+static gchar *
+create_disposition_string (bodystruct_t *bs)
+{
+ GString *buffer;
+ mimeparam_t *current;
+
+ buffer = g_string_new (bs->disposition.type);
+
+ for (current = bs->disposition.params; current != NULL; current = current->next) {
+ gchar *down;
+ buffer = g_string_append (buffer, "; ");
+ down = g_ascii_strdown (current->name, -1);
+ buffer = g_string_append (buffer, down);
+ g_free (down);
+ buffer = g_string_append (buffer, "=");
+ buffer = g_string_append (buffer, current->value);
+ }
+
+ if (bs->octets > 0) {
+ g_string_append_printf (buffer, "; size=%d", bs->octets);
+ }
+
+ return g_string_free (buffer, FALSE);
+}
+
static void
tny_camel_bs_mime_part_get_header_pairs_default (TnyMimePart *self, TnyList *list)
{
TnyCamelBsMimePartPriv *priv = TNY_CAMEL_BS_MIME_PART_GET_PRIVATE (self);
- if (!priv->parent && TNY_IS_MSG (self)) {
- CamelFolderPartState state;
- CamelFolder *cfolder = _tny_camel_folder_get_camel_folder (TNY_CAMEL_FOLDER (priv->folder));
- gchar *pos_filename = camel_folder_get_cache_filename (cfolder,
- priv->uid, "HEADER", &state);
-
- if (pos_filename) {
- FILE *f = fopen (pos_filename, "r");
- if (f) {
- while (!feof (f)) {
- gchar buffer[1024];
- gchar *ptr;
- memset (buffer, 0, 1024);
- fgets (buffer, 1024, f);
- ptr = strchr (buffer, ':');
- if (ptr) {
- TnyPair *pair;
- *ptr='\0';
- ptr++;
- pair = tny_pair_new (buffer, ptr);
- tny_list_append (list, (GObject *) pair);
- g_object_unref (pair);
- }
- }
-
- fclose (f);
- }
- g_free (pos_filename);
+ CamelFolderPartState state;
+ CamelFolder *cfolder = _tny_camel_folder_get_camel_folder (TNY_CAMEL_FOLDER (priv->folder));
+ gchar *pos_filename = camel_folder_get_cache_filename (cfolder,
+ priv->uid, "HEADER", &state);
+
+ if (pos_filename && !priv->parent && TNY_IS_MSG (self)) {
+ FILE *f = fopen (pos_filename, "r");
+ if (f) {
+ while (!feof (f)) {
+ gchar buffer[1024];
+ gchar *ptr;
+ memset (buffer, 0, 1024);
+ fgets (buffer, 1024, f);
+ ptr = strchr (buffer, ':');
+ if (ptr) {
+ TnyPair *pair;
+ *ptr='\0';
+ ptr++;
+ pair = tny_pair_new (buffer, ptr);
+ tny_list_append (list, (GObject *) pair);
+ g_object_unref (pair);
+ }
+ }
+
+ fclose (f);
+ }
+ g_free (pos_filename);
+ } else {
+ /* extract from bodystructure the retrieved headers */
+ TnyPair *pair;
+ gchar *disposition_string;
+ gchar *content_type_string;
+
+ if (priv->bodystructure->description) {
+ pair = tny_pair_new ("Description", priv->bodystructure->description);
+ tny_list_append (list, (GObject *) pair);
+ g_object_unref (pair);
}
+ disposition_string = create_disposition_string (priv->bodystructure);
+ if (disposition_string) {
+ pair = tny_pair_new ("Content-Disposition", disposition_string);
+ tny_list_append (list, (GObject *) pair);
+ g_object_unref (pair);
+ g_free (disposition_string);
+ }
+ content_type_string = create_content_type_string (priv->bodystructure);
+ if (content_type_string) {
+ pair = tny_pair_new ("Content-Type", content_type_string);
+ tny_list_append (list, (GObject *) pair);
+ g_object_unref (pair);
+ g_free (content_type_string);
+ }
+
}
return;
@@ -757,7 +840,7 @@ tny_camel_bs_mime_part_is_purged_default (TnyMimePart *self)
gboolean retval = FALSE;
if (pos_filename) {
- retval = TRUE;
+ retval = FALSE;
g_free (pos_filename);
}
@@ -998,6 +1081,23 @@ _tny_camel_bs_mime_part_set_strat (TnyCamelBsMimePart *self, TnyCamelBsMsgReceiv
return;
}
+gboolean
+tny_camel_bs_mime_part_is_fetched (TnyCamelBsMimePart *part)
+{
+ TnyCamelBsMimePartPriv *priv = TNY_CAMEL_BS_MIME_PART_GET_PRIVATE (part);
+ CamelFolderPartState state;
+ CamelFolder *cfolder = _tny_camel_folder_get_camel_folder (TNY_CAMEL_FOLDER (priv->folder));
+ gchar *pos_filename = camel_folder_get_cache_filename (cfolder,
+ priv->uid, priv->bodystructure->part_spec, &state);
+
+ if (pos_filename) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static void
tny_camel_bs_mime_part_finalize (GObject *object)
{
diff --git a/libtinymail-camel/tny-camel-bs-mime-part.h b/libtinymail-camel/tny-camel-bs-mime-part.h
index 3972901..b2ebf46 100644
--- a/libtinymail-camel/tny-camel-bs-mime-part.h
+++ b/libtinymail-camel/tny-camel-bs-mime-part.h
@@ -79,6 +79,8 @@ struct _TnyCamelBsMimePartClass
GType tny_camel_bs_mime_part_get_type (void);
+gboolean tny_camel_bs_mime_part_is_fetched (TnyCamelBsMimePart *part);
+
G_END_DECLS
diff --git a/libtinymail-camel/tny-camel-bs-msg-header.c b/libtinymail-camel/tny-camel-bs-msg-header.c
index e8e5a36..502f2cf 100644
--- a/libtinymail-camel/tny-camel-bs-msg-header.c
+++ b/libtinymail-camel/tny-camel-bs-msg-header.c
@@ -105,7 +105,7 @@ tny_camel_bs_msg_header_dup_bcc (TnyHeader *self)
static TnyHeaderFlags
tny_camel_bs_msg_header_get_flags (TnyHeader *self)
{
- return 0;
+ return TNY_HEADER_FLAG_CACHED;
}
static void
diff --git a/libtinymail-camel/tny-camel-bs-msg-receive-strategy.c b/libtinymail-camel/tny-camel-bs-msg-receive-strategy.c
index e70b133..1f1374b 100644
--- a/libtinymail-camel/tny-camel-bs-msg-receive-strategy.c
+++ b/libtinymail-camel/tny-camel-bs-msg-receive-strategy.c
@@ -50,6 +50,8 @@
#include <tny-camel-bs-mime-part.h>
#include <tny-fs-stream.h>
+#include <tny-simple-list.h>
+#include <tny-camel-stream.h>
#include "tny-camel-account-priv.h"
#include "tny-camel-folder-priv.h"
@@ -57,6 +59,8 @@
#include "tny-camel-bs-msg-priv.h"
#include "tny-camel-bs-mime-part-priv.h"
+static TnyCamelBsMsgReceiveStrategyBodiesFilter _bodies_filter = NULL;
+
static GObjectClass *parent_class = NULL;
static TnyMsg *
@@ -149,6 +153,37 @@ tny_camel_bs_msg_receive_strategy_perform_get_msg_default (TnyMsgReceiveStrategy
_tny_camel_bs_mime_part_set_strat (TNY_CAMEL_BS_MIME_PART (message),
TNY_CAMEL_BS_MSG_RECEIVE_STRATEGY (self));
+ /* If there are bodies to fetch, fetch them */
+ if (_bodies_filter) {
+ TnyList *bodies;
+ TnyIterator *iterator;
+
+ bodies = TNY_LIST (tny_simple_list_new ());
+ _bodies_filter (message, bodies);
+ for (iterator = tny_list_create_iterator (bodies);
+ !tny_iterator_is_done (iterator) && (err && !*err);
+ tny_iterator_next (iterator)) {
+ TnyMimePart *body;
+ CamelStream *null_stream;
+ TnyStream *tny_null_stream;
+
+ body = TNY_MIME_PART (tny_iterator_get_current (iterator));
+ null_stream = camel_stream_null_new ();
+ tny_null_stream = tny_camel_stream_new (null_stream);
+ tny_mime_part_write_to_stream (body, tny_null_stream, err);
+ g_object_unref (tny_null_stream);
+
+ g_object_unref (body);
+ }
+ g_object_unref (iterator);
+ g_object_unref (bodies);
+
+ if (err && *err != NULL) {
+ g_object_unref (message);
+ return NULL;
+ }
+ }
+ tny_header_set_flag (TNY_HEADER (header), TNY_HEADER_FLAG_CACHED);
} else
message = NULL;
@@ -185,7 +220,6 @@ tny_camel_bs_msg_receive_strategy_new (void)
return TNY_MSG_RECEIVE_STRATEGY (self);
}
-
static void
tny_camel_bs_msg_receive_strategy_class_init (TnyCamelBsMsgReceiveStrategyClass *klass)
{
@@ -197,6 +231,7 @@ tny_camel_bs_msg_receive_strategy_class_init (TnyCamelBsMsgReceiveStrategyClass
klass->perform_get_msg= tny_camel_bs_msg_receive_strategy_perform_get_msg_default;
object_class->finalize = tny_camel_bs_msg_receive_strategy_finalize;
+
}
static void
@@ -249,3 +284,9 @@ tny_camel_bs_msg_receive_strategy_get_type (void)
g_once (&once, tny_camel_bs_msg_receive_strategy_register_type, NULL);
return GPOINTER_TO_UINT (once.retval);
}
+
+void
+tny_camel_bs_msg_receive_strategy_set_global_bodies_filter (TnyCamelBsMsgReceiveStrategyBodiesFilter filter)
+{
+ _bodies_filter = filter;
+}
diff --git a/libtinymail-camel/tny-camel-bs-msg-receive-strategy.h b/libtinymail-camel/tny-camel-bs-msg-receive-strategy.h
index 0d717ac..b0c1665 100644
--- a/libtinymail-camel/tny-camel-bs-msg-receive-strategy.h
+++ b/libtinymail-camel/tny-camel-bs-msg-receive-strategy.h
@@ -24,6 +24,8 @@
#include <tny-msg-receive-strategy.h>
#include <tny-camel-bs-mime-part.h>
+#include <tny-msg.h>
+#include <tny-list.h>
G_BEGIN_DECLS
@@ -34,6 +36,8 @@ G_BEGIN_DECLS
#define TNY_IS_CAMEL_BS_MSG_RECEIVE_STRATEGY_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_CAMEL_BS_MSG_RECEIVE_STRATEGY))
#define TNY_CAMEL_BS_MSG_RECEIVE_STRATEGY_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_CAMEL_BS_MSG_RECEIVE_STRATEGY, TnyCamelBsMsgReceiveStrategyClass))
+typedef void (*TnyCamelBsMsgReceiveStrategyBodiesFilter) (TnyMsg *msg, TnyList *list);
+
typedef struct _TnyCamelBsMsgReceiveStrategy TnyCamelBsMsgReceiveStrategy;
typedef struct _TnyCamelBsMsgReceiveStrategyClass TnyCamelBsMsgReceiveStrategyClass;
@@ -54,6 +58,9 @@ struct _TnyCamelBsMsgReceiveStrategyClass
GType tny_camel_bs_msg_receive_strategy_get_type (void);
TnyMsgReceiveStrategy* tny_camel_bs_msg_receive_strategy_new (void);
+void tny_camel_bs_msg_receive_strategy_set_global_bodies_filter (TnyCamelBsMsgReceiveStrategyBodiesFilter filter);
+
+
TnyStream * tny_camel_bs_msg_receive_strategy_start_receiving_part (TnyCamelBsMsgReceiveStrategy *self, TnyFolder *folder, TnyCamelBsMimePart *part, gboolean *binary, GError **err);
G_END_DECLS
diff --git a/libtinymail-camel/tny-camel-bs-msg.c b/libtinymail-camel/tny-camel-bs-msg.c
index 8377f77..75599dc 100644
--- a/libtinymail-camel/tny-camel-bs-msg.c
+++ b/libtinymail-camel/tny-camel-bs-msg.c
@@ -108,31 +108,39 @@ tny_camel_bs_msg_get_url_string_default (TnyMsg *self)
{
TnyCamelBsMsgPriv *priv = TNY_CAMEL_BS_MSG_GET_PRIVATE (self);
gchar *retval = NULL;
+ TnyFolder *folder;
+
+ TnyHeader *header = tny_msg_get_header (self);
+ gchar *uid = tny_header_dup_uid (header);
if (priv->folder) {
- TnyHeader *header = tny_msg_get_header (self);
- gchar *uid = tny_header_dup_uid (header);
-
- if (uid) {
- TnyCamelFolderPriv *fpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (priv->folder);
- if (fpriv->iter && fpriv->iter->uri) {
- retval = g_strdup_printf ("%s/%s", fpriv->iter->uri, uid);
-
- } else if (fpriv->account) {
- TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (fpriv->account);
- if (apriv->service) {
- char *urls = camel_service_get_url (apriv->service);
- CamelFolder *cfol = _tny_camel_folder_get_camel_folder (TNY_CAMEL_FOLDER (priv->folder));
- const char *foln = camel_folder_get_full_name (cfol);
- retval = g_strdup_printf ("%s/%s/%s", urls, foln, uid);
- g_free (urls);
- }
+ folder = g_object_ref (priv->folder);
+ } else if (header) {
+ folder = tny_header_get_folder (header);
+ } else {
+ folder = NULL;
+ }
+
+ if (uid && folder) {
+ TnyCamelFolderPriv *fpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (priv->folder);
+ if (fpriv->iter && fpriv->iter->uri) {
+ retval = g_strdup_printf ("%s/%s", fpriv->iter->uri, uid);
+
+ } else if (fpriv->account) {
+ TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (fpriv->account);
+ if (apriv->service) {
+ char *urls = camel_service_get_url (apriv->service);
+ CamelFolder *cfol = _tny_camel_folder_get_camel_folder (TNY_CAMEL_FOLDER (priv->folder));
+ const char *foln = camel_folder_get_full_name (cfol);
+ retval = g_strdup_printf ("%s/%s/%s", urls, foln, uid);
+ g_free (urls);
}
- g_free (uid);
}
-
- g_object_unref (header);
+ g_free (uid);
}
+
+ g_object_unref (header);
+ if (folder) g_object_unref (folder);
return retval;
}
@@ -157,11 +165,20 @@ tny_camel_bs_msg_get_allow_external_images_default (TnyMsg *self)
TnyCamelBsMsgPriv *priv = TNY_CAMEL_BS_MSG_GET_PRIVATE (self);
gboolean allow = FALSE;
- if (priv->folder && priv->header) {
+ if (priv->header) {
gchar *uid;
+ TnyFolder *folder;
uid = tny_header_dup_uid (priv->header);
- allow = _tny_camel_folder_get_allow_external_images (TNY_CAMEL_FOLDER(priv->folder),
- uid);
+ if (priv->folder) {
+ folder = g_object_ref (priv->folder);
+ } else {
+ folder = tny_header_get_folder (priv->header);
+ }
+ if (folder) {
+ allow = _tny_camel_folder_get_allow_external_images (TNY_CAMEL_FOLDER(folder),
+ uid);
+ g_object_unref (folder);
+ }
g_free (uid);
}
return allow;
@@ -178,11 +195,20 @@ tny_camel_bs_msg_set_allow_external_images_default (TnyMsg *self, gboolean allow
{
TnyCamelBsMsgPriv *priv = TNY_CAMEL_BS_MSG_GET_PRIVATE (self);
- if (priv->folder && priv->header) {
+ if (priv->header) {
gchar *uid;
+ TnyFolder *folder;
uid = tny_header_dup_uid (priv->header);
- _tny_camel_folder_set_allow_external_images (TNY_CAMEL_FOLDER(priv->folder),
- uid, allow);
+ if (priv->folder) {
+ folder = g_object_ref (priv->folder);
+ } else {
+ folder = tny_header_get_folder (priv->header);
+ }
+ if (folder) {
+ _tny_camel_folder_set_allow_external_images (TNY_CAMEL_FOLDER(folder),
+ uid, allow);
+ g_object_unref (folder);
+ }
g_free (uid);
}
return;
diff --git a/libtinymail-camel/tny-camel-folder.c b/libtinymail-camel/tny-camel-folder.c
index b689d70..d1b26ba 100644
--- a/libtinymail-camel/tny-camel-folder.c
+++ b/libtinymail-camel/tny-camel-folder.c
@@ -3172,7 +3172,9 @@ tny_camel_folder_find_msg_default (TnyFolder *self, const gchar *url_string, GEr
if (retval) {
nhdr = tny_msg_get_header (retval);
/* This trick is for forcing owning a TnyCamelHeader reference */
- _tny_camel_msg_header_set_decorated ((TnyCamelMsgHeader *) nhdr, hdr, TRUE);
+ if (hdr != nhdr && TNY_IS_CAMEL_MSG_HEADER (nhdr)) {
+ _tny_camel_msg_header_set_decorated ((TnyCamelMsgHeader *) nhdr, hdr, TRUE);
+ }
g_object_unref (nhdr);
}
g_object_unref (hdr);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]