📄 imap.c
字号:
/* sanity-check string */ if (ascii_strncasecmp ("FLAGS", s, 5) != 0) { dprint (1, (debugfile, "imap_get_flags: not a FLAGS response: %s\n", s)); return NULL; } s += 5; SKIPWS(s); if (*s != '(') { dprint (1, (debugfile, "imap_get_flags: bogus FLAGS response: %s\n", s)); return NULL; } /* create list, update caller's flags handle */ flags = mutt_new_list(); *hflags = flags; while (*s && *s != ')') { s++; SKIPWS(s); flag_word = s; while (*s && (*s != ')') && !ISSPACE (*s)) s++; ctmp = *s; *s = '\0'; if (*flag_word) mutt_add_list (flags, flag_word); *s = ctmp; } /* note bad flags response */ if (*s != ')') { dprint (1, (debugfile, "imap_get_flags: Unterminated FLAGS response: %s\n", s)); mutt_free_list (hflags); return NULL; } s++; return s;}int imap_open_mailbox (CONTEXT* ctx){ CONNECTION *conn; IMAP_DATA *idata; IMAP_STATUS* status, sb; char buf[LONG_STRING]; char bufout[LONG_STRING]; int count = 0; IMAP_MBOX mx, pmx; int rc; if (imap_parse_path (ctx->path, &mx)) { mutt_error (_("%s is an invalid IMAP path"), ctx->path); return -1; } /* we require a connection which isn't currently in IMAP_SELECTED state */ if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NOSELECT))) goto fail_noidata; if (idata->state < IMAP_AUTHENTICATED) goto fail; conn = idata->conn; /* once again the context is new */ ctx->data = idata; /* Clean up path and replace the one in the ctx */ imap_fix_path (idata, mx.mbox, buf, sizeof (buf)); FREE(&(idata->mailbox)); idata->mailbox = safe_strdup (buf); imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox); FREE (&(ctx->path)); ctx->path = safe_strdup (buf); idata->ctx = ctx; /* clear mailbox status */ idata->status = 0; memset (idata->rights, 0, (RIGHTSMAX+7)/8); idata->newMailCount = 0; mutt_message (_("Selecting %s..."), idata->mailbox); imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox); /* pipeline ACL test */ if (mutt_bit_isset (idata->capabilities, ACL)) { snprintf (bufout, sizeof (bufout), "MYRIGHTS %s", buf); imap_cmd_queue (idata, bufout); } /* assume we have all rights if ACL is unavailable */ else { mutt_bit_set (idata->rights, IMAP_ACL_LOOKUP); mutt_bit_set (idata->rights, IMAP_ACL_READ); mutt_bit_set (idata->rights, IMAP_ACL_SEEN); mutt_bit_set (idata->rights, IMAP_ACL_WRITE); mutt_bit_set (idata->rights, IMAP_ACL_INSERT); mutt_bit_set (idata->rights, IMAP_ACL_POST); mutt_bit_set (idata->rights, IMAP_ACL_CREATE); mutt_bit_set (idata->rights, IMAP_ACL_DELETE); } /* pipeline the postponed count if possible */ pmx.mbox = NULL; if (mx_is_imap (Postponed) && !imap_parse_path (Postponed, &pmx) && mutt_account_match (&pmx.account, &mx.account)) imap_status (Postponed, 1); FREE (&pmx.mbox); snprintf (bufout, sizeof (bufout), "%s %s", ctx->readonly ? "EXAMINE" : "SELECT", buf); idata->state = IMAP_SELECTED; imap_cmd_start (idata, bufout); if (!(status = imap_mboxcache_get (idata, idata->mailbox))) { memset (&sb, 0, sizeof (IMAP_STATUS)); sb.name = idata->mailbox; idata->mboxcache = mutt_add_list_n (idata->mboxcache, &sb, sizeof (IMAP_STATUS)); status = imap_mboxcache_get (idata, idata->mailbox); status->name = safe_strdup (idata->mailbox); } do { char *pc; if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; pc = idata->buf + 2; /* Obtain list of available flags here, may be overridden by a * PERMANENTFLAGS tag in the OK response */ if (ascii_strncasecmp ("FLAGS", pc, 5) == 0) { /* don't override PERMANENTFLAGS */ if (!idata->flags) { dprint (2, (debugfile, "Getting mailbox FLAGS\n")); if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) goto fail; } } /* PERMANENTFLAGS are massaged to look like FLAGS, then override FLAGS */ else if (ascii_strncasecmp ("OK [PERMANENTFLAGS", pc, 18) == 0) { dprint (2, (debugfile, "Getting mailbox PERMANENTFLAGS\n")); /* safe to call on NULL */ mutt_free_list (&(idata->flags)); /* skip "OK [PERMANENT" so syntax is the same as FLAGS */ pc += 13; if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL) goto fail; } /* save UIDVALIDITY for the header cache */ else if (ascii_strncasecmp ("OK [UIDVALIDITY", pc, 14) == 0) { dprint (2, (debugfile, "Getting mailbox UIDVALIDITY\n")); pc += 3; pc = imap_next_word (pc); idata->uid_validity = strtol (pc, NULL, 10); status->uidvalidity = idata->uid_validity; } else if (ascii_strncasecmp ("OK [UIDNEXT", pc, 11) == 0) { dprint (2, (debugfile, "Getting mailbox UIDNEXT\n")); pc += 3; pc = imap_next_word (pc); idata->uidnext = strtol (pc, NULL, 10); status->uidnext = idata->uidnext; } else { pc = imap_next_word (pc); if (!ascii_strncasecmp ("EXISTS", pc, 6)) { count = idata->newMailCount; idata->newMailCount = 0; } } } while (rc == IMAP_CMD_CONTINUE); if (rc == IMAP_CMD_NO) { char *s; s = imap_next_word (idata->buf); /* skip seq */ s = imap_next_word (s); /* Skip response */ mutt_error ("%s", s); mutt_sleep (2); goto fail; } if (rc != IMAP_CMD_OK) goto fail; /* check for READ-ONLY notification */ if (!ascii_strncasecmp (imap_get_qualifier (idata->buf), "[READ-ONLY]", 11) \ && !mutt_bit_isset (idata->capabilities, ACL)) { dprint (2, (debugfile, "Mailbox is read-only.\n")); ctx->readonly = 1; }#ifdef DEBUG /* dump the mailbox flags we've found */ if (debuglevel > 2) { if (!idata->flags) dprint (3, (debugfile, "No folder flags found\n")); else { LIST* t = idata->flags; dprint (3, (debugfile, "Mailbox flags: ")); t = t->next; while (t) { dprint (3, (debugfile, "[%s] ", t->data)); t = t->next; } dprint (3, (debugfile, "\n")); } }#endif if (!(mutt_bit_isset(idata->rights, IMAP_ACL_DELETE) || mutt_bit_isset(idata->rights, IMAP_ACL_SEEN) || mutt_bit_isset(idata->rights, IMAP_ACL_WRITE) || mutt_bit_isset(idata->rights, IMAP_ACL_INSERT))) ctx->readonly = 1; ctx->hdrmax = count; ctx->hdrs = safe_calloc (count, sizeof (HEADER *)); ctx->v2r = safe_calloc (count, sizeof (int)); ctx->msgcount = 0; if (count && (imap_read_headers (idata, 0, count-1) < 0)) { mutt_error _("Error opening mailbox"); mutt_sleep (1); goto fail; } dprint (2, (debugfile, "imap_open_mailbox: msgcount is %d\n", ctx->msgcount)); FREE (&mx.mbox); return 0; fail: if (idata->state == IMAP_SELECTED) idata->state = IMAP_AUTHENTICATED; fail_noidata: FREE (&mx.mbox); return -1;}int imap_open_mailbox_append (CONTEXT *ctx){ CONNECTION *conn; IMAP_DATA *idata; char buf[LONG_STRING]; char mailbox[LONG_STRING]; IMAP_MBOX mx; if (imap_parse_path (ctx->path, &mx)) return -1; /* in APPEND mode, we appear to hijack an existing IMAP connection - * ctx is brand new and mostly empty */ if (!(idata = imap_conn_find (&(mx.account), 0))) { FREE (&mx.mbox); return -1; } conn = idata->conn; ctx->magic = M_IMAP; ctx->data = idata; imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox)); FREE (&mx.mbox); /* really we should also check for W_OK */ if (!imap_access (ctx->path, F_OK)) return 0; snprintf (buf, sizeof (buf), _("Create %s?"), mailbox); if (option (OPTCONFIRMCREATE) && mutt_yesorno (buf, 1) < 1) return -1; if (imap_create_mailbox (idata, mailbox) < 0) return -1; return 0;}/* imap_logout: Gracefully log out of server. */void imap_logout (IMAP_DATA* idata){ /* we set status here to let imap_handle_untagged know we _expect_ to * receive a bye response (so it doesn't freak out and close the conn) */ idata->status = IMAP_BYE; imap_cmd_start (idata, "LOGOUT"); while (imap_cmd_step (idata) == IMAP_CMD_CONTINUE) ; FREE(& idata->buf); mutt_bcache_close (&idata->bcache); FREE(& idata);}/* imap_set_flag: append str to flags if we currently have permission * according to aclbit */static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag, const char *str, char *flags, size_t flsize){ if (mutt_bit_isset (idata->rights, aclbit)) if (flag && imap_has_flag (idata->flags, str)) safe_strcat (flags, flsize, str);}/* imap_has_flag: do a caseless comparison of the flag against a flag list,* return 1 if found or flag list has '\*', 0 otherwise */int imap_has_flag (LIST* flag_list, const char* flag){ if (!flag_list) return 0; flag_list = flag_list->next; while (flag_list) { if (!ascii_strncasecmp (flag_list->data, flag, strlen (flag_list->data))) return 1; if (!ascii_strncmp (flag_list->data, "\\*", strlen (flag_list->data))) return 1; flag_list = flag_list->next; } return 0;}/* imap_make_msg_set: make an IMAP4rev1 UID message set out of a set of * headers, given a flag enum to filter on. * Params: idata: IMAP_DATA containing context containing header set * buf: to write message set into * buflen: length of buffer * flag: enum of flag type on which to filter * changed: include only changed messages in message set * invert: invert sense of flag, eg M_READ matches unread messages * Returns: number of messages in message set (0 if no matches) */int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag, int changed, int invert){ HEADER** hdrs; /* sorted local copy */ int count = 0; /* number of messages in message set */ int match = 0; /* whether current message matches flag condition */ unsigned int setstart = 0; /* start of current message range */ int n; short oldsort; /* we clobber reverse, must restore it */ int started = 0; if (Sort != SORT_ORDER) { hdrs = safe_calloc (idata->ctx->msgcount, sizeof (HEADER*)); memcpy (hdrs, idata->ctx->hdrs, idata->ctx->msgcount * sizeof (HEADER*)); oldsort = Sort; Sort = SORT_ORDER; qsort ((void*) hdrs, idata->ctx->msgcount, sizeof (HEADER*), mutt_get_sort_func (SORT_ORDER)); Sort = oldsort; } else hdrs = idata->ctx->hdrs; for (n = 0; n < idata->ctx->msgcount; n++) { match = 0; /* don't include pending expunged messages */ if (hdrs[n]->active) switch (flag) { case M_DELETED: if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted) match = invert ^ hdrs[n]->deleted; break; case M_FLAG: if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged) match = invert ^ hdrs[n]->flagged; break; case M_OLD: if (hdrs[n]->old != HEADER_DATA(hdrs[n])->old) match = invert ^ hdrs[n]->old; break; case M_READ: if (hdrs[n]->read != HEADER_DATA(hdrs[n])->read) match = invert ^ hdrs[n]->read; break; case M_REPLIED: if (hdrs[n]->replied != HEADER_DATA(hdrs[n])->replied) match = invert ^ hdrs[n]->replied; break; case M_TAG: if (hdrs[n]->tagged) match = 1; break; } if (match && (!changed || hdrs[n]->changed)) { count++; if (setstart == 0) { setstart = HEADER_DATA (hdrs[n])->uid; if (started == 0) { mutt_buffer_printf (buf, "%u", HEADER_DATA (hdrs[n])->uid); started = 1; } else mutt_buffer_printf (buf, ",%u", HEADER_DATA (hdrs[n])->uid); } /* tie up if the last message also matches */ else if (n == idata->ctx->msgcount-1) mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n])->uid); } /* this message is not expunged and doesn't match. End current set. */ else if (setstart && hdrs[n]->active) { if (HEADER_DATA (hdrs[n-1])->uid > setstart) mutt_buffer_printf (buf, ":%u", HEADER_DATA (hdrs[n-1])->uid); setstart = 0; } } if (Sort != SORT_ORDER) FREE (&hdrs); return count;}/* returns 0 if mutt's flags match cached server flags */static int compare_flags (HEADER* h){ IMAP_HEADER_DATA* hd = (IMAP_HEADER_DATA*)h->data; if (h->read != hd->read) return 1; if (h->old != hd->old) return 1; if (h->flagged != hd->flagged) return 1; if (h->replied != hd->replied) return 1; if (h->deleted != hd->deleted) return 1; return 0;}/* Update the IMAP server to reflect the flags a single message. */int imap_sync_message (IMAP_DATA *idata, HEADER *hdr, BUFFER *cmd, int *err_continue){ char flags[LONG_STRING];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -