X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=imap%2Fmessage.c;h=3c5011c10e018cb10e1d56da9247358f459c88f5;hp=41d59504e0e8aa47d7c86aa2625bcccfafbfb474;hb=1bbedb2dcb610160fe7fd2b44bd098248bfd83a0;hpb=6833ce8bdca2d64e14485118f2a4417b7e1cb1b1 diff --git a/imap/message.c b/imap/message.c index 41d5950..3c5011c 100644 --- a/imap/message.c +++ b/imap/message.c @@ -19,6 +19,10 @@ /* message parsing/updating functions */ +#if HAVE_CONFIG_H +# include "config.h" +#endif + #include #include @@ -32,6 +36,12 @@ #include "pgp.h" #endif +#if HAVE_STDINT_H +#include +#elif HAVE_INTTYPES_H +#include +#endif + static void flush_buffer(char* buf, size_t* len, CONNECTION* conn); static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp); @@ -39,6 +49,12 @@ static int msg_has_flag (LIST* flag_list, const char* flag); static int msg_parse_fetch (IMAP_HEADER* h, char* s); static char* msg_parse_flags (IMAP_HEADER* h, char* s); +#if USE_HCACHE +static int msg_fetch_header_fetch (CONTEXT* ctx, IMAP_HEADER* h, char* buf, + FILE* fp); +static size_t imap_hcache_keylen (const char *fn); +#endif /* USE_HCACHE */ + /* imap_read_headers: * Changed to read many headers instead of just one. It will return the * msgno of the last message read. It will return a value other than @@ -55,24 +71,37 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) IMAP_HEADER h; int rc, mfhrc, oldmsgcount; int fetchlast = 0; - const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL"; + const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL"; + +#if USE_HCACHE + void *hc = NULL; + uint64_t *uid_validity = NULL; + char uid_buf[64]; +#endif /* USE_HCACHE */ ctx = idata->ctx; +#if USE_HCACHE + hc = mutt_hcache_open (HeaderCache, ctx->path); +#endif /* USE_HCACHE */ + if (mutt_bit_isset (idata->capabilities,IMAP4REV1)) { - snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]", - want_headers); + snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s%s%s)]", + want_headers, ImapHeaders ? " " : "", ImapHeaders ? ImapHeaders : ""); } else if (mutt_bit_isset (idata->capabilities,IMAP4)) { - snprintf (hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s)", - want_headers); + snprintf (hdrreq, sizeof (hdrreq), "RFC822.HEADER.LINES (%s%s%s)", + want_headers, ImapHeaders ? " " : "", ImapHeaders ? ImapHeaders : ""); } else { /* Unable to fetch headers for lower versions */ mutt_error _("Unable to fetch headers from this IMAP server version."); mutt_sleep (2); /* pause a moment to let the user see the error */ +#if USE_HCACHE + mutt_hcache_close (hc); +#endif /* USE_HCACHE */ return -1; } @@ -83,6 +112,9 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) { mutt_error (_("Could not create temporary file %s"), tempfile); mutt_sleep (2); +#if USE_HCACHE + mutt_hcache_close (hc); +#endif /* USE_HCACHE */ return -1; } unlink (tempfile); @@ -95,14 +127,96 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) idata->reopen &= ~IMAP_NEWMAIL_PENDING; idata->newMailCount = 0; +#if USE_HCACHE + snprintf (buf, sizeof (buf), + "FETCH %d:%d (UID FLAGS)", msgbegin + 1, msgend + 1); + fetchlast = msgend + 1; + + imap_cmd_start (idata, buf); + + for (msgno = msgbegin; msgno <= msgend ; msgno++) + { + if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0))) + mutt_message (_("Evaluating cache... [%d/%d]"), msgno + 1, + msgend + 1); + + rewind (fp); + memset (&h, 0, sizeof (h)); + h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA)); + do + { + mfhrc = 0; + + rc = imap_cmd_step (idata); + if (rc != IMAP_CMD_CONTINUE) + break; + + if ((mfhrc = msg_fetch_header_fetch (idata->ctx, &h, idata->cmd.buf, fp)) == -1) + continue; + else if (mfhrc < 0) + break; + + /* make sure we don't get remnants from older larger message headers */ + fputs ("\n\n", fp); + + sprintf(uid_buf, "/%u", h.data->uid); /* XXX --tg 21:41 04-07-11 */ + uid_validity = (uint64_t *) mutt_hcache_fetch (hc, uid_buf, &imap_hcache_keylen); + + if (uid_validity != NULL + && *uid_validity == idata->uid_validity) { + ctx->hdrs[msgno] = mutt_hcache_restore((unsigned char *) uid_validity, 0); + ctx->hdrs[msgno]->index = h.sid - 1; + if (h.sid != ctx->msgcount + 1) + dprint (1, (debugfile, "imap_read_headers: msgcount and sequence ID are inconsistent!")); + /* 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; + ctx->hdrs[msgno]->flagged = h.flagged; + ctx->hdrs[msgno]->replied = h.replied; + ctx->hdrs[msgno]->changed = h.changed; + /* ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */ + ctx->hdrs[msgno]->data = (void *) (h.data); + + ctx->msgcount++; + } + rewind (fp); + + FREE(&uid_validity); + + } + while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) || + ((msgno + 1) >= fetchlast))); + + if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK))) + { + imap_free_header_data ((void**) &h.data); + fclose (fp); + mutt_hcache_close (hc); + return -1; + } + } + + fetchlast = msgbegin; +#endif /* USE_HCACHE */ + for (msgno = msgbegin; msgno <= msgend ; msgno++) { if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0))) mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1, msgend + 1); + if (ctx->hdrs[msgno]) + continue; + if (msgno + 1 > fetchlast) { + fetchlast = msgno + 1; + while((fetchlast <= msgend) && (! ctx->hdrs[fetchlast])) + fetchlast++; + /* * Make one request for everything. This makes fetching headers an * order of magnitude faster if you have a large mailbox. @@ -112,11 +226,9 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) */ snprintf (buf, sizeof (buf), "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1, - msgend + 1, hdrreq); + fetchlast, hdrreq); imap_cmd_start (idata, buf); - - fetchlast = msgend + 1; } /* freshen fp, h */ @@ -170,6 +282,11 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) /* content built as a side-effect of mutt_read_rfc822_header */ ctx->hdrs[msgno]->content->length = h.content_length; +#if USE_HCACHE + sprintf(uid_buf, "/%u", h.data->uid); + mutt_hcache_store(hc, uid_buf, ctx->hdrs[msgno], idata->uid_validity, &imap_hcache_keylen); +#endif /* USE_HCACHE */ + ctx->msgcount++; } while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) || @@ -179,7 +296,9 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) { imap_free_header_data ((void**) &h.data); fclose (fp); - +#if USE_HCACHE + mutt_hcache_close (hc); +#endif /* USE_HCACHE */ return -1; } @@ -194,6 +313,10 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend) } } +#if USE_HCACHE + mutt_hcache_close (hc); +#endif /* USE_HCACHE */ + fclose(fp); if (ctx->msgcount > oldmsgcount) @@ -263,7 +386,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno) * command handler */ h->active = 0; - snprintf (buf, sizeof (buf), "UID FETCH %d %s", HEADER_DATA(h)->uid, + snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid, (mutt_bit_isset (idata->capabilities, IMAP4REV1) ? (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") : "RFC822")); @@ -439,7 +562,13 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) rewind (fp); imap_munge_mbox_name (mbox, sizeof (mbox), mailbox); - snprintf (buf, sizeof (buf), "APPEND %s (\\Seen) {%d}", mbox, len); + snprintf (buf, sizeof (buf), "APPEND %s (%s%s%s%s%s) {%lu}", mbox, + msg->flags.read ? "\\Seen" : "", + msg->flags.read && (msg->flags.replied || msg->flags.flagged) ? " " : "", + msg->flags.replied ? "\\Answered" : "", + msg->flags.replied && msg->flags.flagged ? " " : "", + msg->flags.flagged ? "\\Flagged" : "", + (unsigned long) len); imap_cmd_start (idata, buf); @@ -665,8 +794,8 @@ void imap_add_keywords (char* s, HEADER* h, LIST* mailbox_flags, size_t slen) { if (msg_has_flag (mailbox_flags, keywords->data)) { - strncat (s, keywords->data, slen); - strncat (s, " ", slen); + safe_strcat (s, slen, keywords->data); + safe_strcat (s, slen, " "); } keywords = keywords->next; } @@ -726,6 +855,7 @@ char* imap_set_flags (IMAP_DATA* idata, HEADER* h, char* s) return s; } + /* msg_fetch_header: import IMAP FETCH response into an IMAP_HEADER. * Expects string beginning with * n FETCH. * Returns: @@ -762,19 +892,20 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) if (msg_parse_fetch (h, buf) != -2) return rc; - if (imap_get_literal_count (buf, &bytes) < 0) - return rc; - imap_read_literal (fp, idata, bytes); - - /* we may have other fields of the FETCH _after_ the literal - * (eg Domino puts FLAGS here). Nothing wrong with that, either. - * This all has to go - we should accept literals and nonliterals - * interchangeably at any time. */ - if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) - return -2; + if (imap_get_literal_count (buf, &bytes) == 0) + { + imap_read_literal (fp, idata, bytes); + + /* we may have other fields of the FETCH _after_ the literal + * (eg Domino puts FLAGS here). Nothing wrong with that, either. + * This all has to go - we should accept literals and nonliterals + * interchangeably at any time. */ + if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) + return rc; - if (msg_parse_fetch (h, idata->cmd.buf) == -1) - return rc; + if (msg_parse_fetch (h, idata->cmd.buf) == -1) + return rc; + } rc = 0; /* success */ @@ -785,6 +916,56 @@ static int msg_fetch_header (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) return rc; } +#if USE_HCACHE +static size_t imap_hcache_keylen (const char *fn) +{ + return mutt_strlen(fn); +} + +/* msg_fetch_header: import IMAP FETCH response into an IMAP_HEADER. + * Expects string beginning with * n FETCH. + * Returns: + * 0 on success + * -1 if the string is not a fetch response + * -2 if the string is a corrupt fetch response */ +static int msg_fetch_header_fetch (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp) +{ + IMAP_DATA* idata; + long bytes; + int rc = -1; /* default now is that string isn't FETCH response*/ + + idata = (IMAP_DATA*) ctx->data; + + if (buf[0] != '*') + return rc; + + /* skip to message number */ + buf = imap_next_word (buf); + h->sid = atoi (buf); + + /* find FETCH tag */ + buf = imap_next_word (buf); + if (ascii_strncasecmp ("FETCH", buf, 5)) + return rc; + + rc = -2; /* we've got a FETCH response, for better or worse */ + if (!(buf = strchr (buf, '('))) + return rc; + buf++; + + if (msg_parse_fetch (h, buf) < 0) { + return -2; + } + + if (!(buf = strchr (buf, ')'))) + return rc; + buf++; + + return 0; +} +#endif /* USE_HCACHE */ + + /* 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)