⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 command.c

📁 mutt-1.5.12 源代码。linux 下邮件接受的工具。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1996-8 Michael R. Elkins <me@mutt.org> * Copyright (C) 1996-9 Brandon Long <blong@fiction.net> * Copyright (C) 1999-2006 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. *  *     You should have received a copy of the GNU General Public License *     along with this program; if not, write to the Free Software *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */ /* command.c: routines for sending commands to an IMAP server and parsing *  responses */#if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "imap_private.h"#include "message.h"#include "mx.h"#include "buffy.h"#include <ctype.h>#include <stdlib.h>#define IMAP_CMD_BUFSIZE 512/* forward declarations */static IMAP_COMMAND* cmd_new (IMAP_DATA* idata);static int cmd_status (const char *s);static void cmd_handle_fatal (IMAP_DATA* idata);static int cmd_handle_untagged (IMAP_DATA* idata);static void cmd_parse_capability (IMAP_DATA* idata, char* s);static void cmd_parse_expunge (IMAP_DATA* idata, const char* s);static void cmd_parse_list (IMAP_DATA* idata, char* s);static void cmd_parse_lsub (IMAP_DATA* idata, char* s);static void cmd_parse_fetch (IMAP_DATA* idata, char* s);static void cmd_parse_myrights (IMAP_DATA* idata, const char* s);static void cmd_parse_search (IMAP_DATA* idata, const char* s);static void cmd_parse_status (IMAP_DATA* idata, char* s);static char *Capabilities[] = {  "IMAP4",  "IMAP4rev1",  "STATUS",  "ACL",   "NAMESPACE",  "AUTH=CRAM-MD5",  "AUTH=GSSAPI",  "AUTH=ANONYMOUS",  "STARTTLS",  "LOGINDISABLED",  "IDLE",  "SASL-IR",  NULL};/* imap_cmd_queue: Add command to command queue. Fails if the queue is full. */int imap_cmd_queue (IMAP_DATA* idata, const char* cmdstr){  IMAP_COMMAND* cmd;  if (idata->status == IMAP_FATAL)  {    cmd_handle_fatal (idata);    return IMAP_CMD_BAD;  }  if (!(cmd = cmd_new (idata)))    return IMAP_CMD_BAD;  if (mutt_buffer_printf (idata->cmdbuf, "%s%s %s\r\n",      idata->state == IMAP_IDLE ? "DONE\r\n" : "", cmd->seq, cmdstr) < 0)    return IMAP_CMD_BAD;  if (idata->state == IMAP_IDLE)    idata->state = IMAP_SELECTED;  return 0;}/* imap_cmd_start: Given an IMAP command, send it to the server. *   If cmdstr is NULL, sends queued commands. */int imap_cmd_start (IMAP_DATA* idata, const char* cmdstr){  int rc;  if (cmdstr && (rc = imap_cmd_queue (idata, cmdstr)) < 0)    return rc;  /* don't write old or empty commands */  if (idata->cmdbuf->dptr == idata->cmdbuf->data)    return IMAP_CMD_BAD;  rc = mutt_socket_write (idata->conn, idata->cmdbuf->data);  idata->cmdbuf->dptr = idata->cmdbuf->data;  return (rc < 0) ? IMAP_CMD_BAD : 0;}/* imap_cmd_step: Reads server responses from an IMAP command, detects *   tagged completion response, handles untagged messages, can read *   arbitrarily large strings (using malloc, so don't make it _too_ *   large!). */int imap_cmd_step (IMAP_DATA* idata){  size_t len = 0;  int c;  int rc;  if (idata->status == IMAP_FATAL)  {    cmd_handle_fatal (idata);    return IMAP_CMD_BAD;  }  /* read into buffer, expanding buffer as necessary until we have a full   * line */  do  {    if (len == idata->blen)    {      safe_realloc (&idata->buf, idata->blen + IMAP_CMD_BUFSIZE);      idata->blen = idata->blen + IMAP_CMD_BUFSIZE;      dprint (3, (debugfile, "imap_cmd_step: grew buffer to %u bytes\n",		  idata->blen));    }    /* back up over '\0' */    if (len)      len--;    c = mutt_socket_readln (idata->buf + len, idata->blen - len, idata->conn);    if (c <= 0)    {      dprint (1, (debugfile, "imap_cmd_step: Error reading server response.\n"));      cmd_handle_fatal (idata);      return IMAP_CMD_BAD;    }    len += c;  }  /* if we've read all the way to the end of the buffer, we haven't read a   * full line (mutt_socket_readln strips the \r, so we always have at least   * one character free when we've read a full line) */  while (len == idata->blen);  /* don't let one large string make cmd->buf hog memory forever */  if ((idata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))  {    safe_realloc (&idata->buf, IMAP_CMD_BUFSIZE);    idata->blen = IMAP_CMD_BUFSIZE;    dprint (3, (debugfile, "imap_cmd_step: shrank buffer to %u bytes\n", idata->blen));  }  idata->lastread = time (NULL);  /* handle untagged messages. The caller still gets its shot afterwards. */  if (!ascii_strncmp (idata->buf, "* ", 2) &&      cmd_handle_untagged (idata))    return IMAP_CMD_BAD;  /* server demands a continuation response from us */  if (idata->buf[0] == '+')    return IMAP_CMD_RESPOND;  /* tagged completion code. TODO: I believe commands will always be completed   * in order, but will have to double-check when I have net again */  rc = IMAP_CMD_CONTINUE;  if (!ascii_strncmp (idata->buf, idata->cmds[idata->lastcmd].seq, SEQLEN))  {    idata->cmds[idata->lastcmd].state = cmd_status (idata->buf);    idata->lastcmd = (idata->lastcmd + 1) % IMAP_PIPELINE_DEPTH;    if (idata->lastcmd == idata->nextcmd)    {      rc = cmd_status (idata->buf);      imap_cmd_finish (idata);    }  }  return rc;}/* imap_code: returns 1 if the command result was OK, or 0 if NO or BAD */int imap_code (const char *s){  return cmd_status (s) == IMAP_CMD_OK;}/* imap_exec: execute a command, and wait for the response from the server. * Also, handle untagged responses. * Flags: *   IMAP_CMD_FAIL_OK: the calling procedure can handle failure. This is used *     for checking for a mailbox on append and login *   IMAP_CMD_PASS: command contains a password. Suppress logging. * Return 0 on success, -1 on Failure, -2 on OK Failure */int imap_exec (IMAP_DATA* idata, const char* cmdstr, int flags){  int rc;  if (idata->status == IMAP_FATAL)  {    cmd_handle_fatal (idata);    return -1;  }  if (cmdstr && (rc = imap_cmd_queue (idata, cmdstr)) < 0)    return rc;    /* don't write old or empty commands */  if (idata->cmdbuf->dptr == idata->cmdbuf->data)    return IMAP_CMD_BAD;    rc = mutt_socket_write_d (idata->conn, idata->cmdbuf->data, -1,    flags & IMAP_CMD_PASS ? IMAP_LOG_PASS : IMAP_LOG_CMD);  idata->cmdbuf->dptr = idata->cmdbuf->data;  if (rc < 0)  {    cmd_handle_fatal (idata);    return -1;  }  do    rc = imap_cmd_step (idata);  while (rc == IMAP_CMD_CONTINUE);  if (rc == IMAP_CMD_NO && (flags & IMAP_CMD_FAIL_OK))    return -2;  if (rc != IMAP_CMD_OK)  {    if (flags & IMAP_CMD_FAIL_OK)      return -2;    dprint (1, (debugfile, "imap_exec: command failed: %s\n", idata->buf));    return -1;  }  return 0;}/* imap_cmd_finish: Attempts to perform cleanup (eg fetch new mail if *   detected, do expunge). Called automatically by imap_cmd_step, but *   may be called at any time. Called by imap_check_mailbox just before *   the index is refreshed, for instance. */void imap_cmd_finish (IMAP_DATA* idata){  if (idata->status == IMAP_FATAL)  {    cmd_handle_fatal (idata);    return;  }  if (!(idata->state >= IMAP_SELECTED) || idata->ctx->closing)    return;    if (idata->reopen & IMAP_REOPEN_ALLOW)  {    int count = idata->newMailCount;    if (!(idata->reopen & IMAP_EXPUNGE_PENDING) &&	(idata->reopen & IMAP_NEWMAIL_PENDING)	&& count > idata->ctx->msgcount)    {      /* read new mail messages */      dprint (2, (debugfile, "imap_cmd_finish: Fetching new mail\n"));      /* check_status: curs_main uses imap_check_mailbox to detect       *   whether the index needs updating */      idata->check_status = IMAP_NEWMAIL_PENDING;      imap_read_headers (idata, idata->ctx->msgcount, count-1);    }    else if (idata->reopen & IMAP_EXPUNGE_PENDING)    {      dprint (2, (debugfile, "imap_cmd_finish: Expunging mailbox\n"));      imap_expunge_mailbox (idata);      /* Detect whether we've gotten unexpected EXPUNGE messages */      if (idata->reopen & IMAP_EXPUNGE_PENDING &&	  !(idata->reopen & IMAP_EXPUNGE_EXPECTED))	idata->check_status = IMAP_EXPUNGE_PENDING;      idata->reopen &= ~(IMAP_EXPUNGE_PENDING | IMAP_NEWMAIL_PENDING |			 IMAP_EXPUNGE_EXPECTED);    }  }  idata->status = 0;}/* sets up a new command control block and adds it to the queue. * Returns NULL if the pipeline is full. */static IMAP_COMMAND* cmd_new (IMAP_DATA* idata){  IMAP_COMMAND* cmd;  if ((idata->nextcmd + 1) % IMAP_PIPELINE_DEPTH == idata->lastcmd)  {    dprint (2, (debugfile, "cmd_new: IMAP command queue full\n"));    return NULL;  }  cmd = idata->cmds + idata->nextcmd;  idata->nextcmd = (idata->nextcmd + 1) % IMAP_PIPELINE_DEPTH;  snprintf (cmd->seq, sizeof (cmd->seq), "a%04u", idata->seqno++);  if (idata->seqno > 9999)    idata->seqno = 0;  cmd->state = IMAP_CMD_NEW;  return cmd;}/* parse response line for tagged OK/NO/BAD */static int cmd_status (const char *s){  s = imap_next_word((char*)s);    if (!ascii_strncasecmp("OK", s, 2))    return IMAP_CMD_OK;  if (!ascii_strncasecmp("NO", s, 2))    return IMAP_CMD_NO;  return IMAP_CMD_BAD;}/* cmd_handle_fatal: when IMAP_DATA is in fatal state, do what we can */static void cmd_handle_fatal (IMAP_DATA* idata){  idata->status = IMAP_FATAL;  if ((idata->state >= IMAP_SELECTED) &&      (idata->reopen & IMAP_REOPEN_ALLOW))  {    mx_fastclose_mailbox (idata->ctx);    mutt_error (_("Mailbox closed"));    mutt_sleep (1);    idata->state = IMAP_DISCONNECTED;  }  if (idata->state < IMAP_SELECTED)  {    idata->state = IMAP_DISCONNECTED;    mutt_socket_close (idata->conn);    idata->status = 0;  }}/* cmd_handle_untagged: fallback parser for otherwise unhandled messages. */static int cmd_handle_untagged (IMAP_DATA* idata){  char* s;  char* pn;  int count;  s = imap_next_word (idata->buf);  if ((idata->state >= IMAP_SELECTED) && isdigit ((unsigned char) *s))  {    pn = s;    s = imap_next_word (s);    /* EXISTS and EXPUNGE are always related to the SELECTED mailbox for the     * connection, so update that one.     */    if (ascii_strncasecmp ("EXISTS", s, 6) == 0)    {      dprint (2, (debugfile, "Handling EXISTS\n"));      /* new mail arrived */      count = atoi (pn);      if ( !(idata->reopen & IMAP_EXPUNGE_PENDING) &&	   count < idata->ctx->msgcount)      {	/* something is wrong because the server reported fewer messages	 * than we previously saw	 */	mutt_error _("Fatal error.  Message count is out of sync!");	idata->status = IMAP_FATAL;	return -1;      }      /* at least the InterChange server sends EXISTS messages freely,       * even when there is no new mail */      else if (count == idata->ctx->msgcount)	dprint (3, (debugfile,          "cmd_handle_untagged: superfluous EXISTS message.\n"));      else      {	if (!(idata->reopen & IMAP_EXPUNGE_PENDING))        {          dprint (2, (debugfile,            "cmd_handle_untagged: New mail in %s - %d messages total.\n",            idata->mailbox, count));	  idata->reopen |= IMAP_NEWMAIL_PENDING;        }	idata->newMailCount = count;      }    }    /* pn vs. s: need initial seqno */    else if (ascii_strncasecmp ("EXPUNGE", s, 7) == 0)      cmd_parse_expunge (idata, pn);    else if (ascii_strncasecmp ("FETCH", s, 5) == 0)      cmd_parse_fetch (idata, pn);  }  else if (ascii_strncasecmp ("CAPABILITY", s, 10) == 0)    cmd_parse_capability (idata, s);  else if (!ascii_strncasecmp ("OK [CAPABILITY", s, 14))    cmd_parse_capability (idata, imap_next_word (s));  else if (ascii_strncasecmp ("LIST", s, 4) == 0)    cmd_parse_list (idata, s);  else if (ascii_strncasecmp ("LSUB", s, 4) == 0)    cmd_parse_lsub (idata, s);  else if (ascii_strncasecmp ("MYRIGHTS", s, 8) == 0)    cmd_parse_myrights (idata, s);  else if (ascii_strncasecmp ("SEARCH", s, 6) == 0)    cmd_parse_search (idata, s);  else if (ascii_strncasecmp ("STATUS", s, 6) == 0)    cmd_parse_status (idata, s);  else if (ascii_strncasecmp ("BYE", s, 3) == 0)  {    dprint (2, (debugfile, "Handling BYE\n"));    /* check if we're logging out */    if (idata->status == IMAP_BYE)      return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -