diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-09-07 06:53:08 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-09-07 06:53:08 +0000 |
commit | 458307e72af511d2fad7961fdd180f02b9f77256 (patch) | |
tree | 5ea94d8f9a3790829f107aef4b7ee56ddf9b3fd1 /imap | |
parent | f7e524f1a7100545042241e68f83099a07c30086 (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/BUGS | 8 | ||||
-rw-r--r-- | imap/Makefile.am | 3 | ||||
-rw-r--r-- | imap/TODO | 43 | ||||
-rw-r--r-- | imap/imap.c | 116 | ||||
-rw-r--r-- | imap/imap_private.h | 5 | ||||
-rw-r--r-- | imap/message.c | 258 | ||||
-rw-r--r-- | imap/message.h | 28 |
7 files changed, 254 insertions, 207 deletions
@@ -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 @@ -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 |