📄 imap.c
字号:
char uid[11]; hdr->changed = 0; if (!compare_flags (hdr)) { idata->ctx->changed--; return 0; } snprintf (uid, sizeof (uid), "%u", HEADER_DATA(hdr)->uid); cmd->dptr = cmd->data; mutt_buffer_addstr (cmd, "UID STORE "); mutt_buffer_addstr (cmd, uid); flags[0] = '\0'; imap_set_flag (idata, IMAP_ACL_SEEN, hdr->read, "\\Seen ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, hdr->old, "Old ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, hdr->flagged, "\\Flagged ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, hdr->replied, "\\Answered ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_DELETE, hdr->deleted, "\\Deleted ", flags, sizeof (flags)); /* now make sure we don't lose custom tags */ if (mutt_bit_isset (idata->rights, IMAP_ACL_WRITE)) imap_add_keywords (flags, hdr, idata->flags, sizeof (flags)); mutt_remove_trailing_ws (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 (idata, IMAP_ACL_SEEN, 1, "\\Seen ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, 1, "Old ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, 1, "\\Flagged ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_WRITE, 1, "\\Answered ", flags, sizeof (flags)); imap_set_flag (idata, IMAP_ACL_DELETE, 1, "\\Deleted ", flags, sizeof (flags)); mutt_remove_trailing_ws (flags); mutt_buffer_addstr (cmd, " -FLAGS.SILENT ("); } else mutt_buffer_addstr (cmd, " FLAGS.SILENT ("); mutt_buffer_addstr (cmd, flags); mutt_buffer_addstr (cmd, ")"); /* dumb hack for bad UW-IMAP 4.7 servers spurious FLAGS updates */ hdr->active = 0; /* after all this it's still possible to have no flags, if you * have no ACL rights */ if (*flags && (imap_exec (idata, cmd->data, 0) != 0) && err_continue && (*err_continue != M_YES)) { *err_continue = imap_continue ("imap_sync_message: STORE failed", idata->buf); if (*err_continue != M_YES) return -1; } hdr->active = 1; idata->ctx->changed--; return 0;}static int sync_helper (IMAP_DATA* idata, BUFFER* buf, int right, int flag, const char* name){ int rc = 0; if (!mutt_bit_isset (idata->rights, right)) return 0; if (right == IMAP_ACL_WRITE && !imap_has_flag (idata->flags, name)) return 0; buf->dptr = buf->data; mutt_buffer_addstr (buf, "UID STORE "); if (imap_make_msg_set (idata, buf, flag, 1, 0)) { rc++; mutt_buffer_printf (buf, " +FLAGS.SILENT (%s)", name); imap_cmd_queue (idata, buf->data); } buf->dptr = buf->data; mutt_buffer_addstr (buf, "UID STORE "); if (imap_make_msg_set (idata, buf, flag, 1, 1)) { rc++; mutt_buffer_printf (buf, " -FLAGS.SILENT (%s)", name); imap_cmd_queue (idata, buf->data); } return rc;}/* 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* index_hint){ IMAP_DATA* idata; CONTEXT* appendctx = NULL; BUFFER cmd; HEADER* h; HEADER** hdrs = NULL; int oldsort; int deleted; int n; int rc;#if USE_HCACHE void* hc = NULL; char uidbuf[32];#endif idata = (IMAP_DATA*) ctx->data; if (idata->state < IMAP_SELECTED) { dprint (2, (debugfile, "imap_sync_mailbox: no mailbox selected\n")); return -1; } /* This function is only called when the calling code expects the context * to be changed. */ imap_allow_reopen (ctx); if ((rc = imap_check_mailbox (ctx, index_hint, 0)) != 0) return rc; memset (&cmd, 0, sizeof (cmd)); /* if we are expunging anyway, we can do deleted messages very quickly... */ if (expunge && mutt_bit_isset (idata->rights, IMAP_ACL_DELETE)) { mutt_buffer_addstr (&cmd, "UID STORE "); deleted = imap_make_msg_set (idata, &cmd, M_DELETED, 1, 0); /* if we have a message set, then let's delete */ if (deleted) { mutt_message (_("Marking %d messages deleted..."), deleted); mutt_buffer_addstr (&cmd, " +FLAGS.SILENT (\\Deleted)"); /* mark these messages as unchanged so second pass ignores them. Done * here so BOGUS UW-IMAP 4.7 SILENT FLAGS updates are ignored. */ for (n = 0; n < ctx->msgcount; n++) if (ctx->hdrs[n]->deleted && ctx->hdrs[n]->changed) ctx->hdrs[n]->active = 0; if (imap_exec (idata, cmd.data, 0) != 0) { mutt_error (_("Expunge failed")); mutt_sleep (1); rc = -1; goto out; } } }#if USE_HCACHE if (expunge && ctx->closing) hc = mutt_hcache_open (HeaderCache, idata->ctx->path);#endif /* save messages with real (non-flag) changes */ for (n = 0; n < ctx->msgcount; n++) { h = ctx->hdrs[n]; if (h->deleted) imap_cache_del (idata, h);#if USE_HCACHE if (hc && h->deleted) { sprintf (uidbuf, "/%u", HEADER_DATA(h)->uid); mutt_hcache_delete (hc, uidbuf, imap_hcache_keylen); }#endif if (h->active && h->changed) { /* if the message has been rethreaded or attachments have been deleted * we delete the message and reupload it. * This works better if we're expunging, of course. */ if ((h->env && (h->env->refs_changed || h->env->irt_changed)) || h->attach_del) { mutt_message (_("Saving changed messages... [%d/%d]"), n+1, ctx->msgcount); if (!appendctx) appendctx = mx_open_mailbox (ctx->path, M_APPEND | M_QUIET, NULL); if (!appendctx) { dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n")); } else _mutt_save_message (h, appendctx, 1, 0, 0); } } } /* sync +/- flags for the five flags mutt cares about */ rc = 0; /* presort here to avoid doing 10 resorts in imap_make_msg_set */ oldsort = Sort; if (Sort != SORT_ORDER) { hdrs = ctx->hdrs; ctx->hdrs = safe_malloc (ctx->msgcount * sizeof (HEADER*)); memcpy (ctx->hdrs, hdrs, ctx->msgcount * sizeof (HEADER*)); oldsort = Sort; Sort = SORT_ORDER; qsort (ctx->hdrs, ctx->msgcount, sizeof (HEADER*), mutt_get_sort_func (SORT_ORDER)); } rc += sync_helper (idata, &cmd, IMAP_ACL_DELETE, M_DELETED, "\\Deleted"); rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_FLAG, "\\Flagged"); rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_OLD, "Old"); rc += sync_helper (idata, &cmd, IMAP_ACL_SEEN, M_READ, "\\Seen"); rc += sync_helper (idata, &cmd, IMAP_ACL_WRITE, M_REPLIED, "\\Answered"); if (oldsort != Sort) { Sort = oldsort; FREE (&ctx->hdrs); ctx->hdrs = hdrs; } if (rc) { if ((rc = imap_exec (idata, NULL, 0)) != IMAP_CMD_OK) { if (ctx->closing) { if (mutt_yesorno (_("Error saving flags. Close anyway?"), 0) == M_YES) { rc = 0; idata->state = IMAP_AUTHENTICATED; goto out; } } else mutt_error _("Error saving flags"); goto out; } } for (n = 0; n < ctx->msgcount; n++) ctx->hdrs[n]->changed = 0; ctx->changed = 0; /* We must send an EXPUNGE command if we're not closing. */ if (expunge && !(ctx->closing) && mutt_bit_isset(idata->rights, IMAP_ACL_DELETE)) { mutt_message _("Expunging messages from server..."); /* Set expunge bit so we don't get spurious reopened messages */ idata->reopen |= IMAP_EXPUNGE_EXPECTED; if (imap_exec (idata, "EXPUNGE", 0) != 0) { imap_error (_("imap_sync_mailbox: EXPUNGE failed"), idata->buf); rc = -1; goto out; } } if (expunge && ctx->closing) { imap_cmd_queue (idata, "CLOSE"); idata->state = IMAP_AUTHENTICATED; } rc = 0; out:#if USE_HCACHE mutt_hcache_close (hc);#endif if (cmd.data) FREE (&cmd.data); if (appendctx) { mx_fastclose_mailbox (appendctx); FREE (&appendctx); } return rc;}/* imap_close_mailbox: clean up IMAP data in CONTEXT */void imap_close_mailbox (CONTEXT* ctx){ IMAP_DATA* idata; int i; idata = (IMAP_DATA*) ctx->data; /* Check to see if the mailbox is actually open */ if (!idata) return; if (ctx == idata->ctx) { if (idata->status != IMAP_FATAL && idata->state >= IMAP_SELECTED) { /* mx_close_mailbox won't sync if there are no deleted messages * and the mailbox is unchanged, so we may have to close here */ if (!ctx->deleted) imap_cmd_queue (idata, "CLOSE"); if (idata->state == IMAP_IDLE) { mutt_buffer_addstr (idata->cmdbuf, "DONE\r\n"); idata->state = IMAP_SELECTED; } idata->state = IMAP_AUTHENTICATED; } idata->reopen &= IMAP_REOPEN_ALLOW; FREE (&(idata->mailbox)); mutt_free_list (&idata->flags); idata->ctx = NULL; } /* 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++) { if (idata->cache[i].path) { unlink (idata->cache[i].path); FREE (&idata->cache[i].path); } } mutt_bcache_close (&idata->bcache);}/* use the NOOP or IDLE command to poll for new mail * * return values: * M_REOPENED mailbox has been externally modified * M_NEW_MAIL new mail has arrived! * 0 no change * -1 error */int imap_check_mailbox (CONTEXT *ctx, int *index_hint, int force){ /* overload keyboard timeout to avoid many mailbox checks in a row. * Most users don't like having to wait exactly when they press a key. */ IMAP_DATA* idata; int result = 0; idata = (IMAP_DATA*) ctx->data; /* try IDLE first, unless force is set */ if (!force && option (OPTIMAPIDLE) && mutt_bit_isset (idata->capabilities, IDLE) && (idata->state != IMAP_IDLE || time(NULL) >= idata->lastread + ImapKeepalive)) { imap_cmd_start (idata, "IDLE"); idata->state = IMAP_IDLE; do result = imap_cmd_step (idata); while (result == IMAP_CMD_CONTINUE); /* it's possible that we were notified and fetched mail before * getting to the +, in which case we've automatically unidled. */ if (result != IMAP_CMD_RESPOND && result != IMAP_CMD_OK) { dprint (1, (debugfile, "Error starting IDLE\n")); idata->state = IMAP_SELECTED; return -1; } } if (idata->state == IMAP_IDLE) { while ((result = mutt_socket_poll (idata->conn)) > 0) { if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE) { dprint (1, (debugfile, "Error reading IDLE response\n")); return -1; } } if (result < 0) { dprint (1, (debugfile, "Poll failed, disabling IDLE\n")); mutt_bit_unset (idata->capabilities, IDLE); } } if ((force || (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout)) && imap_exec (idata, "NOOP", 0) != 0) return -1; /* We call this even when we haven't run NOOP in case we have pending * changes to process, since we can reopen here. */ imap_cmd_finish (idata); if (idata->check_status & IMAP_EXPUNGE_PENDING) result = M_REOPENED; else if (idata->check_status & IMAP_NEWMAIL_PENDING) result = M_NEW_MAIL; else if (idata->check_status & IMAP_FLAGS_PENDING) result = M_FLAGS; idata->check_status = 0; return result;}/* split path into (idata,mailbox name) */static int imap_get_mailbox (const char* path, IMAP_DATA** hidata, char* buf, size_t blen){ IMAP_MBOX mx; if (imap_parse_path (path, &mx)) { dprint (1, (debugfile, "imap_get_mailbox: Error parsing %s\n", path)); return -1; } if (!(*hidata = imap_conn_find (&(mx.account), option (OPTIMAPPASSIVE) ? M_IMAP_CONN_NONEW : 0)) || (*hidata)->state < IMAP_AUTHENTICATED) { FREE (&mx.mbox); return -1; } imap_fix_path (*hidata, mx.mbox, buf, blen); FREE (&mx.mbox); return 0;}/* check for new mail in any subscribed mailboxes. Given a list of mailboxes * rather than called once for each so that it can batch the commands and * save on round trips. Returns number of mailboxes with new mail. */int imap_buffy_check (int force){ IMAP_DATA* idata; IMAP_DATA* lastdata = NULL; BUFFY* mailbox; char name[LONG_STRING]; char command[LONG_STRING]; char munged[LONG_STRING]; int buffies = 0; for (mailbox = Incoming; mailbox; mailbox = mailbox->next) { /* Init newly-added mailboxes */ if (! mailbox->magic) { if (mx_is_imap (mailbox->path)) mailbox->magic = M_IMAP; } if (mailbox->magic != M_IMAP) continue; mailbox->new = 0; if (imap_get_mailbox (mailbox->path, &idata, name, sizeof (name)) < 0) continue; /* Don't issue STATUS on the selected mailbox, it will be NOOPed or * IDLEd elsewhere */ if (!imap_mxcmp (name, idata->mailbox)) continue; if (!lastdata) lastdata = idata; if (idata != lastdata) { /* Send commands to previous server. Sorting the buffy list * may prevent some infelicitous interleavings */ if (imap_exec (lastdata, NULL, 0) != IMAP_CMD_OK)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -