aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-utils.c
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2001-01-17 08:27:19 +0800
committerDan Winship <danw@src.gnome.org>2001-01-17 08:27:19 +0800
commit8ad855fef6632e32723242fda554fce04f025036 (patch)
treefea4a94685bb6504bb679111f0e9e84e0f9ad835 /camel/providers/imap/camel-imap-utils.c
parent35edf4f02ace2559daea85c11c8f36efc7fe0b80 (diff)
downloadgsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar.gz
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar.bz2
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar.lz
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar.xz
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.tar.zst
gsoc2013-evolution-8ad855fef6632e32723242fda554fce04f025036.zip
Delayed loading of IMAP message parts.
* camel-types.h: typedef CamelMessageInfo and CamelMessageContentInfo here * camel-folder-summary.h: Add a "size" field to CamelMessageContentInfo. * camel-folder-summary.c (camel_folder_summary_content_info_new, camel_folder_summary_content_info_free): Renamed and made non-static for providers that construct their own content info. (content_info_load, content_info_save): load/save size * camel-data-wrapper.c (camel_data_wrapper_is_offline): New function to return if a data wrapper's contents are "offline". (So that, for example, we don't make thumbnails of images that haven't been loaded off the IMAP server yet.) Defaults to FALSE. * providers/imap/camel-imap-folder.c (camel_imap_folder_selected): Fix a bug in re-selecting a folder when messages have been expunged from it by another client in the meantime. (imap_get_message): Rewrite. If the message is larger than a certain size, just create a skeleton message containing CamelImapWrappers that will read parts as needed. This way, large attachments only need to be downloaded if the user looks at them, and multipart/alternative alternatives that aren't used will never be downloaded at all. (imap_update_summary): Rewrite this a bunch too to make the parsing more robust. * providers/imap/camel-imap-summary.c (CAMEL_IMAP_SUMMARY_VERSION): bump. (camel_imap_summary_new): Set build_content to TRUE. (content_info_load, content_info_save): Only save/load the content for messages that have it. (The content info gets created as a side effect of imap_get_message.) * providers/imap/camel-imap-utils.c (imap_parse_body): New routine (and helpers) to parse an IMAP 'body' FETCH response and fill in a CamelMessageContentInfo from it. * providers/imap/Makefile.am (libcamelimap_la_SOURCES, libcamelimap_la_HEADERS): add camel-imap-wrapper. svn path=/trunk/; revision=7557
Diffstat (limited to 'camel/providers/imap/camel-imap-utils.c')
-rw-r--r--camel/providers/imap/camel-imap-utils.c250
1 files changed, 246 insertions, 4 deletions
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index 1b4aaba499..8116f12386 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -25,11 +25,9 @@
#include <string.h>
#include <time.h>
-#include <gtk/gtk.h>
#include "camel-imap-utils.h"
-#include "string-utils.h"
-#include <e-sexp.h>
-#include "camel/camel-folder-summary.h"
+#include "camel-imap-summary.h"
+#include "camel-folder.h"
#define d(x) x
@@ -290,6 +288,250 @@ imap_parse_string_generic (char **str_p, int *len, int type)
}
}
+static inline void
+skip_char (char **str_p, char ch)
+{
+ if (*str_p && **str_p == ch)
+ *str_p = *str_p + 1;
+ else
+ *str_p = NULL;
+}
+
+/* Skip atom, string, or number */
+static void
+skip_asn (char **str_p)
+{
+ char *str = *str_p;
+
+ if (!str)
+ return;
+ else if (*str == '"') {
+ while (*++str && *str != '"') {
+ if (*str == '\\') {
+ str++;
+ if (!*str)
+ break;
+ }
+ }
+ if (*str == '"')
+ *str_p = str + 1;
+ else
+ *str_p = NULL;
+ } else if (*str == '{') {
+ unsigned long len;
+
+ len = strtoul (str + 1, &str, 10);
+ if (*str != '}' || *(str + 1) != '\n' ||
+ strlen (str + 2) < len) {
+ *str_p = NULL;
+ return;
+ }
+ *str_p = str + 2 + len;
+ } else {
+ /* We assume the string is well-formed and don't
+ * bother making sure it's a valid atom.
+ */
+ while (*str && *str != ')' && *str != ' ')
+ str++;
+ *str_p = str;
+ }
+}
+
+static void
+skip_list (char **str_p)
+{
+ skip_char (str_p, '(');
+ while (*str_p && **str_p != ')') {
+ if (**str_p == '(')
+ skip_list (str_p);
+ else
+ skip_asn (str_p);
+ if (*str_p && **str_p == ' ')
+ skip_char (str_p, ' ');
+ }
+ skip_char (str_p, ')');
+}
+
+static void
+parse_params (char **parms_p, CamelContentType *type)
+{
+ char *parms = *parms_p, *name, *value;
+ int len;
+
+ if (!g_strncasecmp (parms, "nil", 3)) {
+ *parms_p += 3;
+ return;
+ }
+
+ if (*parms++ != '(') {
+ *parms_p = NULL;
+ return;
+ }
+
+ while (parms && *parms != ')') {
+ name = imap_parse_nstring (&parms, &len);
+ skip_char (&parms, ' ');
+ value = imap_parse_nstring (&parms, &len);
+
+ if (name && value)
+ header_content_type_set_param (type, name, value);
+ g_free (name);
+ g_free (value);
+
+ if (parms && *parms == ' ')
+ parms++;
+ }
+
+ if (!parms || *parms++ != ')') {
+ *parms_p = NULL;
+ return;
+ }
+ *parms_p = parms;
+}
+
+/**
+ * imap_parse_body:
+ * @body_p: pointer to the start of an IMAP "body"
+ * @folder: an imap folder
+ * @ci: a CamelMessageContentInfo to fill in
+ *
+ * This filles in @ci with data from *@body_p. On success *@body_p
+ * will point to the character after the body. On failure, it will be
+ * set to %NULL and @ci will be unchanged.
+ **/
+void
+imap_parse_body (char **body_p, CamelFolder *folder,
+ CamelMessageContentInfo *ci)
+{
+ char *body = *body_p;
+ CamelMessageContentInfo *child;
+ CamelContentType *type;
+ int len;
+
+ if (*body++ != '(') {
+ *body_p = NULL;
+ return;
+ }
+
+ if (*body == '(') {
+ /* multipart */
+ GPtrArray *children;
+ char *subtype;
+ int i;
+
+ /* Parse the child body parts */
+ children = g_ptr_array_new ();
+ i = 0;
+ while (body && *body == '(') {
+ child = camel_folder_summary_content_info_new (folder->summary);
+ g_ptr_array_add (children, child);
+ imap_parse_body (&body, folder, child);
+ if (!body)
+ break;
+ child->parent = ci;
+ }
+ skip_char (&body, ' ');
+
+ /* Parse the multipart subtype */
+ subtype = imap_parse_string (&body, &len);
+
+ /* If there is a parse error, abort. */
+ if (!body) {
+ for (i = 0; i < children->len; i++) {
+ child = children->pdata[i];
+ camel_folder_summary_content_info_free (folder->summary, child);
+ }
+ g_ptr_array_free (children, TRUE);
+ *body_p = NULL;
+ return;
+ }
+
+ g_strdown (subtype);
+ ci->type = header_content_type_new ("multipart", subtype);
+ g_free (subtype);
+
+ /* Chain the children. */
+ ci->childs = children->pdata[0];
+ ci->size = 0;
+ for (i = 0; i < children->len - 1; i++) {
+ child = children->pdata[i];
+ child->next = children->pdata[i + 1];
+ ci->size += child->size;
+ }
+ g_ptr_array_free (children, TRUE);
+ } else {
+ /* single part */
+ char *main_type, *subtype;
+ char *id, *description, *encoding;
+ guint32 size;
+
+ main_type = imap_parse_string (&body, &len);
+ skip_char (&body, ' ');
+ subtype = imap_parse_string (&body, &len);
+ skip_char (&body, ' ');
+ if (!body) {
+ g_free (main_type);
+ g_free (subtype);
+ *body_p = NULL;
+ return;
+ }
+ g_strdown (main_type);
+ g_strdown (subtype);
+ type = header_content_type_new (main_type, subtype);
+ g_free (main_type);
+ g_free (subtype);
+ parse_params (&body, type);
+ skip_char (&body, ' ');
+
+ id = imap_parse_nstring (&body, &len);
+ skip_char (&body, ' ');
+ description = imap_parse_nstring (&body, &len);
+ skip_char (&body, ' ');
+ encoding = imap_parse_string (&body, &len);
+ skip_char (&body, ' ');
+ if (body)
+ size = strtoul (body, &body, 10);
+
+ child = NULL;
+ if (header_content_type_is (type, "message", "rfc822")) {
+ skip_char (&body, ' ');
+ skip_list (&body); /* envelope */
+ skip_char (&body, ' ');
+ child = camel_folder_summary_content_info_new (folder->summary);
+ imap_parse_body (&body, folder, child);
+ if (!body)
+ camel_folder_summary_content_info_free (folder->summary, child);
+ skip_char (&body, ' ');
+ if (body)
+ strtoul (body, &body, 10);
+ } else if (header_content_type_is (type, "text", "*")) {
+ if (body)
+ strtoul (body, &body, 10);
+ }
+
+ if (body) {
+ ci->type = type;
+ ci->id = id;
+ ci->description = description;
+ ci->encoding = encoding;
+ ci->size = size;
+ ci->childs = child;
+ } else {
+ header_content_type_unref (type);
+ g_free (id);
+ g_free (description);
+ g_free (encoding);
+ }
+ }
+
+ if (!body || *body++ != ')') {
+ *body_p = NULL;
+ return;
+ }
+
+ *body_p = body;
+}
+
/**
* imap_quote_string:
* @str: the string to quote, which must not contain CR or LF