From d46d24e504b30b8b9f7b1045c5a2d252b9daf1d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Thu, 10 Jun 2004 19:47:46 +0000 Subject: If flags does not include FOLDER_INFO_FAST, get the total/unread counts 2004-06-10 Jeffrey Stedfast * providers/imap4/camel-imap4-store.c (imap4_build_folder_info): If flags does not include FOLDER_INFO_FAST, get the total/unread counts for the folder-info. * providers/imap4/camel-imap4-engine.c (engine_parse_status): Removed. (camel_imap4_engine_handle_untagged_1): Don't handle untagged STATUS responses anymore. Let the STATUS requestor handle them instead. * providers/imap4/camel-imap4-utils.c (camel_imap4_untagged_status): New function to parse untagged status events. svn path=/trunk/; revision=26291 --- camel/ChangeLog | 16 +++ camel/providers/imap4/camel-imap4-engine.c | 164 ----------------------------- camel/providers/imap4/camel-imap4-store.c | 78 +++++++++++++- camel/providers/imap4/camel-imap4-utils.c | 149 ++++++++++++++++++++++++++ camel/providers/imap4/camel-imap4-utils.h | 26 +++++ 5 files changed, 265 insertions(+), 168 deletions(-) (limited to 'camel') diff --git a/camel/ChangeLog b/camel/ChangeLog index 1801d5f429..da12a57fa5 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,19 @@ +2004-06-10 Jeffrey Stedfast + + * providers/imap4/camel-imap4-store.c (imap4_build_folder_info): + If flags does not include FOLDER_INFO_FAST, get the total/unread + counts for the folder-info. + + * providers/imap4/camel-imap4-engine.c (engine_parse_status): + Removed. + (camel_imap4_engine_handle_untagged_1): Don't handle untagged + STATUS responses anymore. Let the STATUS requestor handle them + instead. + + * providers/imap4/camel-imap4-utils.c + (camel_imap4_untagged_status): New function to parse untagged + status events. + 2004-06-10 Not Zed * camel-filter-driver.c (camel_filter_driver_filter_message): add diff --git a/camel/providers/imap4/camel-imap4-engine.c b/camel/providers/imap4/camel-imap4-engine.c index 73d3136152..059c7dbe22 100644 --- a/camel/providers/imap4/camel-imap4-engine.c +++ b/camel/providers/imap4/camel-imap4-engine.c @@ -558,162 +558,6 @@ engine_parse_flags (CamelIMAP4Engine *engine, CamelException *ex) return 0; } - -enum { - IMAP4_STATUS_MESSAGES, - IMAP4_STATUS_RECENT, - IMAP4_STATUS_UIDNEXT, - IMAP4_STATUS_UIDVALIDITY, - IMAP4_STATUS_UNSEEN, - IMAP4_STATUS_UNKNOWN -}; - -static struct { - const char *name; - int type; -} imap4_status[] = { - { "MESSAGES", IMAP4_STATUS_MESSAGES }, - { "RECENT", IMAP4_STATUS_RECENT }, - { "UIDNEXT", IMAP4_STATUS_UIDNEXT }, - { "UIDVALIDITY", IMAP4_STATUS_UIDVALIDITY }, - { "UNSEEN", IMAP4_STATUS_UNSEEN }, - { NULL, IMAP4_STATUS_UNKNOWN }, -}; - -static int -engine_parse_status (CamelIMAP4Engine *engine, CamelException *ex) -{ - camel_imap4_token_t token; - char *mailbox; - size_t len; - int type; - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) - return -1; - - switch (token.token) { - case CAMEL_IMAP4_TOKEN_ATOM: - mailbox = g_strdup (token.v.atom); - break; - case CAMEL_IMAP4_TOKEN_QSTRING: - mailbox = g_strdup (token.v.qstring); - break; - case CAMEL_IMAP4_TOKEN_LITERAL: - if (camel_imap4_engine_literal (engine, (unsigned char **) &mailbox, &len, ex) == -1) - return -1; - break; - default: - fprintf (stderr, "Unexpected token in IMAP4 untagged STATUS response: %s%c\n", - token.token == CAMEL_IMAP4_TOKEN_NIL ? "NIL" : "", - (unsigned char) (token.token & 0xff)); - camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); - return -1; - } - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) { - g_free (mailbox); - return -1; - } - - if (token.token != '(') { - d(fprintf (stderr, "Expected to find a '(' token after the mailbox token in the STATUS response\n")); - camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); - g_free (mailbox); - return -1; - } - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) { - g_free (mailbox); - return -1; - } - - while (token.token == CAMEL_IMAP4_TOKEN_ATOM) { - const unsigned char *inptr; - unsigned int v = 0; - - /* parse the status messages list */ - for (type = 0; imap4_status[type].name; type++) { - if (!strcasecmp (imap4_status[type].name, token.v.atom)) - break; - } - - if (type == IMAP4_STATUS_UNKNOWN) - fprintf (stderr, "unrecognized token in STATUS list: %s\n", token.v.atom); - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) { - g_free (mailbox); - return -1; - } - - if (token.token != CAMEL_IMAP4_TOKEN_ATOM) - break; - - if (type == IMAP4_STATUS_UIDNEXT || type == IMAP4_STATUS_UIDVALIDITY) { - /* these tokens should be numeric, but we - * treat them as strings internally so we are - * special-casing them here */ - - /* FIXME: save the UIDNEXT/UIDVALIDITY value */ - } else { - inptr = (const unsigned char *) token.v.atom; - while (*inptr && isdigit ((int) *inptr) && v < (UINT_MAX / 10)) - v = (v * 10) + (*inptr++ - '0'); - - if (*inptr != '\0') { - if (type == IMAP4_STATUS_UNKNOWN) { - /* we'll let it slide... unget this token and continue */ - camel_imap4_stream_unget_token (engine->istream, &token); - goto loop; - } - - d(fprintf (stderr, "Encountered non-numeric token after %s in untagged STATUS response: %s\n", - imap4_status[type].name, token.v.atom)); - goto loop; - } - - switch (type) { - case IMAP4_STATUS_MESSAGES: - /* FIXME: save value */ - break; - case IMAP4_STATUS_RECENT: - /* FIXME: save value */ - break; - case IMAP4_STATUS_UNSEEN: - /* FIXME: save value */ - break; - default: - g_assert_not_reached (); - } - } - - loop: - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) { - g_free (mailbox); - return -1; - } - } - - /* don't need this anymore... */ - g_free (mailbox); - - if (token.token != ')') { - d(fprintf (stderr, "Expected to find a ')' token terminating the untagged STATUS response\n")); - camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); - return -1; - } - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) - return -1; - - if (token.token != '\n') { - d(fprintf (stderr, "Expected to find a '\\n' token after the STATUS response\n")); - camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); - return -1; - } - - return 0; -} - static int engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex) { @@ -1212,14 +1056,6 @@ camel_imap4_engine_handle_untagged_1 (CamelIMAP4Engine *engine, camel_imap4_toke if (camel_imap4_engine_parse_resp_code (engine, ex) == -1) return -1; - } else if (!strcmp ("STATUS", token->v.atom)) { - /* FIXME: This should probably be removed... leave it - * up to the caller that sent the STATUS command to - * register an untagged response handler for this */ - - /* next token must be the mailbox name followed by a paren list */ - if (engine_parse_status (engine, ex) == -1) - return -1; } else if (ic && (untagged = g_hash_table_lookup (ic->untagged, token->v.atom))) { /* registered untagged handler for imap4 command */ if (untagged (engine, ic, 0, token, ex) == -1) diff --git a/camel/providers/imap4/camel-imap4-store.c b/camel/providers/imap4/camel-imap4-store.c index fbead28e68..333914123a 100644 --- a/camel/providers/imap4/camel-imap4-store.c +++ b/camel/providers/imap4/camel-imap4-store.c @@ -996,9 +996,59 @@ list_remove_duplicates (GPtrArray *array) } } +static void +imap4_status (CamelStore *store, CamelFolderInfo *fi) +{ + CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; + camel_imap4_status_attr_t *attr, *next; + camel_imap4_status_t *status; + CamelIMAP4Command *ic; + GPtrArray *array; + char *mailbox; + int id, i; + + mailbox = imap4_folder_utf7_name (store, fi->full_name, '\0'); + ic = camel_imap4_engine_queue (engine, NULL, "STATUS %S (MESSAGES UNSEEN)\r\n", mailbox); + g_free (mailbox); + + camel_imap4_command_register_untagged (ic, "STATUS", camel_imap4_untagged_status); + ic->user_data = array = g_ptr_array_new (); + + while ((id = camel_imap4_engine_iterate (engine)) < ic->id && id != -1) + ; + + if (id == -1 || ic->status != CAMEL_IMAP4_COMMAND_COMPLETE) { + camel_imap4_command_unref (ic); + g_ptr_array_free (array, TRUE); + return; + } + + for (i = 0; i < array->len; i++) { + status = array->pdata[i]; + attr = status->attr_list; + while (attr != NULL) { + next = attr->next; + if (attr->type == CAMEL_IMAP4_STATUS_MESSAGES) + fi->total = attr->value; + else if (attr->type == CAMEL_IMAP4_STATUS_UNSEEN) + fi->unread = attr->value; + g_free (attr); + attr = next; + } + + g_free (status->mailbox); + g_free (status); + } + + camel_imap4_command_unref (ic); + g_ptr_array_free (array, TRUE); +} + static CamelFolderInfo * -imap4_build_folder_info (CamelIMAP4Engine *engine, guint32 flags, GPtrArray *array, const char *top) +imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtrArray *array) { + CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; + CamelFolder *folder = (CamelFolder *) engine->folder; camel_imap4_list_t *list; CamelFolderInfo *fi; char *name, *p; @@ -1029,11 +1079,31 @@ imap4_build_folder_info (CamelIMAP4Engine *engine, guint32 flags, GPtrArray *arr fi->name = g_strdup (p ? p + 1: name); fi->uri = camel_url_to_string (url, 0); fi->flags = list->flags; - - /* FIXME: use STATUS to get these values if requested */ fi->unread = -1; fi->total = -1; + if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) { + if (folder && !strcmp (folder->full_name, fi->full_name)) { + CamelMessageInfo *info; + int index; + + fi->total = camel_folder_summary_count (folder->summary); + + fi->unread = 0; + for (index = 0; index < fi->total; index++) { + if (!(info = camel_folder_summary_index (folder->summary, index))) + continue; + + if ((info->flags & CAMEL_MESSAGE_SEEN) == 0) + fi->unread++; + + camel_folder_summary_info_free (folder->summary, info); + } + } else { + imap4_status (store, fi); + } + } + g_free (list->name); g_free (list); @@ -1117,7 +1187,7 @@ imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelE g_free (pattern); - fi = imap4_build_folder_info (engine, flags, array, top); + fi = imap4_build_folder_info (store, top, flags, array); done: diff --git a/camel/providers/imap4/camel-imap4-utils.c b/camel/providers/imap4/camel-imap4-utils.c index 67dd828134..2efac2ff42 100644 --- a/camel/providers/imap4/camel-imap4-utils.c +++ b/camel/providers/imap4/camel-imap4-utils.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -313,3 +314,151 @@ camel_imap4_untagged_list (CamelIMAP4Engine *engine, CamelIMAP4Command *ic, guin return -1; } + + +static struct { + const char *name; + int type; +} imap4_status[] = { + { "MESSAGES", CAMEL_IMAP4_STATUS_MESSAGES }, + { "RECENT", CAMEL_IMAP4_STATUS_RECENT }, + { "UIDNEXT", CAMEL_IMAP4_STATUS_UIDNEXT }, + { "UIDVALIDITY", CAMEL_IMAP4_STATUS_UIDVALIDITY }, + { "UNSEEN", CAMEL_IMAP4_STATUS_UNSEEN }, + { NULL, CAMEL_IMAP4_STATUS_UNKNOWN }, +}; + + +void +camel_imap4_status_free (camel_imap4_status_t *status) +{ + camel_imap4_status_attr_t *attr, *next; + + attr = status->attr_list; + while (attr != NULL) { + next = attr->next; + g_free (attr); + attr = next; + } + + g_free (status->mailbox); + g_free (status); +} + + +int +camel_imap4_untagged_status (CamelIMAP4Engine *engine, CamelIMAP4Command *ic, guint32 index, camel_imap4_token_t *token, CamelException *ex) +{ + camel_imap4_status_attr_t *attr, *tail, *list = NULL; + GPtrArray *array = ic->user_data; + camel_imap4_status_t *status; + char *mailbox; + size_t len; + int type; + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) + return -1; + + switch (token->token) { + case CAMEL_IMAP4_TOKEN_ATOM: + mailbox = g_strdup (token->v.atom); + break; + case CAMEL_IMAP4_TOKEN_QSTRING: + mailbox = g_strdup (token->v.qstring); + break; + case CAMEL_IMAP4_TOKEN_LITERAL: + if (camel_imap4_engine_literal (engine, (unsigned char **) &mailbox, &len, ex) == -1) + return -1; + break; + default: + fprintf (stderr, "Unexpected token in IMAP4 untagged STATUS response: %s%c\n", + token->token == CAMEL_IMAP4_TOKEN_NIL ? "NIL" : "", + (unsigned char) (token->token & 0xff)); + camel_imap4_utils_set_unexpected_token_error (ex, engine, token); + return -1; + } + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) { + g_free (mailbox); + return -1; + } + + if (token->token != '(') { + d(fprintf (stderr, "Expected to find a '(' token after the mailbox token in the STATUS response\n")); + camel_imap4_utils_set_unexpected_token_error (ex, engine, token); + g_free (mailbox); + return -1; + } + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) { + g_free (mailbox); + return -1; + } + + tail = (camel_imap4_status_attr_t *) &list; + + while (token->token == CAMEL_IMAP4_TOKEN_ATOM) { + /* parse the status messages list */ + for (type = 0; type < G_N_ELEMENTS (imap4_status); type++) { + if (!g_ascii_strcasecmp (imap4_status[type].name, token->v.atom)) + break; + } + + if (type == CAMEL_IMAP4_STATUS_UNKNOWN) + fprintf (stderr, "unrecognized token in STATUS list: %s\n", token->v.atom); + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) + goto exception; + + if (token->token != CAMEL_IMAP4_TOKEN_NUMBER) + break; + + attr = g_new (camel_imap4_status_attr_t, 1); + attr->next = NULL; + attr->type = type; + attr->value = token->v.number; + + tail->next = attr; + tail = attr; + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) + goto exception; + } + + status = g_new (camel_imap4_status_t, 1); + status->mailbox = mailbox; + status->attr_list = list; + list = NULL; + + g_ptr_array_add (array, status); + + if (token->token != ')') { + d(fprintf (stderr, "Expected to find a ')' token terminating the untagged STATUS response\n")); + camel_imap4_utils_set_unexpected_token_error (ex, engine, token); + return -1; + } + + if (camel_imap4_engine_next_token (engine, token, ex) == -1) + return -1; + + if (token->token != '\n') { + d(fprintf (stderr, "Expected to find a '\\n' token after the STATUS response\n")); + camel_imap4_utils_set_unexpected_token_error (ex, engine, token); + return -1; + } + + return 0; + + exception: + + g_free (mailbox); + + attr = list; + while (attr != NULL) { + list = attr->next; + g_free (attr); + attr = list; + } + + return -1; +} diff --git a/camel/providers/imap4/camel-imap4-utils.h b/camel/providers/imap4/camel-imap4-utils.h index ace7b4cad0..cfaf6a4dc4 100644 --- a/camel/providers/imap4/camel-imap4-utils.h +++ b/camel/providers/imap4/camel-imap4-utils.h @@ -60,6 +60,32 @@ typedef struct { int camel_imap4_untagged_list (struct _CamelIMAP4Engine *engine, struct _CamelIMAP4Command *ic, guint32 index, struct _camel_imap4_token_t *token, CamelException *ex); + +enum { + CAMEL_IMAP4_STATUS_MESSAGES, + CAMEL_IMAP4_STATUS_RECENT, + CAMEL_IMAP4_STATUS_UIDNEXT, + CAMEL_IMAP4_STATUS_UIDVALIDITY, + CAMEL_IMAP4_STATUS_UNSEEN, + CAMEL_IMAP4_STATUS_UNKNOWN, +}; + +typedef struct _camel_imap4_status_attr { + struct _camel_imap4_status_attr *next; + guint32 type; + guint32 value; +} camel_imap4_status_attr_t; + +typedef struct { + camel_imap4_status_attr_t *attr_list; + char *mailbox; +} camel_imap4_status_t; + +void camel_imap4_status_free (camel_imap4_status_t *status); + +int camel_imap4_untagged_status (struct _CamelIMAP4Engine *engine, struct _CamelIMAP4Command *ic, + guint32 index, struct _camel_imap4_token_t *token, CamelException *ex); + #ifdef __cplusplus } #endif /* __cplusplus */ -- cgit v1.2.3