Commit 8b8dc628 authored by Thomas Roessler's avatar Thomas Roessler

Handle expunged messages. From Brendan Cully.

parent 841f1ff5
......@@ -23,6 +23,7 @@
#include "mutt.h"
#include "imap_private.h"
#include "message.h"
#include "mx.h"
#include <ctype.h>
......@@ -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)
{
......
......@@ -27,6 +27,7 @@
#include "globals.h"
#include "sort.h"
#include "browser.h"
#include "message.h"
#include "imap_private.h"
#include <unistd.h>
......@@ -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;
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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 */
......@@ -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;
......
......@@ -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);
}
......
......@@ -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 */
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment