From: Thomas Roessler Date: Fri, 28 Jul 2000 08:52:36 +0000 (+0000) Subject: Handle expunged messages. From Brendan Cully. X-Git-Tag: mutt-1-3-6-rel~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8b8dc628b8e3ea057673e18035fe65b5478a5f22;p=mutt Handle expunged messages. From Brendan Cully. --- diff --git a/imap/command.c b/imap/command.c index c71d9841..12bacce2 100644 --- a/imap/command.c +++ b/imap/command.c @@ -23,6 +23,7 @@ #include "mutt.h" #include "imap_private.h" +#include "message.h" #include "mx.h" #include @@ -30,7 +31,8 @@ /* forward declarations */ static void cmd_make_sequence (char* buf, size_t buflen); -static void cmd_parse_capabilities (IMAP_DATA *idata, char *s); +static void cmd_parse_capabilities (IMAP_DATA* idata, char* s); +static void cmd_parse_expunge (IMAP_DATA* idata, char* s); static void cmd_parse_myrights (IMAP_DATA* idata, char* s); static char *Capabilities[] = {"IMAP4", "IMAP4rev1", "STATUS", "ACL", @@ -71,7 +73,6 @@ void imap_cmd_finish (IMAP_DATA* idata) } if ((idata->status == IMAP_NEW_MAIL || - idata->status == IMAP_EXPUNGE || (idata->reopen & (IMAP_REOPEN_PENDING|IMAP_NEWMAIL_PENDING))) && (idata->reopen & IMAP_REOPEN_ALLOW)) { @@ -90,7 +91,7 @@ void imap_cmd_finish (IMAP_DATA* idata) } else { - imap_reopen_mailbox (idata->ctx, NULL); + imap_expunge_mailbox (idata); idata->check_status = IMAP_REOPENED; idata->reopen &= ~(IMAP_REOPEN_PENDING|IMAP_NEWMAIL_PENDING); } @@ -100,9 +101,6 @@ void imap_cmd_finish (IMAP_DATA* idata) { if (idata->status == IMAP_NEW_MAIL) idata->reopen |= IMAP_NEWMAIL_PENDING; - - if (idata->status == IMAP_EXPUNGE) - idata->reopen |= IMAP_REOPEN_PENDING; } idata->status = 0; @@ -196,7 +194,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s) /* new mail arrived */ count = atoi (pn); - if ( (idata->status != IMAP_EXPUNGE) && count < idata->ctx->msgcount) + if ( !(idata->reopen & IMAP_REOPEN_PENDING) && + count < idata->ctx->msgcount) { /* something is wrong because the server reported fewer messages * than we previously saw @@ -213,7 +212,7 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s) "imap_handle_untagged: superfluous EXISTS message.\n")); else { - if (idata->status != IMAP_EXPUNGE) + if (!(idata->reopen & IMAP_REOPEN_PENDING)) { dprint (2, (debugfile, "imap_handle_untagged: New mail in %s - %d messages total.\n", @@ -224,7 +223,8 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s) } } else if (mutt_strncasecmp ("EXPUNGE", s, 7) == 0) - idata->status = IMAP_EXPUNGE; + /* pn vs. s: need initial seqno */ + cmd_parse_expunge (idata, pn); } else if (mutt_strncasecmp ("CAPABILITY", s, 10) == 0) cmd_parse_capabilities (idata, s); @@ -248,7 +248,7 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s) { /* Display the warning message from the server */ mutt_error ("%s", s+3); - sleep (1); + sleep (2); } else dprint (1, (debugfile, "imap_handle_untagged(): unhandled request: %s\n", @@ -270,7 +270,7 @@ static void cmd_make_sequence (char* buf, size_t buflen) /* cmd_parse_capabilities: set capability bits according to CAPABILITY * response */ -static void cmd_parse_capabilities (IMAP_DATA *idata, char *s) +static void cmd_parse_capabilities (IMAP_DATA* idata, char* s) { int x; @@ -286,6 +286,32 @@ static void cmd_parse_capabilities (IMAP_DATA *idata, char *s) } } +/* cmd_parse_expunge: mark headers with new sequence ID and mark idata to + * be reopened at our earliest convenience */ +static void cmd_parse_expunge (IMAP_DATA* idata, char* s) +{ + int expno, cur; + HEADER* h; + + expno = atoi (s); + + /* walk headers, zero seqno of expunged message, decrement seqno of those + * above. Possibly we could avoid walking the whole list by resorting + * and guessing a good starting point, but I'm guessing the resort would + * nullify the gains */ + for (cur = 0; cur < idata->ctx->msgcount; cur++) + { + h = idata->ctx->hdrs[cur]; + + if (HEADER_DATA (h)->sid == expno) + HEADER_DATA (h)->sid = 0; + else if (HEADER_DATA (h)->sid > expno) + HEADER_DATA (h)->sid--; + } + + idata->reopen |= IMAP_REOPEN_PENDING; +} + /* cmd_parse_myrights: set rights bits according to MYRIGHTS response */ static void cmd_parse_myrights (IMAP_DATA* idata, char* s) { diff --git a/imap/imap.c b/imap/imap.c index 3ffeb945..7f9738cc 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -27,6 +27,7 @@ #include "globals.h" #include "sort.h" #include "browser.h" +#include "message.h" #include "imap_private.h" #include @@ -186,6 +187,40 @@ int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes) return 0; } +/* imap_expunge_mailbox: Purge IMAP portion of expunged messages from the + * context. Must not be done while something has a handle on any headers + * (eg inside pager or editor). mx_update_tables and mutt_sort_headers + * must be called afterwards. */ +void imap_expunge_mailbox (IMAP_DATA* idata) +{ + HEADER* h; + int i, cacheno; + + for (i = 0; i < idata->ctx->msgcount; i++) + { + h = idata->ctx->hdrs[i]; + + if (!HEADER_DATA(h)->sid) + { + dprint (2, (debugfile, "Expunging message UID %d.\n", HEADER_DATA (h)->uid)); + + h->active = 0; + + /* free cached body from disk, if neccessary */ + cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN; + if (idata->cache[cacheno].uid == HEADER_DATA(h)->uid && + idata->cache[cacheno].path) + { + unlink (idata->cache[cacheno].path); + FREE (&idata->cache[cacheno].path); + } + + imap_free_header_data (&h->data); + } + } +} + +#if 0 /* imap_reopen_mailbox: Reopen an imap mailbox. This is used when the * server sends an EXPUNGE message, indicating that some messages may have * been deleted. This is a heavy handed approach, as it reparses all of the @@ -193,9 +228,10 @@ int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes) * something to actually only remove the messages that are marked * EXPUNGE. */ -int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) +int imap_reopen_mailbox (IMAP_DATA* idata) { HEADER **old_hdrs; + CONTEXT* ctx; int old_msgcount; char buf[LONG_STRING]; char bufout[LONG_STRING]; @@ -206,6 +242,8 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) int i, j; int index_hint_set; + ctx = idata->ctx; + ctx->quiet = 1; if (Sort != SORT_ORDER) @@ -304,7 +342,7 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) ctx->msgcount = 0; count = imap_read_headers (ctx, 0, count - 1) + 1; - index_hint_set = (index_hint == NULL); + index_hint_set = 1; if (!ctx->readonly) { @@ -343,8 +381,10 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) if (found) { /* this is best done here */ +/* if (!index_hint_set && *index_hint == j) *index_hint = i; +*/ if (old_hdrs[j]->changed) { @@ -382,6 +422,7 @@ int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) return 0; } +#endif static int imap_get_delim (IMAP_DATA *idata) { @@ -1095,23 +1136,11 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint) mutt_bit_isset(idata->rights, IMAP_ACL_DELETE)) { mutt_message _("Expunging messages from server..."); - /* FIXME: these status changes seem dubious */ - idata->status = IMAP_EXPUNGE; if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0) { imap_error ("imap_sync_mailbox: EXPUNGE failed", buf); return -1; } - idata->status = 0; - } - - for (n = 0; n < IMAP_CACHE_LEN; n++) - { - if (CTX_DATA->cache[n].path) - { - unlink (CTX_DATA->cache[n].path); - safe_free ((void **) &CTX_DATA->cache[n].path); - } } return 0; diff --git a/imap/imap_private.h b/imap/imap_private.h index 35545ce3..9aa65605 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -49,7 +49,6 @@ enum { IMAP_FATAL = 1, IMAP_NEW_MAIL, - IMAP_EXPUNGE, IMAP_BYE, IMAP_REOPENED }; @@ -122,8 +121,8 @@ enum /* -- data structures -- */ typedef struct { - unsigned int index; - char *path; + unsigned int uid; + char* path; } IMAP_CACHE; typedef struct @@ -175,7 +174,8 @@ time_t imap_parse_date (char* s); int imap_parse_list_response(IMAP_DATA* idata, char* buf, int buflen, char** name, int* noselect, int* noinferiors, char* delim); int imap_read_literal (FILE* fp, IMAP_DATA* idata, long bytes); -int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint); +void imap_expunge_mailbox (IMAP_DATA* idata); +int imap_reopen_mailbox (IMAP_DATA* idata); void imap_logout (IMAP_DATA* idata); /* auth.c */ diff --git a/imap/message.c b/imap/message.c index 954a1d67..3c798ac7 100644 --- a/imap/message.c +++ b/imap/message.c @@ -141,6 +141,9 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend) ctx->hdrs[ctx->msgcount] = mutt_new_header (); ctx->hdrs[ctx->msgcount]->index = ctx->msgcount; + /* messages which have not been expunged are ACTIVE (borrowed from + * mh folders) */ + ctx->hdrs[msgno]->active = 1; ctx->hdrs[msgno]->read = h->read; ctx->hdrs[msgno]->old = h->old; ctx->hdrs[msgno]->deleted = h->deleted; @@ -189,14 +192,16 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) char *pc; long bytes; int uid; + int cacheno; IMAP_CACHE *cache; /* see if we already have the message in our cache */ - cache = &CTX_DATA->cache[ctx->hdrs[msgno]->index % IMAP_CACHE_LEN]; + cacheno = HEADER_DATA(ctx->hdrs[msgno])->uid % IMAP_CACHE_LEN; + cache = &CTX_DATA->cache[cacheno]; if (cache->path) { - if (cache->index == ctx->hdrs[msgno]->index) + if (cache->uid == HEADER_DATA(ctx->hdrs[msgno])->uid) { /* yes, so just return a pointer to the message */ if (!(msg->fp = fopen (cache->path, "r"))) @@ -216,7 +221,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) mutt_message _("Fetching message..."); - cache->index = ctx->hdrs[msgno]->index; + cache->uid = HEADER_DATA(ctx->hdrs[msgno])->uid; mutt_mktemp (path); cache->path = safe_strdup (path); if (!(msg->fp = safe_fopen (path, "w+"))) @@ -628,7 +633,7 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) /* skip to message number */ buf = imap_next_word (buf); - h->number = atoi (buf); + h->data->sid = atoi (buf); /* find FETCH tag */ buf = imap_next_word (buf); diff --git a/imap/message.h b/imap/message.h index ea4d1424..af7ebd7f 100644 --- a/imap/message.h +++ b/imap/message.h @@ -26,12 +26,11 @@ /* IMAP-specific header data, stored as HEADER->data */ typedef struct imap_header_data { + unsigned int sid; /* server message sequence number */ unsigned int uid; /* 32-bit Message UID */ LIST *keywords; } IMAP_HEADER_DATA; -/* Linked list to hold header information while downloading message - * headers */ typedef struct { unsigned int read : 1; @@ -42,7 +41,6 @@ typedef struct unsigned int changed : 1; IMAP_HEADER_DATA* data; - unsigned int number; time_t received; long content_length; @@ -50,4 +48,5 @@ typedef struct /* -- macros -- */ #define HEADER_DATA(ph) ((IMAP_HEADER_DATA*) ((ph)->data)) -#endif + +#endif /* MESSAGE_H */ diff --git a/mutt.h b/mutt.h index c0099fe3..c07f4d59 100644 --- a/mutt.h +++ b/mutt.h @@ -628,7 +628,7 @@ typedef struct header #endif #ifdef USE_IMAP - void *data; /* driver-specific data (only used by IMAP */ + void *data; /* driver-specific data (only used by IMAP) */ #endif } HEADER; diff --git a/muttlib.c b/muttlib.c index e0bfc427..83c52970 100644 --- a/muttlib.c +++ b/muttlib.c @@ -262,6 +262,9 @@ void mutt_free_header (HEADER **h) safe_free ((void **) &(*h)->path); #ifdef MIXMASTER mutt_free_list (&(*h)->chain); +#endif +#ifdef USE_IMAP + safe_free ((void**) &(*h)->data); #endif safe_free ((void **) h); } diff --git a/mx.c b/mx.c index 61cd80c1..676604b9 100644 --- a/mx.c +++ b/mx.c @@ -1078,7 +1078,7 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint) { #ifdef USE_IMAP if (ctx->magic == M_IMAP && !purge) - mutt_message (_("%d kept."), ctx->msgcount); + mutt_message (_("Mailbox checkpointed."), ctx->msgcount); else #endif mutt_message (_("%d kept, %d deleted."), ctx->msgcount - ctx->deleted, @@ -1098,7 +1098,15 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint) /* if we haven't deleted any messages, we don't need to resort */ if (purge) { - mx_update_tables(ctx, 1); +#ifdef USE_IMAP + /* IMAP uses the active flag, since deleted messages may remain after + * a sync */ + if (ctx->magic == M_IMAP) + mx_update_tables (ctx, 0); + else +#endif + mx_update_tables (ctx, 1); + mutt_sort_headers (ctx, 1); /* rethread from scratch */ } }