summaryrefslogtreecommitdiffstats
path: root/imap
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1999-09-07 06:53:08 +0000
committerThomas Roessler <roessler@does-not-exist.org>1999-09-07 06:53:08 +0000
commit458307e72af511d2fad7961fdd180f02b9f77256 (patch)
tree5ea94d8f9a3790829f107aef4b7ee56ddf9b3fd1 /imap
parentf7e524f1a7100545042241e68f83099a07c30086 (diff)
* redoes the folder update optimisation I did yesterday. It's somewhat
cleaner and less invasive, and I'm not so worried about memory leaks now. * Fixes the bug where mutt would append a '/' to $folder even if it was only {mailhost}, causing mutt to browse the root directory instead of the home directory. * includes a first stab at preserving the D flag on the IMAP server. Now if you answer no to 'Purge deleted', the server still stores the messages as deleted, but doesn't expunge them on exit. NOTE: this is a first attempt. Play around, but don't mark things as deleted that you'd be sorry to see disappear. (From: Brendan Cully <brendan@kublai.com>)
Diffstat (limited to 'imap')
-rw-r--r--imap/BUGS8
-rw-r--r--imap/Makefile.am3
-rw-r--r--imap/TODO43
-rw-r--r--imap/imap.c116
-rw-r--r--imap/imap_private.h5
-rw-r--r--imap/message.c258
-rw-r--r--imap/message.h28
7 files changed, 254 insertions, 207 deletions
diff --git a/imap/BUGS b/imap/BUGS
index b75eb413..d52db96e 100644
--- a/imap/BUGS
+++ b/imap/BUGS
@@ -1,8 +1,6 @@
-* Mutt doesn't handle timeouts or dropped connections gracefully.
+In no particular order:
-* Mutt appends a '/' to $folder even when it is just '{server}', causing some
- servers to look for folders off the root of the server instead of in the
- home namespace.
+* Mutt doesn't handle timeouts or dropped connections gracefully.
* Have a hard time when the home namespace isn't default "".
@@ -13,4 +11,4 @@
* The mutt_pretty routines don't work well when the delimiter isn't '/'.
Brendan Cully <brendan@kublai.com>
-Updated 19990903
+Updated 19990906
diff --git a/imap/Makefile.am b/imap/Makefile.am
index 33eca53e..c69a17e0 100644
--- a/imap/Makefile.am
+++ b/imap/Makefile.am
@@ -7,5 +7,4 @@ EXTRA_DIST = BUGS TODO
noinst_LIBRARIES = libimap.a
noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h
-libimap_a_SOURCES = imap.c imap.h auth.c browse.c md5c.c socket.c \
- message.c
+libimap_a_SOURCES = auth.c browse.c imap.c imap.h md5c.c message.c socket.c
diff --git a/imap/TODO b/imap/TODO
index 340071d7..28b96712 100644
--- a/imap/TODO
+++ b/imap/TODO
@@ -1,4 +1,4 @@
-IMAP enhancements/fixes, by priority:
+IMAP enhancements, by priority:
[ -- socket -- ]
* Smarter connection code. Mutt should handle dropped connections/routing
@@ -18,23 +18,17 @@ IMAP enhancements/fixes, by priority:
Possibly we could use a tree-view in the browser, w/ expand, collapse.
For low-bandwidth lines we could defer getting subfolder lists until the
folder is expanded.
-
-[ -- new features -- ]
-* Implement server message COPY, instead of FETCH/APPEND.
-
- PRIORITY: [** ]
-
-* Implement the received folder on IMAP. (Wait on COPY).
-
+ Current thought is that <ENTER> will select a mailbox if it doesn't have
+ subfolders or enter the folder if it does. If it has messages and subfolders,
+ we'll use a new key to select it as a mailbox.
+ We should maybe add a new imap_format string for IMAP browsing, without all
+ the stat variables but with tags like how many messages are in the folders,
+ how many subfolders, that weird \Marked tag, etc.
+
PRIORITY: [** ]
-* Commands for creating/deleting folders on the server, since users may not
- otherwise be able to do this on IMAP servers.
-
- PRIORITY: [** ]
-
-* Implement READ-ONLY support, and the x (quit without saving changes)
- command.
+[ -- speed -- ]
+* Implement server message COPY, instead of FETCH/APPEND.
PRIORITY: [** ]
@@ -54,5 +48,20 @@ IMAP enhancements/fixes, by priority:
PRIORITY: [* ]
+[ -- new features -- ]
+* Implement the received folder on IMAP. (Wait on COPY).
+
+ PRIORITY: [** ]
+
+* Commands for creating/deleting folders on the server, since users may not
+ otherwise be able to do this on IMAP servers.
+
+ PRIORITY: [** ]
+
+* Implement READ-ONLY support, and the x (quit without saving changes)
+ command.
+
+ PRIORITY: [** ]
+
Brendan Cully <brendan@kublai.com>
-Updated: 19990904
+Updated: 19990906
diff --git a/imap/imap.c b/imap/imap.c
index ea66c688..b577de91 100644
--- a/imap/imap.c
+++ b/imap/imap.c
@@ -50,7 +50,6 @@ static void imap_parse_capabilities (IMAP_DATA *idata, char *s);
static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint);
static int imap_get_delim (IMAP_DATA *idata, CONNECTION *conn);
static char* imap_get_flags (LIST** hflags, char* s);
-static int imap_has_flag (LIST* flag_list, const char* flag);
static int imap_check_acl (IMAP_DATA *idata);
static int imap_check_capabilities (IMAP_DATA *idata);
static int imap_create_mailbox (IMAP_DATA *idata, char *mailbox);
@@ -1007,10 +1006,10 @@ int imap_open_mailbox (CONTEXT *ctx)
else if (mutt_strncasecmp ("FLAGS", pc, 5) == 0)
{
/* don't override PERMANENTFLAGS */
- if (!idata->mailbox_flags)
+ if (!idata->flags)
{
dprint (2, (debugfile, "Getting mailbox FLAGS\n"));
- if ((pc = imap_get_flags (&(idata->mailbox_flags), pc)) == NULL)
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
return -1;
}
}
@@ -1020,10 +1019,10 @@ int imap_open_mailbox (CONTEXT *ctx)
dprint (2, (debugfile,
"Getting mailbox PERMANENTFLAGS\n"));
/* safe to call on NULL */
- mutt_free_list (&(idata->mailbox_flags));
+ mutt_free_list (&(idata->flags));
/* skip "OK [PERMANENT" so syntax is the same as FLAGS */
pc += 13;
- if ((pc = imap_get_flags (&(idata->mailbox_flags), pc)) == NULL)
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
return -1;
}
else if (imap_handle_untagged (idata, buf) != 0)
@@ -1035,11 +1034,11 @@ int imap_open_mailbox (CONTEXT *ctx)
/* dump the mailbox flags we've found */
if (debuglevel > 2)
{
- if (!idata->mailbox_flags)
+ if (!idata->flags)
dprint (3, (debugfile, "No folder flags found\n"));
else
{
- LIST* t = idata->mailbox_flags;
+ LIST* t = idata->flags;
dprint (3, (debugfile, "Mailbox flags: "));
@@ -1118,7 +1117,7 @@ int imap_select_mailbox (CONTEXT* ctx, const char* path)
return -1;
}
- if (imap_sync_mailbox (ctx, M_NO) < 0)
+ if (imap_sync_mailbox (ctx, 0) < 0)
return -1;
idata = CTX_DATA;
@@ -1261,44 +1260,6 @@ int imap_close_connection (CONTEXT *ctx)
return 0;
}
-/* imap_has_flag: do a caseless comparison of the flag against a flag list,
- * return 1 if found or flag list has '\*', 0 otherwise */
-static int imap_has_flag (LIST* flag_list, const char* flag)
-{
- if (!flag_list)
- return 0;
-
- flag_list = flag_list->next;
- while (flag_list)
- {
- if (!mutt_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
- return 1;
-
- flag_list = flag_list->next;
- }
-
- return 0;
-}
-
-/* imap_stringify_flaglist: concatenate custom IMAP tags to list, if they
- * appear in the folder flags list. Why wouldn't they? */
-static void imap_stringify_flaglist (LIST* flags, LIST* mailbox_flags, char *s)
-{
- if (!mailbox_flags || !flags)
- return;
-
- flags = flags->next;
- while (flags)
- {
- if (imap_has_flag (mailbox_flags, flags->data))
- {
- strcat (s, flags->data);
- strcat (s, " ");
- }
- flags = flags->next;
- }
-}
-
static void imap_set_flag (CONTEXT *ctx, int aclbit, int flag, const char *str,
char *flags)
{
@@ -1310,7 +1271,7 @@ static void imap_set_flag (CONTEXT *ctx, int aclbit, int flag, const char *str,
/* update the IMAP server to reflect message changes done within mutt.
* Arguments
* ctx: the current context
- * expunge: M_YES or M_NO - do expunge? */
+ * expunge: 0 or 1 - do expunge? */
int imap_sync_mailbox (CONTEXT *ctx, int expunge)
{
char seq[8];
@@ -1321,7 +1282,7 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge)
/* save status changes */
for (n = 0; n < ctx->msgcount; n++)
{
- if (ctx->hdrs[n]->deleted || ctx->hdrs[n]->changed)
+ if (ctx->hdrs[n]->changed)
{
snprintf (buf, sizeof (buf), _("Saving message status flags... [%d/%d]"),
n+1, ctx->msgcount);
@@ -1339,23 +1300,42 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge)
flags);
/* now make sure we don't lose custom tags */
- imap_stringify_flaglist (ctx->hdrs[n]->server_flags,
- CTX_DATA->mailbox_flags, flags);
+ imap_add_keywords (flags, ctx->hdrs[n], CTX_DATA->flags);
mutt_remove_trailing_ws (flags);
imap_make_sequence (seq, sizeof (seq));
- snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq,
- ctx->hdrs[n]->index + 1, NONULL(flags));
+ /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
+ * explicitly revoke all system flags (if we have permission) */
+ if (!*flags)
+ {
+ imap_set_flag (ctx, IMAP_ACL_SEEN, 1, "\\Seen ", flags);
+ imap_set_flag (ctx, IMAP_ACL_WRITE, 1, "\\Flagged ", flags);
+ imap_set_flag (ctx, IMAP_ACL_WRITE, 1, "\\Answered ", flags);
+ imap_set_flag (ctx, IMAP_ACL_DELETE, 1, "\\Deleted ", flags);
+
+ mutt_remove_trailing_ws (flags);
+
+ snprintf (buf, sizeof (buf), "%s STORE %d -FLAGS.SILENT (%s)\r\n", seq,
+ ctx->hdrs[n]->index + 1, flags);
+ }
+ else
+ snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq,
+ ctx->hdrs[n]->index + 1, flags);
if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0)
{
imap_error ("imap_sync_mailbox()", buf);
- return (-1);
+ /* Give up on this message if we pass here again */
+ ctx->hdrs[n]->changed = 0;
+ return -1;
}
+
+ ctx->hdrs[n]->changed = 0;
}
}
+ ctx->changed = 0;
- if (expunge == M_YES)
+ if (expunge == 1)
{
if (mutt_bit_isset(CTX_DATA->rights, IMAP_ACL_DELETE))
{
@@ -1384,27 +1364,6 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge)
return 0;
}
-/* commit changes and terminate connection */
-static int imap_close_mailbox (IMAP_DATA *idata)
-{
- char seq[8];
- char buf[LONG_STRING];
-
- /* tell the server to commit changes */
- mutt_message _("Closing mailbox...");
- imap_make_sequence (seq, sizeof (seq));
- snprintf (buf, sizeof (buf), "%s CLOSE\r\n", seq);
- if (imap_exec (buf, sizeof (buf), idata, seq, buf, 0) != 0)
- {
- imap_error ("imap_close_mailbox()", buf);
- idata->status = IMAP_FATAL;
- return (-1);
- }
- idata->state = IMAP_AUTHENTICATED;
- return 0;
-}
-
-
void imap_fastclose_mailbox (CONTEXT *ctx)
{
int i;
@@ -1414,8 +1373,11 @@ void imap_fastclose_mailbox (CONTEXT *ctx)
return;
if ((CTX_DATA->state == IMAP_SELECTED) && (ctx == CTX_DATA->selected_ctx))
- if (imap_close_mailbox (CTX_DATA) != 0)
- return;
+ CTX_DATA->state = IMAP_AUTHENTICATED;
+
+ /* free IMAP part of headers */
+ for (i = 0; i < ctx->msgcount; i++)
+ imap_free_header_data (&(ctx->hdrs[i]->data));
for (i = 0; i < IMAP_CACHE_LEN; i++)
{
diff --git a/imap/imap_private.h b/imap/imap_private.h
index 6b10bcbc..3fcfbc0d 100644
--- a/imap/imap_private.h
+++ b/imap/imap_private.h
@@ -135,7 +135,8 @@ typedef struct
unsigned char rights[(RIGHTSMAX + 7)/8];
unsigned int newMailCount;
IMAP_CACHE cache[IMAP_CACHE_LEN];
- LIST *mailbox_flags;
+ /* all folder flags - system flags AND keywords */
+ LIST *flags;
} IMAP_DATA;
/* -- macros -- */
@@ -166,6 +167,8 @@ void imap_unquote_string (char *s);
int imap_authenticate (IMAP_DATA *idata, CONNECTION *conn);
/* message.c */
+void imap_add_keywords (char* s, HEADER* keywords, LIST* mailbox_flags);
+void imap_free_header_data (void** data);
int imap_read_headers (CONTEXT* ctx, int msgbegin, int msgend);
#endif
diff --git a/imap/message.c b/imap/message.c
index 5789d5da..6b0faf3e 100644
--- a/imap/message.c
+++ b/imap/message.c
@@ -32,9 +32,11 @@
#include "pgp.h"
#endif
-static void flush_buffer(char *buf, size_t *len, CONNECTION *conn);
-static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s);
-static char* msg_parse_flags (IMAP_FLAGS* flags, char* s);
+static void flush_buffer(char* buf, size_t* len, CONNECTION* conn);
+static int msg_has_flag (LIST* flag_list, const char* flag);
+static IMAP_HEADER* msg_new_header (void);
+static int msg_parse_fetch (IMAP_HEADER* h, char* s);
+static char* msg_parse_flags (IMAP_HEADER* h, char* s);
/* imap_read_headers:
* Changed to read many headers instead of just one. It will return the
@@ -52,25 +54,41 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
long ploc;
long bytes = 0;
int msgno,fetchlast;
- IMAP_HEADER_INFO *h0,*h,*htemp;
-#define WANT_HEADERS "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO"
- const char *want_headers = WANT_HEADERS;
+ IMAP_HEADER *h, *h0;
+ const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO";
int using_body_peek = 0;
fetchlast = 0;
+ /* define search string */
+ if (mutt_bit_isset(CTX_DATA->capabilities,IMAP4REV1))
+ {
+ snprintf(hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]",
+ want_headers);
+ using_body_peek = 1;
+ }
+ else if (mutt_bit_isset(CTX_DATA->capabilities,IMAP4))
+ {
+ snprintf(hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)",
+ want_headers);
+ }
+ else
+ { /* Unable to fetch headers for lower versions */
+ mutt_error _("Unable to fetch headers from this IMAP server version.");
+ sleep (1); /* pause a moment to let the user see the error */
+ return -1;
+ }
+
/*
* We now download all of the headers into one file. This should be
* faster on most systems.
*/
mutt_mktemp (tempfile);
if (!(fp = safe_fopen (tempfile, "w+")))
- {
- return (-1);
- }
+ return -1;
- h0 = (IMAP_HEADER_INFO*) safe_malloc(sizeof(IMAP_HEADER_INFO));
- h = h0;
- for (msgno=msgbegin; msgno <= msgend ; msgno++)
+ h = msg_new_header ();
+ h0 = h;
+ for (msgno = msgbegin; msgno <= msgend ; msgno++)
{
snprintf (buf, sizeof (buf), _("Fetching message headers... [%d/%d]"),
msgno + 1, msgend + 1);
@@ -86,26 +104,9 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
* If we get more messages while doing this, we make another
* request for all the new messages.
*/
- if (mutt_bit_isset(CTX_DATA->capabilities,IMAP4REV1))
- {
- snprintf(hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]",
- want_headers);
- using_body_peek = 1;
- }
- else if (mutt_bit_isset(CTX_DATA->capabilities,IMAP4))
- {
- snprintf(hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)",
- want_headers);
- }
- else
- { /* Unable to fetch headers for lower versions */
- mutt_error _("Unable to fetch headers from this IMAP server version.");
- sleep (1); /* pause a moment to let the user see the error */
- return (-1);
- }
snprintf (buf, sizeof (buf),
- "%s FETCH %d:%d (FLAGS INTERNALDATE RFC822.SIZE %s)\r\n",
- seq, msgno + 1, msgend + 1, hdrreq);
+ "%s FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)\r\n",
+ seq, msgno + 1, msgend + 1, hdrreq);
mutt_socket_write (CTX_DATA->conn, buf);
fetchlast = msgend + 1;
@@ -114,9 +115,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
do
{
if (mutt_socket_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
- {
- return (-1);
- }
+ return -1;
if (buf[0] == '*')
{
@@ -143,7 +142,7 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
if (!hdr)
{
imap_error ("imap_read_headers()", buf);
- return (-1);
+ return -1;
}
strncpy(fpc,pc,hdr-pc);
fpc += hdr-pc;
@@ -153,25 +152,24 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
if (imap_get_literal_count(buf, &bytes) < 0)
{
imap_error ("imap_read_headers()", buf);
- return (-1);
+ return -1;
}
imap_read_bytes (fp, CTX_DATA->conn, bytes);
if (mutt_socket_read_line_d (buf, sizeof (buf), CTX_DATA->conn) < 0)
- {
- return (-1);
- }
+ return -1;
+
pc = buf;
}
}
else if (imap_handle_untagged (CTX_DATA, buf) != 0)
- return (-1);
+ return -1;
}
}
while ((msgno + 1) >= fetchlast && mutt_strncmp (seq, buf, SEQLEN) != 0);
h->content_length = -bytes;
if (msg_parse_fetch (h, fetchbuf) == -1)
- return (-1);
+ return -1;
/* subtract the header length; the total message size will be
added to this */
@@ -185,12 +183,12 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
((IMAP_DATA *) ctx->data)->status = 0;
}
- h->next=safe_malloc(sizeof(IMAP_HEADER_INFO));
- h=h->next;
+ h->next = msg_new_header ();
+ h = h->next;
}
rewind(fp);
- h=h0;
+ h = h0;
/*
* Now that we have all the header information, we can tell mutt about
@@ -204,21 +202,22 @@ int imap_read_headers (CONTEXT *ctx, int msgbegin, int msgend)
ctx->hdrs[msgno]->env = mutt_read_rfc822_header (fp, ctx->hdrs[msgno], 0);
ploc=ftell(fp);
- ctx->hdrs[msgno]->read = h->flags.read;
- ctx->hdrs[msgno]->old = h->flags.old;
- ctx->hdrs[msgno]->deleted = h->flags.deleted;
- ctx->hdrs[msgno]->flagged = h->flags.flagged;
- ctx->hdrs[msgno]->replied = h->flags.replied;
- ctx->hdrs[msgno]->changed = h->flags.changed;
- ctx->hdrs[msgno]->server_flags = h->flags.server_flags;
+ ctx->hdrs[msgno]->read = h->read;
+ ctx->hdrs[msgno]->old = h->old;
+ ctx->hdrs[msgno]->deleted = h->deleted;
+ ctx->hdrs[msgno]->flagged = h->flagged;
+ ctx->hdrs[msgno]->replied = h->replied;
+ ctx->hdrs[msgno]->changed = h->changed;
ctx->hdrs[msgno]->received = h->received;
ctx->hdrs[msgno]->content->length = h->content_length;
+ ctx->hdrs[msgno]->data = (void *) (h->data);
mx_update_context (ctx); /* increments ->msgcount */
- htemp=h;
- h=h->next;
- safe_free ((void **) &htemp);
+ h0 = h;
+ h = h->next;
+ /* hdata is freed later */
+ safe_free ((void **) &h0);
}
fclose(fp);
unlink(tempfile);
@@ -318,35 +317,38 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
pc = buf;
}
/* UW-IMAP will provide a FLAGS update here if the FETCH causes a
- * change (eg from \Unseen to \Seen) */
- else if (strncasecmp ("FLAGS", pc, 5) == 0)
+ * change (eg from \Unseen to \Seen).
+ * Uncommitted changes in mutt take precedence. If we decide to
+ * incrementally update flags later, this won't stop us syncing */
+ else if ((strncasecmp ("FLAGS", pc, 5) == 0) &&
+ !ctx->hdrs[msgno]->changed)
{
- IMAP_FLAGS flags;
+ IMAP_HEADER* newh;
HEADER* h = ctx->hdrs[msgno];
- flags.server_flags = NULL;
+ newh = msg_new_header ();
dprint (2, (debugfile, "imap_fetch_message: parsing FLAGS\n"));
- if ((pc = msg_parse_flags (&flags, pc)) == NULL)
+ if ((pc = msg_parse_flags (newh, pc)) == NULL)
return -1;
/* update context sums */
- ctx->new += ((flags.read | flags.old) ? 0 : 1) -
+ ctx->new += ((newh->read | newh->old) ? 0 : 1) -
((h->read | h->old) ? 0 : 1);
- ctx->unread += h->read - flags.read;
- ctx->deleted += h->deleted = flags.deleted;
- ctx->flagged += h->flagged - flags.flagged;
+ ctx->unread += h->read - newh->read;
+ ctx->deleted += h->deleted = newh->deleted;
+ ctx->flagged += h->flagged - newh->flagged;
/* now commit the new flags */
- ctx->hdrs[msgno]->read = flags.read;
- ctx->hdrs[msgno]->old = flags.old;
- ctx->hdrs[msgno]->deleted = flags.deleted;
- ctx->hdrs[msgno]->flagged = flags.flagged;
- ctx->hdrs[msgno]->replied = flags.replied;
- ctx->hdrs[msgno]->changed = flags.changed;
-
- mutt_free_list (&(h->server_flags));
- h->server_flags = flags.server_flags;
+ ctx->hdrs[msgno]->read = newh->read;
+ ctx->hdrs[msgno]->old = newh->old;
+ ctx->hdrs[msgno]->deleted = newh->deleted;
+ ctx->hdrs[msgno]->flagged = newh->flagged;
+ ctx->hdrs[msgno]->replied = newh->replied;
+
+ mutt_free_list (&(HEADER_DATA(h)->keywords));
+ HEADER_DATA(h)->keywords = newh->data->keywords;
+ safe_free ((void**) &newh);
}
}
}
@@ -505,8 +507,79 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
return 0;
}
+/* imap_add_keywords: concatenate custom IMAP tags to list, if they
+ * appear in the folder flags list. Why wouldn't they? */
+void imap_add_keywords (char* s, HEADER* h, LIST* mailbox_flags)
+{
+ LIST *keywords;
+
+ if (!mailbox_flags || !HEADER_DATA(h) || !HEADER_DATA(h)->keywords)
+ return;
+
+ keywords = HEADER_DATA(h)->keywords->next;
+
+ while (keywords)
+ {
+ if (msg_has_flag (mailbox_flags, keywords->data))
+ {
+ strcat (s, keywords->data);
+ strcat (s, " ");
+ }
+ keywords = keywords->next;
+ }
+}
+
+/* imap_free_header_data: free IMAP_HEADER structure */
+void imap_free_header_data (void** data)
+{
+ /* this should be safe even if the list wasn't used */
+ mutt_free_list (&(((IMAP_HEADER_DATA*) *data)->keywords));
+
+ safe_free (data);
+}
+
+/* msg_new_header: allocate and initialise a new IMAP_HEADER structure */
+static IMAP_HEADER* msg_new_header (void)
+{
+ IMAP_HEADER* h;
+
+ h = (IMAP_HEADER*) safe_malloc (sizeof (IMAP_HEADER));
+ h->data = (IMAP_HEADER_DATA*) safe_malloc (sizeof (IMAP_HEADER_DATA));
+
+ /* lists aren't allocated unless they're used */
+ h->data->keywords = NULL;
+
+ h->deleted = 0;
+ h->flagged = 0;
+ h->replied = 0;
+ h->read = 0;
+ h->old = 0;
+ h->changed = 0;
+
+ return h;
+}
+
+/* msg_has_flag: do a caseless comparison of the flag against a flag list,
+ * return 1 if found or flag list has '\*', 0 otherwise */
+static int msg_has_flag (LIST* flag_list, const char* flag)
+{
+ if (!flag_list)
+ return 0;
+
+ flag_list = flag_list->next;
+ while (flag_list)
+ {
+ if (!mutt_strncasecmp (flag_list->data, flag, strlen (flag_list->data)))
+ return 1;
+
+ flag_list = flag_list->next;
+ }
+
+ return 0;
+}
+
/* msg_parse_fetch: handle headers returned from header fetch */
-static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s)
+static int msg_parse_fetch (IMAP_HEADER *h, char *s)
{
char tmp[SHORT_STRING];
char *ptmp;
@@ -520,10 +593,17 @@ static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s)
if (mutt_strncasecmp ("FLAGS", s, 5) == 0)
{
- h->flags.server_flags = NULL;
- if ((s = msg_parse_flags (&(h->flags), s)) == NULL)
+ if ((s = msg_parse_flags (h, s)) == NULL)
return -1;
}
+ else if (mutt_strncasecmp ("UID", s, 3) == 0)
+ {
+ s += 3;
+ SKIPWS (s);
+ h->data->uid = (unsigned int) atoi (s);
+
+ s = imap_next_word (s);
+ }
else if (mutt_strncasecmp ("INTERNALDATE", s, 12) == 0)
{
s += 12;
@@ -568,7 +648,7 @@ static int msg_parse_fetch (IMAP_HEADER_INFO *h, char *s)
/* msg_parse_flags: fill out the message header according to the flags from the
* server. Expects a flags line of the form "FLAGS (flag flag ...)" */
-static char* msg_parse_flags (IMAP_FLAGS* flags, char* s)
+static char* msg_parse_flags (IMAP_HEADER* h, char* s)
{
int recent = 0;
@@ -589,36 +669,28 @@ static char* msg_parse_flags (IMAP_FLAGS* flags, char* s)
}
s++;
- /* reset the current flags */
- flags->deleted = 0;
- flags->flagged = 0;
- flags->replied = 0;
- flags->read = 0;
- flags->old = 0;
- flags->changed = 0;
-
/* start parsing */
while (*s && *s != ')')
{
if (mutt_strncasecmp ("\\deleted", s, 8) == 0)
{
s += 8;
- flags->deleted = 1;
+ h->deleted = 1;
}
else if (mutt_strncasecmp ("\\flagged", s, 8) == 0)
{
s += 8;
- flags->flagged = 1;
+ h->flagged = 1;
}
else if (mutt_strncasecmp ("\\answered", s, 9) == 0)
{
s += 9;
- flags->replied = 1;
+ h->replied = 1;
}
else if (mutt_strncasecmp ("\\seen", s, 5) == 0)
{
s += 5;
- flags->read = 1;
+ h->read = 1;
}
else if (mutt_strncasecmp ("\\recent", s, 5) == 0)
{
@@ -631,14 +703,14 @@ static char* msg_parse_flags (IMAP_FLAGS* flags, char* s)
char ctmp;
char* flag_word = s;
- if (!flags->server_flags)
- flags->server_flags = mutt_new_list ();
+ if (!h->data->keywords)
+ h->data->keywords = mutt_new_list ();
while (*s && !ISSPACE (*s) && *s != ')')
s++;
ctmp = *s;
*s = '\0';
- mutt_add_list (flags->server_flags, flag_word);
+ mutt_add_list (h->data->keywords, flag_word);
*s = ctmp;
}
SKIPWS(s);
@@ -648,8 +720,8 @@ static char* msg_parse_flags (IMAP_FLAGS* flags, char* s)
if (*s == ')')
{
/* if a message is neither seen nor recent, it is OLD. */
- if (option (OPTMARKOLD) && !recent && !(flags->read))
- flags->old = 1;
+ if (option (OPTMARKOLD) && !recent && !(h->read))
+ h->old = 1;
s++;
}
else
diff --git a/imap/message.h b/imap/message.h
index 1669d8c6..ab31fd8f 100644
--- a/imap/message.h
+++ b/imap/message.h
@@ -22,8 +22,17 @@
#ifndef MESSAGE_H
#define MESSAGE_H 1
-/* Data from the FLAGS response */
-typedef struct imap_flags
+/* -- data structures -- */
+/* IMAP-specific header data, stored as HEADER->data */
+typedef struct imap_header_data
+{
+ unsigned int uid; /* 32-bit Message UID */
+ LIST *keywords;
+} IMAP_HEADER_DATA;
+
+/* Linked list to hold header information while downloading message
+ * headers */
+typedef struct imap_header
{
unsigned int read : 1;
unsigned int old : 1;
@@ -32,19 +41,14 @@ typedef struct imap_flags
unsigned int replied : 1;
unsigned int changed : 1;
- LIST* server_flags; /* flags mutt doesn't use, but the server does */
-} IMAP_FLAGS;
-
-/* Linked list to hold header information while downloading message
- * headers */
-typedef struct imap_header_info
-{
- IMAP_FLAGS flags;
+ IMAP_HEADER_DATA* data;
unsigned int number;
time_t received;
long content_length;
- struct imap_header_info *next;
-} IMAP_HEADER_INFO;
+ struct imap_header *next;
+} IMAP_HEADER;
+/* -- macros -- */
+#define HEADER_DATA(ph) ((IMAP_HEADER_DATA*) ((ph)->data))
#endif