Fixed the hack around quoted string responses - should now handle them
authorJeffrey Stedfast <fejj@helixcode.com>
Mon, 28 Aug 2000 23:47:21 +0000 (23:47 +0000)
committerJeffrey Stedfast <fejj@src.gnome.org>
Mon, 28 Aug 2000 23:47:21 +0000 (23:47 +0000)
2000-08-28  Jeffrey Stedfast  <fejj@helixcode.com>

* providers/imap/camel-imap-folder.c (imap_get_message): Fixed the
hack around quoted string responses - should now handle them
according to the specifications in the RFC

* providers/imap/camel-imap-stream.c (stream_read): Updated to
match the code currently used in camel-imap-folder.c

camel/ChangeLog
camel/providers/imap/camel-imap-folder.c
camel/providers/imap/camel-imap-stream.c

index 9ce35eb..be17adb 100644 (file)
@@ -1,3 +1,12 @@
+2000-08-28  Jeffrey Stedfast  <fejj@helixcode.com>
+
+       * providers/imap/camel-imap-folder.c (imap_get_message): Fixed the
+       hack around quoted string responses - should now handle them
+       according to the specifications in the RFC
+       
+       * providers/imap/camel-imap-stream.c (stream_read): Updated to
+       match the code currently used in camel-imap-folder.c
+
 2000-08-28  Ettore Perazzoli  <ettore@helixcode.com>
 
        * providers/mbox/camel-mbox-summary.c (camel_mbox_summary_sync):
index 78fbe38..33d7d06 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
-/* camel-imap-folder.c: Abstract class for an email folder */
+/* camel-imap-folder.c: Abstract class for an imap folder */
 
 /* 
  * Authors: Jeffrey Stedfast <fejj@helixcode.com> 
@@ -103,19 +103,19 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
        CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_imap_folder_class);
 
        parent_class = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs (camel_folder_get_type ()));
-               
+       
        /* virtual method definition */
-
+       
        /* virtual method overload */
        camel_folder_class->init = imap_init;
        camel_folder_class->sync = imap_sync;
        camel_folder_class->expunge = imap_expunge;
-
+       
        camel_folder_class->get_uids = imap_get_uids;
        camel_folder_class->free_uids = camel_folder_free_nop;
        camel_folder_class->get_subfolder_names = imap_get_subfolder_names;
        camel_folder_class->free_subfolder_names = camel_folder_free_nop;
-
+       
        camel_folder_class->get_message_count = imap_get_message_count;
        camel_folder_class->get_unread_message_count = imap_get_unread_message_count;
        camel_folder_class->get_message = imap_get_message;
@@ -126,9 +126,9 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
        camel_folder_class->get_summary = imap_get_summary;
        camel_folder_class->get_message_info = imap_get_message_info;
        camel_folder_class->free_summary = camel_folder_free_nop;
-
+       
        camel_folder_class->search_by_expression = imap_search_by_expression;
-
+       
        /*camel_folder_class->get_permanent_flags = imap_get_permanent_flags;*/
        camel_folder_class->get_message_flags = imap_get_message_flags;
        camel_folder_class->set_message_flags = imap_set_message_flags;
@@ -157,7 +157,7 @@ camel_imap_folder_get_type (void)
 {
        static CamelType camel_imap_folder_type = CAMEL_INVALID_TYPE;
        
-       if (camel_imap_folder_type == CAMEL_INVALID_TYPE)       {
+       if (camel_imap_folder_type == CAMEL_INVALID_TYPE) {
                camel_imap_folder_type =
                        camel_type_register (CAMEL_FOLDER_TYPE, "CamelImapFolder",
                                             sizeof (CamelImapFolder),
@@ -177,11 +177,11 @@ camel_imap_folder_new (CamelStore *parent, char *folder_name, CamelException *ex
        CamelFolder *folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ()));
        CamelURL *url = CAMEL_SERVICE (parent)->url;
        char *dir_sep;
-
+       
        dir_sep = CAMEL_IMAP_STORE (parent)->dir_sep;
        
        CF_CLASS (folder)->init (folder, parent, NULL, folder_name, dir_sep, FALSE, ex);
+       
        if (!strcmp (folder_name, url->path + 1))
                folder->can_hold_messages = FALSE;
        
@@ -227,14 +227,13 @@ imap_folder_summary_free (CamelImapFolder *imap_folder)
                g_hash_table_destroy (imap_folder->summary_hash);
                imap_folder->summary_hash = NULL;
        }
-
+       
        imap_summary_free (&imap_folder->summary);
 }
 
 static void           
 imap_finalize (CamelObject *object)
 {
-       /* TODO: do we need to do more cleanup here? */
        CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
        gint max, i;
        
@@ -270,9 +269,9 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo
        folder->has_summary_capability = TRUE;
        folder->has_search_capability = TRUE;
        
-        /* some IMAP daemons support user-flags           *
-        * I would not, however, rely on this feature as  *
-        * most IMAP daemons are not 100% RFC compliant   */
+        /* some IMAP daemons support user-flags              *
+        * I would not, however, rely on this feature as     *
+        * most IMAP daemons do not support all the features */
        folder->permanent_flags = CAMEL_MESSAGE_SEEN |
                CAMEL_MESSAGE_ANSWERED |
                CAMEL_MESSAGE_FLAGGED |
@@ -291,7 +290,7 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 {
        CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
        gint i, max;
-
+       
        if (expunge) {
                imap_expunge (folder, ex);
                return;
@@ -631,7 +630,7 @@ imap_copy_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
        CamelURL *url = CAMEL_SERVICE (store)->url;
        char *result, *folder_path, *dir_sep;
        int status;
-
+       
        dir_sep = CAMEL_IMAP_STORE (source->parent_store)->dir_sep;
        
        if (url && url->path && *(url->path + 1) && strcmp (destination->full_name, "INBOX"))
@@ -653,10 +652,10 @@ imap_copy_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
                g_free (folder_path);
                return;
        }
-
+       
        g_free (result);
        g_free (folder_path);
-
+       
        camel_imap_folder_changed (destination, 1, ex);
 }
 
@@ -669,7 +668,7 @@ imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
        CamelMessageInfo *info;
        char *result, *folder_path, *dir_sep;
        int status;
-
+       
        dir_sep = CAMEL_IMAP_STORE (source->parent_store)->dir_sep;
        
        if (url && url->path && *(url->path + 1) && strcmp (destination->full_name, "INBOX"))
@@ -679,7 +678,7 @@ imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
        
        status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), source, &result,
                                              "UID COPY %s %s", uid, folder_path);
-
+       
        if (status != CAMEL_IMAP_OK) {
                CamelService *service = CAMEL_SERVICE (store);
                camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
@@ -691,7 +690,7 @@ imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
                g_free (folder_path);
                return;
        }
-
+       
        g_free (result);
        g_free (folder_path);
        
@@ -703,9 +702,9 @@ imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destina
                                      uid, service->url->host, "Unknown error");
                return;
        }
-
+       
        imap_set_message_flags (source, uid, CAMEL_MESSAGE_DELETED, ~(info->flags));
-
+       
        camel_imap_folder_changed (destination, 1, ex);
 }
 
@@ -740,7 +739,7 @@ imap_get_subfolder_names_internal (CamelFolder *folder, CamelException *ex)
        gboolean found_inbox = FALSE;
        gint status;
        gchar *result, *namespace, *dir_sep;
-
+       
        g_return_val_if_fail (folder != NULL, g_ptr_array_new ());
        
        dir_sep = CAMEL_IMAP_STORE (folder->parent_store)->dir_sep;
@@ -792,7 +791,7 @@ imap_get_subfolder_names_internal (CamelFolder *folder, CamelException *ex)
                                      "Unknown error");
                g_free (result);
                g_free (namespace);
-
+               
                imap_folder->lsub = g_ptr_array_new ();
                return imap_folder->lsub;
        }
@@ -862,10 +861,7 @@ static CamelMimeMessage *
 imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
 {
        CamelStream *msgstream = NULL;
-       /*CamelStreamFilter *f_stream;*/
-       /*CamelMimeFilter *filter;*/
        CamelMimeMessage *msg = NULL;
-       /*CamelMimePart *part;*/
        gchar *result, *header, *body, *mesg, *p, *q, *data_item;
        int status, part_len;
        
@@ -877,7 +873,7 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
        status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder,
                                              &result, "UID FETCH %s %s", uid,
                                              data_item);
-
+       
        if (!result || status != CAMEL_IMAP_OK) {
                CamelService *service = CAMEL_SERVICE (folder->parent_store);
                
@@ -890,28 +886,43 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
                return NULL;
        }
        
-       for (p = result; *p && *p != '{' && *p != '\n'; p++);
-       if (*p != '{') {
-               g_free (result);
-               return NULL;
-       }
-       
-       part_len = atoi (p + 1);
-       for ( ; *p && *p != '\n'; p++);
-       if (*p != '\n') {
+       /* parse out the message part */
+       for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
+       switch (*p) {
+       case '"':
+               /* a quoted string - section 4.3 */
+               p++;
+               for (q = p; *q && *q != '"' && *q != '\n'; q++);
+               part_len = (gint) (q - p);
+               
+               break;
+       case '{':
+               /* a literal string - section 4.3 */
+               part_len = atoi (p + 1);
+               for ( ; *p && *p != '\n'; p++);
+               if (*p != '\n') {
+                       g_free (result);
+                       return NULL;
+               }
+               
+               /* calculate the new part-length */
+               for (q = p; *q && (q - p) <= part_len; q++) {
+                       if (*q == '\n')
+                               part_len--;
+               }
+               
+               /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
+               for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
+               part_len++;
+               
+               break;
+       default:
+               /* Bad input */
                g_free (result);
                return NULL;
        }
        
-       /* calculate the new part-length */
-       for (q = p; *q && (q - p) <= part_len; q++) {
-               if (*q == '\n')
-                       part_len--;
-       }
-       /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
-       for (q--, part_len--; q > p && *(q-1) != '\n'; q--, part_len--);
-
-       header = g_strndup (p, part_len + 1);
+       header = g_strndup (p, part_len);
        
        g_free (result);
        d(fprintf (stderr, "*** We got the header ***\n"));
@@ -938,13 +949,18 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
                return NULL;
        }
        
-       for (p = result; *p && *p != '{' && *p != '\n'; p++);
-       if (*p != '{') {
-               /* this is a hack for when the part length isn't in {}'s */
-               part_len = 1;
-               for ( ; *p && *p != '\n'; p++);
+       /* parse out the message part */
+       for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
+       switch (*p) {
+       case '"':
+               /* a quoted string - section 4.3 */
                p++;
-       } else {
+               for (q = p; *q && *q != '"' && *q != '\n'; q++);
+               part_len = (gint) (q - p);
+               
+               break;
+       case '{':
+               /* a literal string - section 4.3 */
                part_len = atoi (p + 1);
                for ( ; *p && *p != '\n'; p++);
                if (*p != '\n') {
@@ -952,17 +968,26 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
                        g_free (header);
                        return NULL;
                }
+               
+               /* calculate the new part-length */
+               for (q = p; *q && (q - p) <= part_len; q++) {
+                       if (*q == '\n')
+                               part_len--;
+               }
+               
+               /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
+               for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
+               part_len++;
+               
+               break;
+       default:
+               /* Bad input */
+               g_free (result);
+               g_free (header);
+               return NULL;
        }
        
-       /* calculate the new part-length */
-       for (q = p; *q && (q - p) <= part_len; q++) {
-               if (*q == '\n')
-                       part_len--;
-       }
-       /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
-       for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
-       
-       body = g_strndup (p, part_len + 1);
+       body = g_strndup (p, part_len);
        
        g_free (result);
        d(fprintf (stderr, "*** We got the body ***\n"));
@@ -995,51 +1020,6 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
        
        g_free (mesg);
        return msg;
-       
-#if 0
-       CamelStream *imap_stream;
-       CamelStream *msgstream;
-       CamelStreamFilter *f_stream;   /* will be used later w/ crlf filter */
-       CamelMimeFilter *filter;       /* crlf/dot filter */
-       CamelMimeMessage *msg;
-       CamelMimePart *part;
-       CamelDataWrapper *cdw;
-       gchar *cmdbuf;
-       int id;
-       
-       /* TODO: fetch the correct part, get rid of the hard-coded stuff */
-       cmdbuf = g_strdup_printf ("UID FETCH %s BODY[TEXT]", uid);
-       imap_stream = camel_imap_stream_new (CAMEL_IMAP_FOLDER (folder), cmdbuf);
-       g_free (cmdbuf);
-
-
-       /* Temp hack - basically we read in the entire message instead of getting a part as it's needed */
-       msgstream = camel_stream_mem_new ();
-       camel_stream_write_to_stream (CAMEL_STREAM (imap_stream), msgstream);
-       camel_object_unref (CAMEL_OBJECT (imap_stream));
-       
-       f_stream = camel_stream_filter_new_with_stream (msgstream);
-       filter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
-       id = camel_stream_filter_add (f_stream, CAMEL_MIME_FILTER (filter));
-       
-       msg = camel_mime_message_new ();
-       
-       /*cdw = camel_data_wrapper_new ();*/
-       /*camel_data_wrapper_construct_from_stream (cdw, CAMEL_STREAM (f_stream));*/
-       camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), CAMEL_STREAM (f_stream));
-       
-       camel_stream_filter_remove (f_stream, id);
-       camel_stream_close (CAMEL_STREAM (f_stream));
-       camel_object_unref (CAMEL_OBJECT (msgstream));
-       camel_object_unref (CAMEL_OBJECT (f_stream));
-       
-       /*camel_data_wrapper_set_mime_type (cdw, "text/plain");*/
-
-       /*camel_medium_set_content_object (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (cdw));*/
-       /*camel_object_unref (CAMEL_OBJECT (cdw));*/
-       
-       return msg;
-#endif
 }
 
 /* This probably shouldn't go here...but it will for now */
@@ -1047,7 +1027,7 @@ static gchar *
 get_header_field (gchar *header, gchar *field)
 {
        gchar *part, *index, *p, *q;
-
+       
        index = (char *) e_strstrcase (header, field);
        if (index == NULL)
                return NULL;
@@ -1079,7 +1059,7 @@ static char *header_fields[] = { "subject", "from", "to", "cc", "date",
  * Make a data item specifier for the header lines we need,
  * appropriate to the server level.
  *
- * IMAP4rev1:  UID FLAGS BODY[HEADER.FIELDS (SUBJECT FROM .. IN-REPLY-TO)]
+ * IMAP4rev1:  UID FLAGS BODY.PEEK[HEADER.FIELDS (SUBJECT FROM .. IN-REPLY-TO)]
  * IMAP4:      UID FLAGS RFC822.HEADER.LINES (SUBJECT FROM .. IN-REPLY-TO)
  **/
 static char *
@@ -1087,7 +1067,7 @@ imap_protocol_get_summary_specifier (CamelFolder *folder)
 {
        char *sect_begin, *sect_end;
        char *headers_wanted = "SUBJECT FROM TO CC DATE MESSAGE-ID REFERENCES IN-REPLY-TO";
-
+       
        if (CAMEL_IMAP_STORE (folder->parent_store)->server_level >= IMAP_LEVEL_IMAP4REV1) {
                sect_begin = "BODY.PEEK[HEADER.FIELDS";
                sect_end = "]";
@@ -1095,7 +1075,7 @@ imap_protocol_get_summary_specifier (CamelFolder *folder)
                sect_begin = "RFC822.HEADER.LINES";
                sect_end   = "";
        }
-
+       
        return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin, headers_wanted, sect_end);
 }
 
@@ -1113,10 +1093,10 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
        struct _header_raw *h = NULL, *tail = NULL;
        
        num = imap_get_message_count_internal (folder, ex);
-
+       
        /* sync any previously set/changed message flags */
        imap_sync (folder, FALSE, ex);
-
+       
        if (num == 0) {
                /* clean up any previous summary data */
                imap_folder_summary_free (imap_folder);
@@ -1128,7 +1108,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
        }
        
        summary_specifier = imap_protocol_get_summary_specifier (folder);
-
+       
        if (num == 1) {
                status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder,
                                                      &result, "FETCH 1 (%s)", summary_specifier);
@@ -1137,7 +1117,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
                                                      &result, "FETCH 1:%d (%s)", num, summary_specifier);
        }
        g_free (summary_specifier);
-
+       
        if (status != CAMEL_IMAP_OK) {
                CamelService *service = CAMEL_SERVICE (folder->parent_store);
                
@@ -1147,7 +1127,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
                                      status != CAMEL_IMAP_FAIL && result ? result :
                                      "Unknown error");
                g_free (result);
-
+               
                if (!imap_folder->summary) {
                        imap_folder->summary = g_ptr_array_new ();
                        imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -1155,7 +1135,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
                
                return imap_folder->summary;
        }
-
+       
        /* initialize our new summary-to-be */
        summary = g_ptr_array_new ();
        hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -1165,7 +1145,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
        node = result;
        for (i = 1; node; i++) {
                char *end;
-
+               
                if ((end = strstr (node + 2, "\n*"))) {
                        g_ptr_array_add (headers, g_strndup (node, (gint)(end - node)));
                } else {
@@ -1177,16 +1157,16 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
                d(fprintf (stderr, "IMAP server didn't respond with as many headers as we expected...\n"));
                /* should we error?? */
        }
-
+       
        g_free (result);
        result = NULL;
        
        for (i = 0; i < headers->len; i++) {
                CamelMessageInfo *info;
                char *uid, *flags, *header;
-
+               
                info = g_malloc0 (sizeof (CamelMessageInfo));
-
+               
                /* lets grab the UID... */
                if (!(uid = strstr (headers->pdata[i], "UID "))) {
                        d(fprintf (stderr, "Cannot get a uid for %d\n\n%s\n\n", i+1, (char *) headers->pdata[i]));
@@ -1307,7 +1287,7 @@ static GPtrArray *
 imap_get_summary (CamelFolder *folder)
 {
        CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
+       
        return imap_folder->summary;
 }
 
@@ -1321,13 +1301,13 @@ imap_get_message_info_internal (CamelFolder *folder, guint id)
        char *result, *uid, *flags, *header, *q;
        char *summary_specifier;
        int j, status;
-
+       
        /* we don't have a cached copy, so fetch it */
        summary_specifier = imap_protocol_get_summary_specifier (folder);
        
        status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder,
                                              &result, "FETCH %d (%s)", id, summary_specifier);
-
+       
        g_free (summary_specifier);
        
        if (status != CAMEL_IMAP_OK) {
@@ -1345,7 +1325,7 @@ imap_get_message_info_internal (CamelFolder *folder, guint id)
        for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */
        for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the <uid> */
        uid = g_strndup (uid, (gint)(q - uid));
-
+       
        info = g_malloc0 (sizeof (CamelMessageInfo));
        info->uid = uid;
        d(fprintf (stderr, "*** info->uid = %s\n", info->uid));
@@ -1428,7 +1408,7 @@ imap_get_message_info_internal (CamelFolder *folder, guint id)
        info->references = header_references_decode (header_raw_find (&h, "references", NULL));
        if (info->references == NULL)
                info->references = header_references_decode (header_raw_find (&h, "in-reply-to", NULL));
-
+       
        while (h->next) {
                struct _header_raw *next = h->next;
                
@@ -1437,7 +1417,7 @@ imap_get_message_info_internal (CamelFolder *folder, guint id)
                g_free (h);
                h = next;
        }
-
+       
        g_free (result);
        
        return info;
@@ -1448,19 +1428,18 @@ static const CamelMessageInfo *
 imap_get_message_info (CamelFolder *folder, const char *uid)
 {
        CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
-
+       
        g_return_val_if_fail (*uid != '\0', NULL);
-
+       
        if (imap_folder->summary)
                return (CamelMessageInfo *) g_hash_table_lookup (imap_folder->summary_hash, uid);
-
+       
        return NULL;
 }
 
 static GPtrArray *
 imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
 {
-       /* NOTE: This is experimental code... */
        GPtrArray *uids = NULL;
        char *result, *sexp, *p;
        int status;
@@ -1491,7 +1470,7 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc
                g_free (sexp);
                return uids;
        }
-
+       
        if ((p = strstr (result, "* SEARCH"))) {
                char *word;
                
index 7b88543..fcddd4c 100644 (file)
@@ -43,9 +43,9 @@ camel_imap_stream_class_init (CamelImapStreamClass *camel_imap_stream_class)
 {
        CamelStreamClass *camel_stream_class =
                CAMEL_STREAM_CLASS (camel_imap_stream_class);
-
+       
        parent_class = CAMEL_STREAM_CLASS(camel_type_get_global_classfuncs (camel_stream_get_type ()));
-
+       
        /* virtual method overload */
        camel_stream_class->read  = stream_read;
        camel_stream_class->reset = stream_reset;
@@ -56,7 +56,7 @@ static void
 camel_imap_stream_init (gpointer object, gpointer klass)
 {
        CamelImapStream *imap_stream = CAMEL_IMAP_STREAM (object);
-
+       
        imap_stream->cache = NULL;
        imap_stream->cache_ptr = NULL;
 }
@@ -65,7 +65,7 @@ CamelType
 camel_imap_stream_get_type (void)
 {
        static CamelType camel_imap_stream_type = CAMEL_INVALID_TYPE;
-
+       
        if (camel_imap_stream_type == CAMEL_INVALID_TYPE) {
                camel_imap_stream_type = camel_type_register (camel_stream_get_type (), "CamelImapStream",
                                                              sizeof (CamelImapStream),
@@ -75,7 +75,7 @@ camel_imap_stream_get_type (void)
                                                              (CamelObjectInitFunc) camel_imap_stream_init,
                                                              (CamelObjectFinalizeFunc) finalize);
        }
-
+       
        return camel_imap_stream_type;
 }
 
@@ -83,9 +83,9 @@ CamelStream *
 camel_imap_stream_new (CamelImapFolder *folder, char *command)
 {
        CamelImapStream *imap_stream;
-
+       
        imap_stream = CAMEL_IMAP_STREAM(camel_object_new (camel_imap_stream_get_type ()));
-
+       
        imap_stream->folder = folder;
        camel_object_ref (CAMEL_OBJECT (imap_stream->folder));
        
@@ -98,10 +98,10 @@ static void
 finalize (CamelObject *object)
 {
        CamelImapStream *imap_stream = CAMEL_IMAP_STREAM (object);
-
+       
        g_free (imap_stream->cache);
        g_free (imap_stream->command);
-
+       
        if (imap_stream->folder)
                camel_object_unref (CAMEL_OBJECT (imap_stream->folder));
 }
@@ -113,7 +113,7 @@ stream_read (CamelStream *stream, char *buffer, size_t n)
        
        /* do we want to do any IMAP specific parsing in here? If not, maybe rename to camel-stream-cache? */
        CamelImapStream *imap_stream = CAMEL_IMAP_STREAM (stream);
-
+       
        if (!imap_stream->cache) {
                /* We need to send the IMAP command since this is our first fetch */
                CamelFolder *folder = CAMEL_FOLDER (imap_stream->folder);
@@ -136,30 +136,44 @@ stream_read (CamelStream *stream, char *buffer, size_t n)
                
                /* we don't need the folder anymore... */
                camel_object_unref (CAMEL_OBJECT (imap_stream->folder));
-
-               /* parse out the message part */
-               for (p = result; *p && *p != '{' && *p != '\n'; p++);
-               if (*p != '{') {
-                       g_free (result);
-                       return -1;
-               }
                
-               part_len = atoi (p + 1);
-               for ( ; *p && *p != '\n'; p++);
-               if (*p != '\n') {
+               /* parse out the message part */
+               for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
+               switch (*p) {
+               case '"':
+                       /* a quoted string - section 4.3 */
+                       p++;
+                       for (q = p; *q && *q != '"' && *q != '\n'; q++);
+                       part_len = (gint) (q - p);
+                       
+                       break;
+               case '{':
+                       /* a literal string - section 4.3 */
+                       part_len = atoi (p + 1);
+                       for ( ; *p && *p != '\n'; p++);
+                       if (*p != '\n') {
+                               g_free (result);
+                               return -1;
+                       }
+                       
+                       /* calculate the new part-length */
+                       for (q = p; *q && (q - p) <= part_len; q++) {
+                               if (*q == '\n')
+                                       part_len--;
+                       }
+                       
+                       /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
+                       for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
+                       part_len++;
+                       
+                       break;
+               default:
+                       /* Bad input */
                        g_free (result);
                        return -1;
                }
                
-               /* calculate the new part-length */
-               for (q = p; *q && (q - p) <= part_len; q++) {
-                       if (*q == '\n')
-                               part_len--;
-               }
-               /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
-               for (q--, part_len--; q > p && *(q-1) != '\n'; q--, part_len--);
-
-               imap_stream->cache = g_strndup (p, part_len + 1);
+               imap_stream->cache = g_strndup (p, part_len);
                g_free (result);
                
                imap_stream->cache_ptr = imap_stream->cache;
@@ -174,7 +188,7 @@ stream_read (CamelStream *stream, char *buffer, size_t n)
        } else {
                nread = -1;
        }
-
+       
        return nread;
 }
 
@@ -184,7 +198,7 @@ stream_reset (CamelStream *stream)
        CamelImapStream *imap_stream = CAMEL_IMAP_STREAM (stream);
        
        imap_stream->cache_ptr = imap_stream->cache;
-
+       
        return 1;
 }
 
@@ -192,6 +206,6 @@ static gboolean
 stream_eos (CamelStream *stream)
 {
        CamelImapStream *imap_stream = CAMEL_IMAP_STREAM (stream);
-
+       
        return (imap_stream->cache_ptr && strlen (imap_stream->cache_ptr));
 }