From 50976d8ff0f04f44250753aa1dc1ce9dab9dea66 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Fri, 28 Jul 2000 17:41:15 +0000 Subject: [PATCH] Get message count when STATUS is not available. (imap_init): 2000-07-28 Jeffrey Stedfast * providers/imap/camel-imap-folder.c (imap_get_message_count_internal): Get message count when STATUS is not available. (imap_init): folder->has_search_capability is required for IMAP so should always be set to TRUE (is currently being set to FALSE as I've not yet implemented SEARCH support). (camel_imap_folder_changed): Seem to have fixed my optimization hack 2000-07-28 Jon K Hellan * providers/imap/camel-imap-store.h (CamelImapServerLevel): New enum. (CamelImapStore): Added server_level and has_status_capability members. * providers/imap/camel-imap-store.c (imap_connect): Detect IMAP4REV1, IMAP4 and STATUS in capability response. * providers/imap/camel-imap-folder.c (imap_get_message_count_internal): Use STATUS only if server supports it. TODO: Get message count when STATUS not supported. (imap_get_message, imap_get_summary_internal, imap_get_message_info_internal): Handle IMAP4 as well. (imap_protocol_get_summary_specifier): New function: Make a data item specifier for the header lines we need, appropriate to the server level. --- camel/ChangeLog | 30 +++++++ camel/providers/imap/camel-imap-folder.c | 143 +++++++++++++++++++++---------- camel/providers/imap/camel-imap-store.c | 18 ++-- camel/providers/imap/camel-imap-store.h | 17 ++-- 4 files changed, 153 insertions(+), 55 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index afea44e..20434ab 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,33 @@ +2000-07-28 Jeffrey Stedfast + + * providers/imap/camel-imap-folder.c + (imap_get_message_count_internal): Get message count when STATUS + is not available. + (imap_init): folder->has_search_capability is required for IMAP so + should always be set to TRUE (is currently being set to FALSE as + I've not yet implemented SEARCH support). + (camel_imap_folder_changed): Seem to have fixed my optimization + hack + +2000-07-28 Jon K Hellan + + * providers/imap/camel-imap-store.h (CamelImapServerLevel): New + enum. + (CamelImapStore): Added server_level and has_status_capability + members. + + * providers/imap/camel-imap-store.c (imap_connect): Detect + IMAP4REV1, IMAP4 and STATUS in capability response. + + * providers/imap/camel-imap-folder.c + (imap_get_message_count_internal): Use STATUS only if server + supports it. TODO: Get message count when STATUS not supported. + (imap_get_message, imap_get_summary_internal, + imap_get_message_info_internal): Handle IMAP4 as well. + (imap_protocol_get_summary_specifier): New function: Make a data + item specifier for the header lines we need, appropriate to the + server level. + 2000-07-27 Jeffrey Stedfast * providers/imap/camel-imap-folder.c (camel_imap_folder_changed): diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index bdedcd5..c9546be 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -146,7 +146,7 @@ camel_imap_folder_init (gpointer object, gpointer klass) folder->can_hold_messages = TRUE; folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; - folder->has_search_capability = FALSE; /* this gets set in imap_init */ + folder->has_search_capability = FALSE; /* FIXME: this should be TRUE but it's not yet implemented */ imap_folder->summary = NULL; imap_folder->summary_hash = NULL; @@ -261,7 +261,6 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo const gchar *name, gchar *separator, gboolean path_begins_with_sep, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - CamelStore *store = CAMEL_STORE (parent_store); /* call parent method */ parent_class->init (folder, parent_store, parent_folder, name, separator, path_begins_with_sep, ex); @@ -273,7 +272,7 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo folder->can_hold_messages = TRUE; folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; - folder->has_search_capability = CAMEL_IMAP_STORE (store)->has_search_capability; + folder->has_search_capability = FALSE; /* FIXME: this should be TRUE 'cept it ain't implemented yet */ /* some IMAP daemons support user-flags * * I would not, however, rely on this feature as * @@ -398,9 +397,13 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) folder_path = g_strdup_printf ("%s%s%s", url->path + 1, dir_sep, folder->full_name); else folder_path = g_strdup (folder->full_name); - - status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "STATUS %s (MESSAGES)", folder_path); + + if (CAMEL_IMAP_STORE (store)->has_status_capability) + status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), folder, + &result, "STATUS %s (MESSAGES)", folder_path); + else + status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), folder, + &result, "EXAMINE %s", folder_path); if (status != CAMEL_IMAP_OK) { CamelService *service = CAMEL_SERVICE (folder->parent_store); @@ -415,15 +418,26 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) } g_free (folder_path); - /* parse out the message count - should come in the form: "* STATUS (MESSAGES )\r\n" */ + /* parse out the message count */ if (result && *result == '*') { - if ((msg_count = strstr (result, "MESSAGES")) != NULL) { - msg_count += strlen ("MESSAGES") + 1; - - for ( ; *msg_count == ' '; msg_count++); + if (CAMEL_IMAP_STORE (store)->has_status_capability) { + /* should come in the form: "* STATUS (MESSAGES )" */ + if ((msg_count = strstr (result, "MESSAGES")) != NULL) { + msg_count = imap_next_word (msg_count); - /* we should now be pointing to the message count */ - count = atoi (msg_count); + /* we should now be pointing to the message count */ + count = atoi (msg_count); + } + } else { + /* should come in the form: "* EXIST" */ + if ((msg_count = strstr (result, "EXIST")) != NULL) { + for ( ; msg_count > result && *msg_count != '*'; msg_count--); + + msg_count = imap_next_word (msg_count); + + /* we should now be pointing to the message count */ + count = atoi (msg_count); + } } } g_free (result); @@ -452,7 +466,7 @@ imap_get_unread_message_count (CamelFolder *folder) g_return_val_if_fail (folder != NULL, 0); - /* If we don't have a message count, return */ + /* If we don't have a message count, return 0 */ if (!imap_folder->summary) return 0; @@ -746,11 +760,17 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) /*CamelMimeFilter *filter;*/ CamelMimeMessage *msg = NULL; /*CamelMimePart *part;*/ - gchar *result, *header = NULL, *body = NULL, *mesg = NULL, *p = NULL, *q = NULL; - int status = 0, part_len = 0; + gchar *result, *header, *body, *mesg, *p, *q, *data_item; + int status, part_len; + + if (CAMEL_IMAP_STORE (folder->parent_store)->server_level >= IMAP_LEVEL_IMAP4REV1) + data_item = "BODY.PEEK[HEADER]"; + else + data_item = "RFC822.HEADER"; status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "UID FETCH %s BODY.PEEK[HEADER]", uid); + &result, "UID FETCH %s %s", uid, + data_item); if (!result || status != CAMEL_IMAP_OK) { CamelService *service = CAMEL_SERVICE (folder->parent_store); @@ -790,8 +810,14 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) g_free (result); d(fprintf (stderr, "*** We got the header ***\n")); + if (CAMEL_IMAP_STORE (folder->parent_store)->server_level >= IMAP_LEVEL_IMAP4REV1) + data_item = "BODY[TEXT]"; + else + data_item = "RFC822.TEXT"; + status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "UID FETCH %s BODY[TEXT]", uid); + &result, "UID FETCH %s %s", uid, + data_item); if (!result || status != CAMEL_IMAP_OK) { CamelService *service = CAMEL_SERVICE (folder->parent_store); @@ -939,6 +965,31 @@ get_header_field (gchar *header, gchar *field) static char *header_fields[] = { "subject", "from", "to", "cc", "date", "received", "message-id", "references", "in-reply-to", "" }; +/** + * imap_protocol_get_summary_specifier + * + * 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)] + * IMAP4: UID FLAGS RFC822.HEADER.LINES (SUBJECT FROM .. IN-REPLY-TO) + **/ +static char * +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[HEADER.FIELDS"; + sect_end = "]"; + } else { + sect_begin = "RFC822.HEADER.LINES"; + sect_end = ""; + } + + return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin, headers_wanted, sect_end); +} static GPtrArray * imap_get_summary_internal (CamelFolder *folder, CamelException *ex) @@ -950,6 +1001,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) gint num, i, j, status = 0; char *result, *q, *node; const char *received; + char *summary_specifier; struct _header_raw *h, *tail = NULL; num = imap_get_message_count_internal (folder, ex); @@ -957,8 +1009,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) /* sync any previously set/changed message flags */ imap_sync (folder, FALSE, ex); - switch (num) { - case 0: + if (num == 0) { /* clean up any previous summary data */ imap_folder_summary_free (imap_folder); @@ -966,19 +1017,19 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal); return imap_folder->summary; - case 1: + } + + 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 (UID FLAGS BODY[HEADER.FIELDS " - "(SUBJECT FROM TO CC DATE MESSAGE-ID " - "REFERENCES IN-REPLY-TO)])"); - break; - default: + &result, "FETCH 1 (%s)", summary_specifier); + } else { status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "FETCH 1:%d (UID FLAGS BODY[HEADER.FIELDS " - "(SUBJECT FROM TO CC DATE MESSAGE-ID " - "REFERENCES IN-REPLY-TO)])", num); + &result, "FETCH 1:%d (%s)", num, summary_specifier); } - + g_free (summary_specifier); + if (status != CAMEL_IMAP_OK) { CamelService *service = CAMEL_SERVICE (folder->parent_store); @@ -1160,14 +1211,17 @@ imap_get_message_info_internal (CamelFolder *folder, guint id) struct _header_raw *h, *tail = NULL; const char *received; 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 (UID FLAGS BODY[HEADER.FIELDS " - "(SUBJECT FROM TO CC DATE MESSAGE-ID " - "REFERENCES IN-REPLY-TO)])", id); + &result, "FETCH %d (%s)", id, summary_specifier); + g_free (summary_specifier); + if (status != CAMEL_IMAP_OK) { g_free (result); return NULL; @@ -1306,10 +1360,10 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); char *result; int status; - + if (!imap_folder->has_search_capability) return NULL; - + status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, &result, "SEARCH %s", expression); @@ -1324,7 +1378,7 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc g_free (result); return NULL; } - + /* now to parse @result */ #endif } @@ -1333,10 +1387,10 @@ static guint32 imap_get_message_flags (CamelFolder *folder, const char *uid) { const CamelMessageInfo *info; - + info = imap_get_message_info (folder, uid); g_return_val_if_fail (info != NULL, 0); - + return info->flags; } @@ -1344,12 +1398,12 @@ static void imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set) { CamelMessageInfo *info; - + info = (CamelMessageInfo*)imap_get_message_info (folder, uid); g_return_if_fail (info != NULL); - + info->flags = (info->flags & ~flags) | (set & flags) | CAMEL_MESSAGE_FOLDER_FLAGGED; - + gtk_signal_emit_by_name (GTK_OBJECT (folder), "message_changed", uid); } @@ -1373,16 +1427,16 @@ camel_imap_folder_changed (CamelFolder *folder, gint recent, CamelException *ex) if (recent > 0) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); CamelMessageInfo *info; - gint i, last; + gint i, j, last; 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); } - last = imap_folder->summary->len; + last = imap_folder->summary->len + 1; - for (i = last; i < last + recent; i++) { + for (i = last, j = 0; j < recent; i++, j++) { info = imap_get_message_info_internal (folder, i); if (info) { g_ptr_array_add (imap_folder->summary, info); @@ -1390,6 +1444,7 @@ camel_imap_folder_changed (CamelFolder *folder, gint recent, CamelException *ex) } else { /* our hack failed so now we need to do it the old fashioned way */ imap_get_summary_internal (folder, ex); + d(fprintf (stderr, "*** we tried to get message %d but failed\n", i)); break; } } diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 29baae5..22a730e 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -351,16 +351,24 @@ imap_connect (CamelService *service, CamelException *ex) status != CAMEL_IMAP_FAIL && result ? result : "Unknown error"); } + + /* FIXME: parse for capabilities here. */ + d(fprintf (stderr, "%s\n", result)); + + if (e_strstrcase (result, "IMAP4REV1")) + store->server_level = IMAP_LEVEL_IMAP4REV1; + else if (e_strstrcase (result, "IMAP4")) + store->server_level = IMAP_LEVEL_IMAP4; + else + store->server_level = IMAP_LEVEL_UNKNOWN; - if (e_strstrcase (result, "SEARCH")) - store->has_search_capability = TRUE; + if ((store->server_level >= IMAP_LEVEL_IMAP4REV1) || (e_strstrcase (result, "STATUS"))) + store->has_status_capability = TRUE; else - store->has_search_capability = FALSE; + store->has_status_capability = FALSE; g_free (result); - d(fprintf (stderr, "IMAP provider does%shave SEARCH support\n", store->has_search_capability ? " " : "n't ")); - /* We now need to find out which directory separator this daemon uses */ status = camel_imap_command_extended (store, NULL, &result, "LIST \"\" \"\""); diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index e1bdc86..b8bb19f 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -40,24 +40,29 @@ extern "C" { #define CAMEL_IMAP_STORE_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), CAMEL_IMAP_STORE_TYPE, CamelImapStoreClass)) #define IS_CAMEL_IMAP_STORE(o) (GTK_CHECK_TYPE((o), CAMEL_IMAP_STORE_TYPE)) +typedef enum { + IMAP_LEVEL_UNKNOWN, + IMAP_LEVEL_IMAP4, + IMAP_LEVEL_IMAP4REV1 +} CamelImapServerLevel; typedef struct { CamelStore parent_object; - + CamelFolder *current_folder; CamelStream *istream, *ostream; guint32 command; - - gboolean has_search_capability; - + + CamelImapServerLevel server_level; + gboolean has_status_capability; + gchar *dir_sep; - + guint timeout_id; } CamelImapStore; - typedef struct { CamelStoreClass parent_class; -- 2.7.4