diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-09-12 07:45:30 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-09-12 07:45:30 +0000 |
commit | 97bae0db181796555344b5d751020e2b9250d606 (patch) | |
tree | f94eb80e11e63f16ec896a3d92ab1d9e9a26db19 /imap | |
parent | 6d0ed4409462de9f9ec88d12497995223f586505 (diff) |
The attached patch (imap-turbocharge.diff):
* changes mutt_buffy_check to only poll the selected folder when it
is opened, not all mailboxes (unless the timeout has expired).
This is a noticeable win if you have a few IMAP mailboxes.
* sets the default checkinterval to 60 seconds from 0. Things are
much much slower with 0.
* makes some cosmetic renames
* moves lots of generic imap stuff into a separate file, imap/util.c
* abstracts the process of sending a command to an IMAP server a bit
better (lots more to do here, though).
* moves the message-set creation code used by the new fastdelete
code into its own function, since it is generally useful.
* implements server-side copy of messages. Tagged messages are
copied in one command, thanks to the message-set function. Speedy!
(From: Brendan Cully; modifications by tlr.)
Diffstat (limited to 'imap')
-rw-r--r-- | imap/BUGS | 13 | ||||
-rw-r--r-- | imap/Makefile.am | 3 | ||||
-rw-r--r-- | imap/TODO | 8 | ||||
-rw-r--r-- | imap/auth.c | 6 | ||||
-rw-r--r-- | imap/imap.c | 458 | ||||
-rw-r--r-- | imap/imap.h | 15 | ||||
-rw-r--r-- | imap/imap_private.h | 42 | ||||
-rw-r--r-- | imap/message.c | 100 | ||||
-rw-r--r-- | imap/util.c | 226 |
9 files changed, 521 insertions, 350 deletions
@@ -1,5 +1,16 @@ In no particular order: +* Not really an IMAP bug, but postponed-message checking is done too often, + incurring needless network overhead. + +* Server copy won't be able to implement decode/decrypt options to + message saving. If people want this we'll have to add a new variable + which, when set, causes mutt to fetch, transform and append instead of + using server copy. + +* Server copy currently doesn't take into account uncommitted changes in + messages about to be copied. Sync first. + * Mutt doesn't handle timeouts or dropped connections gracefully. * Have a hard time when the home namespace isn't default "". @@ -11,4 +22,4 @@ In no particular order: * The mutt_pretty routines don't work well when the delimiter isn't '/'. Brendan Cully <brendan@kublai.com> -Updated 19990906 +Updated 19990911 diff --git a/imap/Makefile.am b/imap/Makefile.am index c69a17e0..03b42d42 100644 --- a/imap/Makefile.am +++ b/imap/Makefile.am @@ -7,4 +7,5 @@ EXTRA_DIST = BUGS TODO noinst_LIBRARIES = libimap.a noinst_HEADERS = imap_private.h imap_socket.h md5.h message.h -libimap_a_SOURCES = auth.c browse.c imap.c imap.h md5c.c message.c socket.c +libimap_a_SOURCES = auth.c browse.c imap.c imap.h md5c.c message.c socket.c \ + util.c @@ -28,10 +28,6 @@ IMAP enhancements, by priority: PRIORITY: [** ] [ -- speed -- ] -* Implement server message COPY, instead of FETCH/APPEND. - - PRIORITY: [** ] - * Persistent caching of data. I think the nicest way to do this is to store local copies like IMAP does, with an invisible control message at the top, and extra invisible headers in the message (for UID/dirty bits). This does @@ -49,7 +45,7 @@ IMAP enhancements, by priority: PRIORITY: [* ] [ -- new features -- ] -* Implement the received folder on IMAP. (Wait on COPY). +* Implement the received folder on IMAP, now that COPY is done PRIORITY: [** ] @@ -64,4 +60,4 @@ IMAP enhancements, by priority: PRIORITY: [** ] Brendan Cully <brendan@kublai.com> -Updated: 19990906 +Updated: 19990911 diff --git a/imap/auth.c b/imap/auth.c index ba11f023..571ebca3 100644 --- a/imap/auth.c +++ b/imap/auth.c @@ -418,7 +418,6 @@ int imap_authenticate (IMAP_DATA *idata, CONNECTION *conn) char user[SHORT_STRING], q_user[SHORT_STRING]; char ckey[SHORT_STRING]; char pass[SHORT_STRING], q_pass[SHORT_STRING]; - char seq[16]; int r = 1; @@ -499,9 +498,8 @@ int imap_authenticate (IMAP_DATA *idata, CONNECTION *conn) imap_quote_string (q_pass, sizeof (q_pass), pass); mutt_message _("Logging in..."); - imap_make_sequence (seq, sizeof (seq)); - snprintf (buf, sizeof (buf), "%s LOGIN %s %s\r\n", seq, q_user, q_pass); - r = imap_exec (buf, sizeof (buf), idata, seq, buf, IMAP_OK_FAIL); + snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass); + r = imap_exec (buf, sizeof (buf), idata, buf, IMAP_OK_FAIL); if (r == -1) { /* connection or protocol problem */ diff --git a/imap/imap.c b/imap/imap.c index e66e5ff2..b696c9dc 100644 --- a/imap/imap.c +++ b/imap/imap.c @@ -52,12 +52,6 @@ static int imap_get_delim (IMAP_DATA *idata, CONNECTION *conn); static char* imap_get_flags (LIST** hflags, char* s); 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); - -void imap_error (const char *where, const char *msg) -{ - mutt_error (_("imap_error(): unexpected response in %s: %s\n"), where, msg); -} void imap_set_logout (CONTEXT *ctx) { @@ -65,16 +59,6 @@ void imap_set_logout (CONTEXT *ctx) CTX_DATA->status = IMAP_LOGOUT; } -void imap_make_sequence (char *buf, size_t buflen) -{ - static int sequence = 0; - - snprintf (buf, buflen, "a%04d", sequence++); - - if (sequence > 9999) - sequence = 0; -} - /* imap_parse_date: date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */ time_t imap_parse_date (char *s) { @@ -123,69 +107,6 @@ time_t imap_parse_date (char *s) return (mutt_mktime (&t, 0) + tz); } -void imap_quote_string (char *dest, size_t slen, const char *src) -{ - char quote[] = "\"\\", *pt; - const char *s; - size_t len = slen; - - pt = dest; - s = src; - - *pt++ = '"'; - /* save room for trailing quote-char */ - len -= 2; - - for (; *s && len; s++) - { - if (strchr (quote, *s)) - { - len -= 2; - if (!len) - break; - *pt++ = '\\'; - *pt++ = *s; - } - else - { - *pt++ = *s; - len--; - } - } - *pt++ = '"'; - *pt = 0; -} - -void imap_unquote_string (char *s) -{ - char *d = s; - - if (*s == '\"') - s++; - else - return; - - while (*s) - { - if (*s == '\"') - { - *d = '\0'; - return; - } - if (*s == '\\') - { - s++; - } - if (*s) - { - *d = *s; - d++; - s++; - } - } - *d = '\0'; -} - /* imap_read_bytes: read bytes bytes from server into file */ int imap_read_bytes (FILE *fp, CONNECTION *conn, long bytes) { @@ -214,14 +135,6 @@ int imap_code (const char *s) return (mutt_strncasecmp ("OK", s, 2) == 0); } -char *imap_next_word (char *s) -{ - while (*s && !ISSPACE (*s)) - s++; - SKIPWS (s); - return s; -} - /* a is a word, b a string of words */ static int imap_wordcasecmp(const char *a, const char *b) { @@ -367,24 +280,6 @@ int imap_handle_untagged (IMAP_DATA *idata, char *s) return 0; } -/* imap_get_literal_count: write number of bytes in an IMAP literal into - * bytes, return 0 on success, -1 on failure. */ -int imap_get_literal_count(const char *buf, long *bytes) -{ - char *pc; - char *pn; - - if (!(pc = strchr (buf, '{'))) - return (-1); - pc++; - pn = pc; - while (isdigit (*pc)) - pc++; - *pc = 0; - *bytes = atoi(pn); - return (0); -} - /* 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 headers, @@ -452,7 +347,7 @@ static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) ctx->subj_hash = hash_create (1031); mutt_message (_("Reopening mailbox... %s"), CTX_DATA->selected_mailbox); - imap_quote_string (buf, sizeof(buf), CTX_DATA->selected_mailbox); + imap_quote_string (buf, sizeof (buf), CTX_DATA->selected_mailbox); imap_make_sequence (seq, sizeof (seq)); snprintf (bufout, sizeof (bufout), "%s SELECT %s\r\n", seq, buf); mutt_socket_write (CTX_DATA->conn, bufout); @@ -587,12 +482,24 @@ static int imap_reopen_mailbox (CONTEXT *ctx, int *index_hint) * failing, this is used for checking for a mailbox on append and login * Return 0 on success, -1 on Failure, -2 on OK Failure */ -int imap_exec (char *buf, size_t buflen, IMAP_DATA *idata, - const char *seq, const char *cmd, int flags) +int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd, + int flags) { + char* out; + int outlen; + char seq[8]; int count; - mutt_socket_write (idata->conn, cmd); + /* create sequence for command */ + imap_make_sequence (seq, sizeof (seq)); + /* seq, space, cmd, \r\n\0 */ + outlen = strlen (seq) + strlen (cmd) + 4; + out = (char*) safe_malloc (outlen); + snprintf (out, outlen, "%s %s\r\n", seq, cmd); + + mutt_socket_write (idata->conn, out); + + safe_free ((void**) &out); do { @@ -699,106 +606,17 @@ static int imap_get_delim (IMAP_DATA *idata, CONNECTION *conn) return 0; } -/* imap_parse_path: given an IMAP mailbox name, return host, port - * and a path IMAP servers will recognise. */ -int imap_parse_path (char *path, char *host, size_t hlen, int *port, - char **mbox) -{ - int n; - char *pc; - char *pt; - - /* set default port */ - *port = IMAP_PORT; - pc = path; - if (*pc != '{') - return (-1); - pc++; - n = 0; - while (*pc && *pc != '}' && *pc != ':' && (n < hlen-1)) - host[n++] = *pc++; - host[n] = 0; - if (!*pc) - return (-1); - if (*pc == ':') - { - pc++; - pt = pc; - while (*pc && *pc != '}') pc++; - if (!*pc) - return (-1); - *pc = '\0'; - *port = atoi (pt); - *pc = '}'; - } - pc++; - - *mbox = pc; - return 0; -} - -/* - * Fix up the imap path. This is necessary because the rest of mutt - * assumes a hierarchy delimiter of '/', which is not necessarily true - * in IMAP. Additionally, the filesystem converts multiple hierarchy - * delimiters into a single one, ie "///" is equal to "/". IMAP servers - * are not required to do this. - */ -char *imap_fix_path (IMAP_DATA *idata, char *mailbox, char *path, - size_t plen) -{ - int x = 0; - - if (!mailbox || !*mailbox) - { - strfcpy (path, "INBOX", plen); - return path; - } - - while (mailbox && *mailbox && (x < (plen - 1))) - { - if ((*mailbox == '/') || (*mailbox == idata->delim)) - { - while ((*mailbox == '/') || (*mailbox == idata->delim)) mailbox++; - path[x] = idata->delim; - } - else - { - path[x] = *mailbox; - mailbox++; - } - x++; - } - path[x] = '\0'; - return path; -} - -/* imap_qualify_path: make an absolute IMAP folder target, given host, port - * and relative path. Use this and maybe it will be easy to convert to - * IMAP URLs */ -void imap_qualify_path (char* dest, size_t len, const char* host, int port, - const char* path, const char* name) -{ - if (port == IMAP_PORT) - snprintf (dest, len, "{%s}%s%s", host, NONULL (path), NONULL (name)); - else - snprintf (dest, len, "{%s:%d}%s%s", host, port, NONULL (path), - NONULL (name)); -} - static int imap_check_acl (IMAP_DATA *idata) { char buf[LONG_STRING]; char mbox[LONG_STRING]; - char seq[16]; - imap_make_sequence (seq, sizeof (seq)); imap_quote_string (mbox, sizeof(mbox), idata->selected_mailbox); - snprintf (buf, sizeof (buf), "%s MYRIGHTS %s\r\n", seq, mbox); - if (imap_exec (buf, sizeof (buf), idata, seq, buf, 0) != 0) + snprintf (buf, sizeof (buf), "MYRIGHTS %s", mbox); + if (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0) { imap_error ("imap_check_acl", buf); - return (-1); + return -1; } return (0); } @@ -806,23 +624,20 @@ static int imap_check_acl (IMAP_DATA *idata) static int imap_check_capabilities (IMAP_DATA *idata) { char buf[LONG_STRING]; - char seq[16]; - imap_make_sequence (seq, sizeof (seq)); - snprintf (buf, sizeof (buf), "%s CAPABILITY\r\n", seq); - if (imap_exec (buf, sizeof (buf), idata, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), idata, "CAPABILITY", 0) != 0) { imap_error ("imap_check_capabilities", buf); - return (-1); + return -1; } if (!(mutt_bit_isset(idata->capabilities,IMAP4) ||mutt_bit_isset(idata->capabilities,IMAP4REV1))) { mutt_error _("This IMAP server is ancient. Mutt does not work with it."); sleep (5); /* pause a moment to let the user see the error */ - return (-1); + return -1; } - return (0); + return 0; } int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn) @@ -1135,16 +950,14 @@ int imap_select_mailbox (CONTEXT* ctx, const char* path) return imap_open_mailbox (ctx); } -static int imap_create_mailbox (IMAP_DATA *idata, char *mailbox) +int imap_create_mailbox (IMAP_DATA* idata, char* mailbox) { - char seq[8]; char buf[LONG_STRING], mbox[LONG_STRING]; - imap_make_sequence (seq, sizeof (seq)); imap_quote_string (mbox, sizeof (mbox), mailbox); - snprintf (buf, sizeof (buf), "%s CREATE %s\r\n", seq, mbox); + snprintf (buf, sizeof (buf), "CREATE %s", mbox); - if (imap_exec (buf, sizeof (buf), idata, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), idata, buf, 0) != 0) { imap_error ("imap_create_mailbox()", buf); return (-1); @@ -1159,7 +972,6 @@ int imap_open_mailbox_append (CONTEXT *ctx) char host[SHORT_STRING]; char buf[LONG_STRING], mbox[LONG_STRING]; char mailbox[LONG_STRING]; - char seq[16]; char *pc; int r; int port; @@ -1191,17 +1003,16 @@ int imap_open_mailbox_append (CONTEXT *ctx) imap_fix_path (idata, pc, mailbox, sizeof (mailbox)); imap_quote_string (mbox, sizeof (mbox), mailbox); - imap_make_sequence (seq, sizeof (seq)); if (mutt_bit_isset(idata->capabilities,IMAP4REV1)) { - snprintf (buf, sizeof (buf), "%s STATUS %s (UIDVALIDITY)\r\n", seq, mbox); + snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox); } else if (mutt_bit_isset(idata->capabilities,STATUS)) { /* We have no idea what the other guy wants. UW imapd 8.3 wants this * (but it does not work if another mailbox is selected) */ - snprintf (buf, sizeof (buf), "%s STATUS %s (UID-VALIDITY)\r\n", seq, mbox); + snprintf (buf, sizeof (buf), "STATUS %s (UID-VALIDITY)", mbox); } else { @@ -1210,10 +1021,10 @@ int imap_open_mailbox_append (CONTEXT *ctx) * - Open a *new* IMAP session, select, and then close it. Report the * error if the mailbox did not exist. */ mutt_message _("Unable to append to IMAP mailboxes at this server"); - return (-1); + return -1; } - r = imap_exec (buf, sizeof (buf), idata, seq, buf, IMAP_OK_FAIL); + r = imap_exec (buf, sizeof (buf), idata, buf, IMAP_OK_FAIL); if (r == -2) { /* command failed cause folder doesn't exist */ @@ -1233,7 +1044,7 @@ int imap_open_mailbox_append (CONTEXT *ctx) else if (r == -1) { /* Hmm, some other failure */ - return (-1); + return -1; } return 0; } @@ -1274,16 +1085,101 @@ static void imap_set_flag (CONTEXT *ctx, int aclbit, int flag, const char *str, strcat (flags, str); } +/* imap_make_msg_set: make an IMAP4rev1 message set out of a set of headers, + * given a flag enum to filter on. + * Params: buf: to write message set into + * buflen: length of buffer + * ctx: CONTEXT containing header set + * flag: enum of flag type on which to filter + * changed: include only changed messages in message set + * Returns: number of messages in message set (0 if no matches) */ +int imap_make_msg_set (char* buf, size_t buflen, CONTEXT* ctx, int flag, + int changed) +{ + HEADER** hdrs; /* sorted local copy */ + int count = 0; /* number of messages in message set */ + int match = 0; /* whether current message matches flag condition */ + int setstart = 0; /* start of current message range */ + char* tmp; + int n; + + /* sanity-check */ + if (!buf || buflen < 2) + return 0; + + *buf = '\0'; + + /* make copy of header pointers to sort in natural order */ + hdrs = safe_calloc (ctx->msgcount, sizeof (HEADER*)); + memcpy (hdrs, ctx->hdrs, ctx->msgcount * sizeof (HEADER*)); + qsort ((void*) hdrs, ctx->msgcount, sizeof (HEADER*), + mutt_get_sort_func (SORT_ORDER)); + + tmp = safe_malloc (buflen); + + for (n = 0; n < ctx->msgcount; n++) + { + match = 0; + switch (flag) + { + case M_DELETE: + if (hdrs[n]->deleted) + match = 1; + break; + case M_TAG: + if (hdrs[n]->tagged) + match = 1; + break; + } + + if (match && (!changed || hdrs[n]->changed)) + { + count++; + if (setstart == 0) + { + setstart = n+1; + if (!buf[0]) + snprintf (buf, buflen, "%u", n+1); + else + { + strncpy (tmp, buf, buflen); + snprintf (buf, buflen, "%s,%u", tmp, n+1); + } + } + /* tie up if the last message also matches */ + else if (n == ctx->msgcount-1) + { + strncpy (tmp, buf, buflen); + snprintf (buf, buflen, "%s:%u", tmp, n+1); + } + } + else if (setstart) + { + if (n > setstart) + { + strncpy (tmp, buf, buflen); + snprintf (buf, buflen, "%s:%u", tmp, n); + } + setstart = 0; + } + } + + safe_free ((void**) &tmp); + safe_free ((void**) &hdrs); + + return count; +} + /* update the IMAP server to reflect message changes done within mutt. * Arguments * ctx: the current context * expunge: 0 or 1 - do expunge? */ -int imap_sync_mailbox (CONTEXT *ctx, int expunge) +int imap_sync_mailbox (CONTEXT* ctx, int expunge) { - char seq[8]; char buf[LONG_STRING]; char flags[LONG_STRING]; char tmp[LONG_STRING]; + int deleted; int n; if (CTX_DATA->state != IMAP_SELECTED) @@ -1295,65 +1191,23 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge) /* if we are expunging anyway, we can do deleted messages very quickly... */ if (expunge && mutt_bit_isset (CTX_DATA->rights, IMAP_ACL_DELETE)) { - int setstart = 0; - HEADER** hdrs; - - buf[0] = '\0'; - - /* make copy of header pointers to sort in natural order */ - hdrs = safe_calloc (ctx->msgcount, sizeof (HEADER*)); - memcpy (hdrs, ctx->hdrs, ctx->msgcount * sizeof (HEADER*)); - qsort ((void*) hdrs, ctx->msgcount, sizeof (HEADER*), - mutt_get_sort_func (SORT_ORDER)); - - for (n = 0; n < ctx->msgcount; n++) - { - if (hdrs[n]->changed && hdrs[n]->deleted) - { - if (setstart == 0) - { - setstart = n+1; - if (!buf[0]) - snprintf (buf, sizeof (buf), "%u", n+1); - else - { - strncpy (tmp, buf, sizeof (tmp)); - snprintf (buf, sizeof (buf), "%s,%u", tmp, n+1); - } - } - /* tie up if the last message is also deleted */ - else if (n == ctx->msgcount-1) - { - strncpy (tmp, buf, sizeof (tmp)); - snprintf (buf, sizeof (buf), "%s:%u", tmp, n+1); - } - /* the normal flag update can skip this message */ - hdrs[n]->changed = 0; - } - else if (setstart) - { - if (n > setstart) - { - strncpy (tmp, buf, sizeof (tmp)); - snprintf (buf, sizeof (buf), "%s:%u", tmp, n); - } - setstart = 0; - } - } - - safe_free ((void**) &hdrs); + deleted = imap_make_msg_set (buf, sizeof (buf), ctx, M_DELETE, 1); /* if we have a message set, then let's delete */ - if (buf[0]) + if (deleted) { - snprintf (tmp, sizeof (tmp), _("Marking %d messages for deletion..."), ctx->deleted); + snprintf (tmp, sizeof (tmp), _("Marking %d messages for deletion..."), + deleted); mutt_message (tmp); - imap_make_sequence (seq, sizeof (seq)); - snprintf (tmp, sizeof (tmp), "%s STORE %s +FLAGS.SILENT (\\Deleted)\r\n", - seq, buf); - if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, tmp, 0) != 0) + snprintf (tmp, sizeof (tmp), "STORE %s +FLAGS.SILENT (\\Deleted)", buf); + if (imap_exec (buf, sizeof (buf), CTX_DATA, tmp, 0) != 0) /* continue, let regular store try before giving up */ dprint(2, (debugfile, "imap_sync_mailbox: fast delete failed\n")); + else + /* mark these messages as unchanged so second pass ignores them */ + for (n = 0; n < ctx->msgcount; n++) + if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) + ctx->hdrs[n]->changed = 0; } } @@ -1382,7 +1236,6 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge) mutt_remove_trailing_ws (flags); - imap_make_sequence (seq, sizeof (seq)); /* 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) @@ -1394,13 +1247,13 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge) mutt_remove_trailing_ws (flags); - snprintf (buf, sizeof (buf), "%s STORE %d -FLAGS.SILENT (%s)\r\n", seq, + snprintf (buf, sizeof (buf), "STORE %d -FLAGS.SILENT (%s)", ctx->hdrs[n]->index + 1, flags); } else - snprintf (buf, sizeof (buf), "%s STORE %d FLAGS.SILENT (%s)\r\n", seq, + snprintf (buf, sizeof (buf), "STORE %d FLAGS.SILENT (%s)", ctx->hdrs[n]->index + 1, flags); - if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), CTX_DATA, buf, 0) != 0) { imap_error ("imap_sync_mailbox()", buf); /* Give up on this message if we pass here again */ @@ -1419,9 +1272,7 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge) if (ctx->closing) { 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), CTX_DATA, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), CTX_DATA, "CLOSE", 0) != 0) { imap_error ("imap_sync_mailbox()", buf); return -1; @@ -1432,9 +1283,7 @@ int imap_sync_mailbox (CONTEXT *ctx, int expunge) { mutt_message _("Expunging messages from server..."); CTX_DATA->status = IMAP_EXPUNGE; - imap_make_sequence (seq, sizeof (seq)); - snprintf (buf, sizeof (buf), "%s EXPUNGE\r\n", seq); - if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), CTX_DATA, "EXPUNGE", 0) != 0) { imap_error ("imap_sync_mailbox()", buf); return -1; @@ -1497,24 +1346,22 @@ void imap_fastclose_mailbox (CONTEXT *ctx) */ int imap_check_mailbox (CONTEXT *ctx, int *index_hint) { - char seq[8]; char buf[LONG_STRING]; static time_t checktime=0; - if (ImapCheckTime) + if (ImapCheckTimeout) { time_t k=time(NULL); - if (checktime && (k-checktime < ImapCheckTime)) return 0; + if (k-checktime < ImapCheckTimeout) + return 0; checktime=k; } CTX_DATA->check_status = 0; - imap_make_sequence (seq, sizeof (seq)); - snprintf (buf, sizeof (buf), "%s NOOP\r\n", seq); - if (imap_exec (buf, sizeof (buf), CTX_DATA, seq, buf, 0) != 0) + if (imap_exec (buf, sizeof (buf), CTX_DATA, "NOOP", 0) != 0) { imap_error ("imap_check_mailbox()", buf); - return (-1); + return -1; } if (CTX_DATA->check_status == IMAP_NEW_MAIL) @@ -1640,18 +1487,6 @@ int imap_mailbox_check (char *path, int new) return msgcount; } -/* returns whether there is new mail in a mailbox. callers appear to expect - * TRUE, FALSE or -1. I haven't checked if just returning the retcode would - * break anything */ -int imap_buffy_check (char *path) -{ - int retcode = 0; - - retcode = imap_mailbox_check (path, 1); - - return (retcode > 0) ? TRUE : retcode; -} - int imap_parse_list_response(CONNECTION *conn, char *buf, int buflen, char **name, int *noselect, int *noinferiors, char *delim) { @@ -1734,7 +1569,6 @@ int imap_subscribe (char *path, int subscribe) char buf[LONG_STRING]; char mbox[LONG_STRING]; char host[SHORT_STRING]; - char seq[16]; char *ipath = NULL; int port; @@ -1754,7 +1588,7 @@ int imap_subscribe (char *path, int subscribe) idata->conn = conn; } if (imap_open_connection (idata, conn)) - return (-1); + return -1; } imap_fix_path (idata, ipath, buf, sizeof (buf)); @@ -1763,15 +1597,13 @@ int imap_subscribe (char *path, int subscribe) else mutt_message (_("Unsubscribing to %s..."), buf); imap_quote_string (mbox, sizeof(mbox), buf); - imap_make_sequence (seq, sizeof (seq)); - snprintf (buf, sizeof (buf), "%s %s %s\r\n", seq, - subscribe ? "SUBSCRIBE" : "UNSUBSCRIBE", mbox); + snprintf (buf, sizeof (buf), "%s %s", subscribe ? "SUBSCRIBE" : + "UNSUBSCRIBE", mbox); + + if (imap_exec (buf, sizeof (buf), idata, buf, 0) < 0) + return -1; - if (imap_exec (buf, sizeof (buf), idata, seq, buf, 0) < 0) - { - return (-1); - } return 0; } diff --git a/imap/imap.h b/imap/imap.h index 15395f01..59a6506d 100644 --- a/imap/imap.h +++ b/imap/imap.h @@ -26,8 +26,6 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint); int imap_close_connection (CONTEXT *ctx); int imap_open_mailbox (CONTEXT *ctx); int imap_open_mailbox_append (CONTEXT *ctx); -int imap_parse_path (char *path, char *host, size_t hlen, int *port, - char **mbox); int imap_select_mailbox (CONTEXT *ctx, const char* path); void imap_set_logout (CONTEXT *ctx); int imap_sync_mailbox (CONTEXT *ctx, int expunge); @@ -37,11 +35,16 @@ int imap_mailbox_check (char *path, int new); int imap_subscribe (char *path, int subscribe); int imap_init_browse (char *path, struct browser_state *state); int imap_complete (char* dest, size_t dlen, char* path); -void imap_qualify_path (char* dest, size_t len, const char* host, int port, - const char* path, const char* name); /* message.c */ -int imap_append_message (CONTEXT *ctx, MESSAGE *msg); -int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno); +int imap_append_message (CONTEXT* ctx, MESSAGE* msg); +int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete); +int imap_fetch_message (MESSAGE* msg, CONTEXT* ctx, int msgno); + +/* util.c */ +int imap_parse_path (char* path, char* host, size_t hlen, int* port, + char** mbox); +void imap_qualify_path (char* dest, size_t len, const char* host, int port, + const char* path, const char* name); #endif diff --git a/imap/imap_private.h b/imap/imap_private.h index 618f9d4b..31a29af9 100644 --- a/imap/imap_private.h +++ b/imap/imap_private.h @@ -146,25 +146,20 @@ typedef struct /* -- private IMAP functions -- */ /* imap.c */ -int imap_code (const char *s); -void imap_error (const char *where, const char *msg); -int imap_exec (char *buf, size_t buflen, IMAP_DATA *idata, - const char *seq, const char *cmd, int flags); -char *imap_fix_path (IMAP_DATA *idata, char *mailbox, char *path, - size_t plen); -int imap_get_literal_count (const char *buf, long *bytes); -int imap_handle_untagged (IMAP_DATA *idata, char *s); -void imap_make_sequence (char *buf, size_t buflen); -char *imap_next_word (char *s); -int imap_open_connection (IMAP_DATA *idata, CONNECTION *conn); -time_t imap_parse_date (char *s); -int imap_parse_list_response(CONNECTION *conn, char *buf, int buflen, - char **name, int *noselect, int *noinferiors, char *delim); -int imap_read_bytes (FILE *fp, CONNECTION *conn, long bytes); -void imap_quote_string (char *dest, size_t slen, const char *src); -void imap_unquote_string (char *s); - -/* imap_auth.c */ +int imap_code (const char* s); +int imap_create_mailbox (IMAP_DATA* idata, char* mailbox); +int imap_exec (char* buf, size_t buflen, IMAP_DATA* idata, const char* cmd, + int flags); +int imap_handle_untagged (IMAP_DATA* idata, char* s); +int imap_make_msg_set (char* buf, size_t buflen, CONTEXT* ctx, int flag, + int changed); +int imap_open_connection (IMAP_DATA* idata, CONNECTION* conn); +time_t imap_parse_date (char* s); +int imap_parse_list_response(CONNECTION* conn, char* buf, int buflen, + char** name, int* noselect, int* noinferiors, char* delim); +int imap_read_bytes (FILE* fp, CONNECTION* conn, long bytes); + +/* auth.c */ int imap_authenticate (IMAP_DATA *idata, CONNECTION *conn); /* message.c */ @@ -172,4 +167,13 @@ 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); +/* util.c */ +void imap_error (const char* where, const char* msg); +char* imap_fix_path (IMAP_DATA* idata, char* mailbox, char* path, + size_t plen); +int imap_get_literal_count (const char* buf, long* bytes); +void imap_make_sequence (char *buf, size_t buflen); +char* imap_next_word (char* s); +void imap_quote_string (char* dest, size_t slen, const char* src); +void imap_unquote_string (char* s); #endif diff --git a/imap/message.c b/imap/message.c index 6b0faf3e..6772539e 100644 --- a/imap/message.c +++ b/imap/message.c @@ -507,6 +507,106 @@ int imap_append_message (CONTEXT *ctx, MESSAGE *msg) return 0; } +/* imap_copy_messages: use server COPY command to copy messages to another + * folder. + * Return codes: + * -1: error + * 0: success + * 1: non-fatal error - try fetch/append */ +int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete) +{ + char buf[LONG_STRING]; + char cmd[LONG_STRING]; + char mbox[LONG_STRING]; + char host[SHORT_STRING]; + int port; + char* pc; + int rc; + int n; + + if (imap_parse_path (dest, host, sizeof (host), &port, &pc)) + { + dprint (1, (debugfile, "imap_copy_message: bad destination %s\n", dest)); + return -1; + } + + /* check that the save-to folder is on the same server */ + if (mutt_socket_select_connection (host, port, 0) != CTX_DATA->conn) + { + dprint (3, (debugfile, "imap_copy_message: %s not same server as %s\n", + dest, ctx->path)); + return 1; + } + + imap_fix_path (CTX_DATA, pc, cmd, sizeof (cmd)); + + /* Null HEADER* means copy tagged messages */ + if (!h) + { + rc = imap_make_msg_set (buf, sizeof (buf), ctx, M_TAG, 0); + if (!rc) + { + dprint (1, (debugfile, "imap_copy_messages: No messages tagged\n")); + return -1; + } + mutt_message (_("Copying %d messages to %s..."), rc, cmd); + } + else + { + mutt_message (_("Copying message %d to %s..."), h->index+1, cmd); + snprintf (buf, sizeof (buf), "%d", h->index+1); + } + + /* let's get it on */ + strncpy (mbox, cmd, sizeof (mbox)); + snprintf (cmd, sizeof (cmd), "COPY %s \"%s\"", buf, mbox); + rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, IMAP_OK_FAIL); + if (rc == -2) + { + /* command failed because folder doesn't exist */ + if (option (OPTCONFIRMCREATE)) + { + snprintf (buf, sizeof (buf), _("Create %s?"), mbox); + if (mutt_yesorno (buf, 1) < 1) + return -1; + if (imap_create_mailbox (CTX_DATA, mbox) < 0) + return -1; + } + /* try again */ + rc = imap_exec (buf, sizeof (buf), CTX_DATA, cmd, 0); + } + if (rc != 0) + { + imap_error ("imap_copy_messages", buf); + return -1; + } + + /* cleanup */ + if (delete) + { + if (!h) + { + for (n = 0; n < ctx->msgcount; n++) + { + if (ctx->hdrs[n]->tagged) + { + mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1); + if (option (OPTDELETEUNTAG)) + mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0); + } + } + } + else + { + mutt_set_flag (ctx, h, M_DELETE, 1); + if (option (OPTDELETEUNTAG)) + mutt_set_flag (ctx, h, M_TAG, 0); + } + } + + 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) diff --git a/imap/util.c b/imap/util.c new file mode 100644 index 00000000..b8a94c83 --- /dev/null +++ b/imap/util.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu> + * Copyright (C) 1996-9 Brandon Long <blong@fiction.net> + * Copyright (C) 1999 Brendan Cully <brendan@kublai.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. |