📄 imap.c
字号:
dprint (1, (debugfile, "Error polling mailboxes\n")); lastdata = NULL; } if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) && !mutt_bit_isset (idata->capabilities, STATUS)) { dprint (2, (debugfile, "Server doesn't support STATUS\n")); continue; } imap_munge_mbox_name (munged, sizeof (munged), name); snprintf (command, sizeof (command), "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN)", munged); if (imap_cmd_queue (idata, command) < 0) { /* pipeline must be full, drain it */ dprint (2, (debugfile, "IMAP command pipeline full, draining\n")); if (imap_exec (idata, NULL, 0) != IMAP_CMD_OK) dprint (1, (debugfile, "Error polling mailboxes\n")); if (imap_cmd_queue (idata, command) < 0) { /* real trouble */ dprint (1, (debugfile, "Error queueing command\n")); return 0; } } } if (lastdata && (imap_exec (lastdata, NULL, 0) != IMAP_CMD_OK)) { dprint (1, (debugfile, "Error polling mailboxes")); return 0; } /* collect results */ for (mailbox = Incoming; mailbox; mailbox = mailbox->next) { if (mailbox->magic == M_IMAP && mailbox->new) buffies++; } return buffies;}/* imap_status: returns count of messages in mailbox, or -1 on error. * if queue != 0, queue the command and expect it to have been run * on the next call (for pipelining the postponed count) */int imap_status (char* path, int queue){ static int queued = 0; IMAP_DATA *idata; char buf[LONG_STRING]; char mbox[LONG_STRING]; IMAP_STATUS* status; if (imap_get_mailbox (path, &idata, buf, sizeof (buf)) < 0) return -1; if (!imap_mxcmp (buf, idata->mailbox)) /* We are in the folder we're polling - just return the mailbox count */ return idata->ctx->msgcount; else if (mutt_bit_isset(idata->capabilities,IMAP4REV1) || mutt_bit_isset(idata->capabilities,STATUS)) { imap_munge_mbox_name (mbox, sizeof(mbox), buf); snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox, "MESSAGES"); imap_unmunge_mbox_name (mbox); } else /* Server does not support STATUS, and this is not the current mailbox. * There is no lightweight way to check recent arrivals */ return -1; if (queue) { imap_cmd_queue (idata, buf); queued = 1; return 0; } else if (!queued) imap_exec (idata, buf, 0); queued = 0; if ((status = imap_mboxcache_get (idata, mbox))) return status->messages; return 0;}/* return cached mailbox stats or NULL */IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox){ LIST* cur; IMAP_STATUS* status; for (cur = idata->mboxcache; cur; cur = cur->next) { status = (IMAP_STATUS*)cur->data; if (!imap_mxcmp (mbox, status->name)) return status; } return NULL;}void imap_mboxcache_free (IMAP_DATA* idata){ LIST* cur; IMAP_STATUS* status; for (cur = idata->mboxcache; cur; cur = cur->next) { status = (IMAP_STATUS*)cur->data; FREE (&status->name); } mutt_free_list (&idata->mboxcache);}/* returns number of patterns in the search that should be done server-side * (eg are full-text) */static int do_search (const pattern_t* search, int allpats){ int rc = 0; const pattern_t* pat; for (pat = search; pat; pat = pat->next) { switch (pat->op) { case M_BODY: case M_HEADER: case M_WHOLE_MSG: if (pat->stringmatch) rc++; break; default: if (pat->child && do_search (pat->child, 1)) rc++; } if (!allpats) break; } return rc;}/* convert mutt pattern_t to IMAP SEARCH command containing only elements * that require full-text search (mutt already has what it needs for most * match types, and does a better job (eg server doesn't support regexps). */static int imap_compile_search (const pattern_t* pat, BUFFER* buf){ if (! do_search (pat, 0)) return 0; if (pat->not) mutt_buffer_addstr (buf, "NOT "); if (pat->child) { int clauses; if ((clauses = do_search (pat->child, 1)) > 0) { const pattern_t* clause = pat->child; mutt_buffer_addch (buf, '('); while (clauses) { if (do_search (clause, 0)) { if (pat->op == M_OR && clauses > 1) mutt_buffer_addstr (buf, "OR "); clauses--; if (imap_compile_search (clause, buf) < 0) return -1; if (clauses) mutt_buffer_addch (buf, ' '); clause = clause->next; } } mutt_buffer_addch (buf, ')'); } } else { char term[STRING]; char *delim; switch (pat->op) { case M_HEADER: mutt_buffer_addstr (buf, "HEADER "); /* extract header name */ if (! (delim = strchr (pat->p.str, ':'))) { mutt_error (_("Header search without header name: %s"), pat->p.str); return -1; } *delim = '\0'; imap_quote_string (term, sizeof (term), pat->p.str); mutt_buffer_addstr (buf, term); mutt_buffer_addch (buf, ' '); /* and field */ *delim = ':'; delim++; SKIPWS(delim); imap_quote_string (term, sizeof (term), delim); mutt_buffer_addstr (buf, term); break; case M_BODY: mutt_buffer_addstr (buf, "BODY "); imap_quote_string (term, sizeof (term), pat->p.str); mutt_buffer_addstr (buf, term); break; case M_WHOLE_MSG: mutt_buffer_addstr (buf, "TEXT "); imap_quote_string (term, sizeof (term), pat->p.str); mutt_buffer_addstr (buf, term); break; } } return 0;}int imap_search (CONTEXT* ctx, const pattern_t* pat){ BUFFER buf; IMAP_DATA* idata = (IMAP_DATA*)ctx->data; int i; for (i = 0; i < ctx->msgcount; i++) ctx->hdrs[i]->matched = 0; if (!do_search (pat, 1)) return 0; memset (&buf, 0, sizeof (buf)); mutt_buffer_addstr (&buf, "UID SEARCH "); if (imap_compile_search (pat, &buf) < 0) { FREE (&buf.data); return -1; } if (imap_exec (idata, buf.data, 0) < 0) { FREE (&buf.data); return -1; } FREE (&buf.data); return 0;}int imap_subscribe (char *path, int subscribe){ CONNECTION *conn; IMAP_DATA *idata; char buf[LONG_STRING]; char mbox[LONG_STRING]; char errstr[STRING]; BUFFER err, token; IMAP_MBOX mx; if (!mx_is_imap (path) || imap_parse_path (path, &mx)) { mutt_error (_("Bad mailbox name")); return -1; } if (!(idata = imap_conn_find (&(mx.account), 0))) goto fail; conn = idata->conn; imap_fix_path (idata, mx.mbox, buf, sizeof (buf)); if (option (OPTIMAPCHECKSUBSCRIBED)) { memset (&token, 0, sizeof (token)); err.data = errstr; err.dsize = sizeof (errstr); snprintf (mbox, sizeof (mbox), "%smailboxes \"%s\"", subscribe ? "" : "un", path); if (mutt_parse_rc_line (mbox, &token, &err)) dprint (1, (debugfile, "Error adding subscribed mailbox: %s\n", errstr)); FREE (&token.data); } if (subscribe) mutt_message (_("Subscribing to %s..."), buf); else mutt_message (_("Unsubscribing from %s..."), buf); imap_munge_mbox_name (mbox, sizeof(mbox), buf); snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox); if (imap_exec (idata, buf, 0) < 0) goto fail; imap_unmunge_mbox_name(mx.mbox); if (subscribe) mutt_message (_("Subscribed to %s"), mx.mbox); else mutt_message (_("Unsubscribed from %s"), mx.mbox); FREE (&mx.mbox); return 0; fail: FREE (&mx.mbox); return -1;}/* trim dest to the length of the longest prefix it shares with src, * returning the length of the trimmed string */static intlongest_common_prefix (char *dest, const char* src, int start, size_t dlen){ int pos = start; while (pos < dlen && dest[pos] && dest[pos] == src[pos]) pos++; dest[pos] = '\0'; return pos;}/* look for IMAP URLs to complete from defined mailboxes. Could be extended * to complete over open connections and account/folder hooks too. */static intimap_complete_hosts (char *dest, size_t len){ BUFFY* mailbox; CONNECTION* conn; int rc = -1; int matchlen; matchlen = mutt_strlen (dest); for (mailbox = Incoming; mailbox && mailbox->next; mailbox = mailbox->next) { if (!mutt_strncmp (dest, mailbox->path, matchlen)) { if (rc) { strfcpy (dest, mailbox->path, len); rc = 0; } else longest_common_prefix (dest, mailbox->path, matchlen, len); } } for (conn = mutt_socket_head (); conn && conn->next; conn = conn->next) { ciss_url_t url; char urlstr[LONG_STRING]; if (conn->account.type != M_ACCT_TYPE_IMAP) continue; mutt_account_tourl (&conn->account, &url); /* FIXME: how to handle multiple users on the same host? */ url.user = NULL; url.path = NULL; url_ciss_tostring (&url, urlstr, sizeof (urlstr), 0); if (!mutt_strncmp (dest, urlstr, matchlen)) { if (rc) { strfcpy (dest, urlstr, len); rc = 0; } else longest_common_prefix (dest, urlstr, matchlen, len); } } return rc;}/* imap_complete: given a partial IMAP folder path, return a string which * adds as much to the path as is unique */int imap_complete(char* dest, size_t dlen, char* path) { CONNECTION* conn; IMAP_DATA* idata; char list[LONG_STRING]; char buf[LONG_STRING]; IMAP_LIST listresp; char completion[LONG_STRING]; int clen, matchlen = 0; int completions = 0; IMAP_MBOX mx; int rc; if (imap_parse_path (path, &mx) || !mx.mbox) { strfcpy (dest, path, dlen); return imap_complete_hosts (dest, dlen); } /* don't open a new socket just for completion. Instead complete over * known mailboxes/hooks/etc */ if (!(idata = imap_conn_find (&(mx.account), M_IMAP_CONN_NONEW))) { FREE (&mx.mbox); strfcpy (dest, path, dlen); return imap_complete_hosts (dest, dlen); } conn = idata->conn; /* reformat path for IMAP list, and append wildcard */ /* don't use INBOX in place of "" */ if (mx.mbox && mx.mbox[0]) imap_fix_path (idata, mx.mbox, list, sizeof(list)); else list[0] = '\0'; /* fire off command */ snprintf (buf, sizeof(buf), "%s \"\" \"%s%%\"", option (OPTIMAPLSUB) ? "LSUB" : "LIST", list); imap_cmd_start (idata, buf); /* and see what the results are */ strfcpy (completion, NONULL(mx.mbox), sizeof(completion)); idata->cmddata = &listresp; do { listresp.name = NULL; rc = imap_cmd_step (idata); if (rc == IMAP_CMD_CONTINUE && listresp.name) { /* if the folder isn't selectable, append delimiter to force browse * to enter it on second tab. */ if (listresp.noselect) { clen = strlen(listresp.name); listresp.name[clen++] = listresp.delim; listresp.name[clen] = '\0'; } /* copy in first word */ if (!completions) { strfcpy (completion, listresp.name, sizeof(completion)); matchlen = strlen (completion); completions++; continue; } matchlen = longest_common_prefix (completion, listresp.name, 0, matchlen); completions++; } } while (rc == IMAP_CMD_CONTINUE); idata->cmddata = NULL; if (completions) { /* reformat output */ imap_qualify_path (dest, dlen, &mx, completion); mutt_pretty_mailbox (dest); FREE (&mx.mbox); return 0; } return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -