示例#1
0
文件: crypt.c 项目: darnir/neomutt
/**
 * crypt_query - Check out the type of encryption used
 * @param m Body of email
 * @retval num Flags, see #SecurityFlags
 * @retval 0   Error (#SEC_NO_FLAGS)
 *
 * Set the cached status values if there are any.
 */
SecurityFlags crypt_query(struct Body *m)
{
  if (!WithCrypto || !m)
    return SEC_NO_FLAGS;

  SecurityFlags rc = SEC_NO_FLAGS;

  if (m->type == TYPE_APPLICATION)
  {
    if (WithCrypto & APPLICATION_PGP)
      rc |= mutt_is_application_pgp(m);

    if (WithCrypto & APPLICATION_SMIME)
    {
      rc |= mutt_is_application_smime(m);
      if (rc && m->goodsig)
        rc |= SEC_GOODSIGN;
      if (rc && m->badsig)
        rc |= SEC_BADSIGN;
    }
  }
  else if (((WithCrypto & APPLICATION_PGP) != 0) && (m->type == TYPE_TEXT))
  {
    rc |= mutt_is_application_pgp(m);
    if (rc && m->goodsig)
      rc |= SEC_GOODSIGN;
  }

  if (m->type == TYPE_MULTIPART)
  {
    rc |= mutt_is_multipart_encrypted(m);
    rc |= mutt_is_multipart_signed(m);
    rc |= mutt_is_malformed_multipart_pgp_encrypted(m);

    if (rc && m->goodsig)
      rc |= SEC_GOODSIGN;
  }

  if ((m->type == TYPE_MULTIPART) || (m->type == TYPE_MESSAGE))
  {
    SecurityFlags u = m->parts ? SEC_ALL_FLAGS : 0; /* Bits set in all parts */
    SecurityFlags w = SEC_NO_FLAGS;                 /* Bits set in any part  */

    for (struct Body *b = m->parts; b; b = b->next)
    {
      const SecurityFlags v = crypt_query(b);
      u &= v;
      w |= v;
    }
    rc |= u | (w & ~SEC_GOODSIGN);

    if ((w & SEC_GOODSIGN) && !(u & SEC_GOODSIGN))
      rc |= SEC_PARTSIGN;
  }

  return rc;
}
示例#2
0
文件: message.c 项目: aschrab/mutt
int imap_fetch_message (CONTEXT *ctx, MESSAGE *msg, int msgno)
{
  IMAP_DATA* idata;
  HEADER* h;
  ENVELOPE* newenv;
  char buf[LONG_STRING];
  char path[_POSIX_PATH_MAX];
  char *pc;
  long bytes;
  progress_t progressbar;
  int uid;
  int cacheno;
  IMAP_CACHE *cache;
  int read;
  int rc;
  /* Sam's weird courier server returns an OK response even when FETCH
   * fails. Thanks Sam. */
  short fetched = 0;

  idata = (IMAP_DATA*) ctx->data;
  h = ctx->hdrs[msgno];

  if ((msg->fp = msg_cache_get (idata, h)))
  {
    if (HEADER_DATA(h)->parsed)
      return 0;
    else
      goto parsemsg;
  }

  /* we still do some caching even if imap_cachedir is unset */
  /* see if we already have the message in our cache */
  cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
  cache = &idata->cache[cacheno];

  if (cache->path)
  {
    /* don't treat cache errors as fatal, just fall back. */
    if (cache->uid == HEADER_DATA(h)->uid &&
        (msg->fp = fopen (cache->path, "r")))
      return 0;
    else
    {
      unlink (cache->path);
      FREE (&cache->path);
    }
  }

  if (!isendwin())
    mutt_message _("Fetching message...");

  if (!(msg->fp = msg_cache_put (idata, h)))
  {
    cache->uid = HEADER_DATA(h)->uid;
    mutt_mktemp (path, sizeof (path));
    cache->path = safe_strdup (path);
    if (!(msg->fp = safe_fopen (path, "w+")))
    {
      FREE (&cache->path);
      return -1;
    }
  }

  /* mark this header as currently inactive so the command handler won't
   * also try to update it. HACK until all this code can be moved into the
   * command handler */
  h->active = 0;

  snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid,
	    (mutt_bit_isset (idata->capabilities, IMAP4REV1) ?
	     (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") :
	     "RFC822"));

  imap_cmd_start (idata, buf);
  do
  {
    if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
      break;

    pc = idata->buf;
    pc = imap_next_word (pc);
    pc = imap_next_word (pc);

    if (!ascii_strncasecmp ("FETCH", pc, 5))
    {
      while (*pc)
      {
	pc = imap_next_word (pc);
	if (pc[0] == '(')
	  pc++;
	if (ascii_strncasecmp ("UID", pc, 3) == 0)
	{
	  pc = imap_next_word (pc);
	  uid = atoi (pc);
	  if (uid != HEADER_DATA(h)->uid)
	    mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
	}
	else if ((ascii_strncasecmp ("RFC822", pc, 6) == 0) ||
		 (ascii_strncasecmp ("BODY[]", pc, 6) == 0))
	{
	  pc = imap_next_word (pc);
	  if (imap_get_literal_count(pc, &bytes) < 0)
	  {
	    imap_error ("imap_fetch_message()", buf);
	    goto bail;
	  }
	  mutt_progress_init (&progressbar, _("Fetching message..."),
			      MUTT_PROGRESS_SIZE, NetInc, bytes);
	  if (imap_read_literal (msg->fp, idata, bytes, &progressbar) < 0)
	    goto bail;
	  /* pick up trailing line */
	  if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
	    goto bail;
	  pc = idata->buf;

	  fetched = 1;
	}
	/* UW-IMAP will provide a FLAGS update here if the FETCH causes a
	 * change (eg from \Unseen to \Seen).
	 * Uncommitted changes in mutt take precedence. If we decide to
	 * incrementally update flags later, this won't stop us syncing */
	else if ((ascii_strncasecmp ("FLAGS", pc, 5) == 0) && !h->changed)
	{
	  if ((pc = imap_set_flags (idata, h, pc)) == NULL)
	    goto bail;
	}
      }
    }
  }
  while (rc == IMAP_CMD_CONTINUE);

  /* see comment before command start. */
  h->active = 1;

  fflush (msg->fp);
  if (ferror (msg->fp))
  {
    mutt_perror (cache->path);
    goto bail;
  }

  if (rc != IMAP_CMD_OK)
    goto bail;

  if (!fetched || !imap_code (idata->buf))
    goto bail;

  msg_cache_commit (idata, h);

  parsemsg:
  /* Update the header information.  Previously, we only downloaded a
   * portion of the headers, those required for the main display.
   */
  rewind (msg->fp);
  /* It may be that the Status header indicates a message is read, but the
   * IMAP server doesn't know the message has been \Seen. So we capture
   * the server's notion of 'read' and if it differs from the message info
   * picked up in mutt_read_rfc822_header, we mark the message (and context
   * changed). Another possibility: ignore Status on IMAP?*/
  read = h->read;
  newenv = mutt_read_rfc822_header (msg->fp, h, 0, 0);
  mutt_merge_envelopes(h->env, &newenv);

  /* see above. We want the new status in h->read, so we unset it manually
   * and let mutt_set_flag set it correctly, updating context. */
  if (read != h->read)
  {
    h->read = read;
    mutt_set_flag (ctx, h, MUTT_NEW, read);
  }

  h->lines = 0;
  fgets (buf, sizeof (buf), msg->fp);
  while (!feof (msg->fp))
  {
    h->lines++;
    fgets (buf, sizeof (buf), msg->fp);
  }

  h->content->length = ftell (msg->fp) - h->content->offset;

  /* This needs to be done in case this is a multipart message */
#if defined(HAVE_PGP) || defined(HAVE_SMIME)
  h->security = crypt_query (h->content);
#endif

  mutt_clear_error();
  rewind (msg->fp);
  HEADER_DATA(h)->parsed = 1;

  return 0;

bail:
  safe_fclose (&msg->fp);
  imap_cache_del (idata, h);
  if (cache->path)
  {
    unlink (cache->path);
    FREE (&cache->path);
  }

  return -1;
}
示例#3
0
int mutt_display_message (HEADER *cur)
{
  char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING];
  int rc = 0, builtin = 0;
  int cmflags = M_CM_DECODE | M_CM_DISPLAY | M_CM_CHARCONV;
  FILE *fpout = NULL;
  FILE *fpfilterout = NULL;
  pid_t filterpid = -1;
  int res;

  snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content),
	    cur->content->subtype);

  mutt_parse_mime_message (Context, cur);
  mutt_message_hook (Context, cur, M_MESSAGEHOOK);

  /* see if crypto is needed for this message.  if so, we should exit curses */
  if (WithCrypto && cur->security)
  {
    if (cur->security & ENCRYPT)
    {
      if (cur->security & APPLICATION_SMIME)
	crypt_smime_getkeys (cur->env);
      if(!crypt_valid_passphrase(cur->security))
	return 0;

      cmflags |= M_CM_VERIFY;
    }
    else if (cur->security & SIGN)
    {
      /* find out whether or not the verify signature */
      if (query_quadoption (OPT_VERIFYSIG, _("Verify PGP signature?")) == M_YES)
      {
	cmflags |= M_CM_VERIFY;
      }
    }
  }
  
  if (cmflags & M_CM_VERIFY || cur->security & ENCRYPT)
  {
    if (cur->security & APPLICATION_PGP)
    {
      if (cur->env->from)
        crypt_pgp_invoke_getkeys (cur->env->from);
      
      crypt_invoke_message (APPLICATION_PGP);
    }

    if (cur->security & APPLICATION_SMIME)
      crypt_invoke_message (APPLICATION_SMIME);
  }


  mutt_mktemp (tempfile, sizeof (tempfile));
  if ((fpout = safe_fopen (tempfile, "w")) == NULL)
  {
    mutt_error _("Could not create temporary file!");
    return (0);
  }

  if (DisplayFilter && *DisplayFilter) 
  {
    fpfilterout = fpout;
    fpout = NULL;
    /* mutt_endwin (NULL); */
    filterpid = mutt_create_filter_fd (DisplayFilter, &fpout, NULL, NULL,
				       -1, fileno(fpfilterout), -1);
    if (filterpid < 0)
    {
      mutt_error (_("Cannot create display filter"));
      safe_fclose (&fpfilterout);
      unlink (tempfile);
      return 0;
    }
  }

  if (!Pager || mutt_strcmp (Pager, "builtin") == 0)
    builtin = 1;
  else
  {
    struct hdr_format_info hfi;
    hfi.ctx = Context;
    hfi.pager_progress = ExtPagerProgress;
    hfi.hdr = cur;
    mutt_make_string_info (buf, sizeof (buf), NONULL(PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
    fputs (buf, fpout);
    fputs ("\n\n", fpout);
  }

  res = mutt_copy_message (fpout, Context, cur, cmflags,
       	(option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY);
  if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0)
  {
    mutt_error (_("Could not copy message"));
    if (fpfilterout != NULL)
    {
      mutt_wait_filter (filterpid);
      safe_fclose (&fpfilterout);
    }
    mutt_unlink (tempfile);
    return 0;
  }

  if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0)
    mutt_any_key_to_continue (NULL);

  safe_fclose (&fpfilterout);	/* XXX - check result? */

  
  if (WithCrypto)
  {
    /* update crypto information for this message */
    cur->security &= ~(GOODSIGN|BADSIGN);
    cur->security |= crypt_query (cur->content);
  
    /* Remove color cache for this message, in case there
       are color patterns for both ~g and ~V */
    cur->pair = 0;
  }

  if (builtin)
  {
    pager_t info;

    if (WithCrypto 
        && (cur->security & APPLICATION_SMIME) && (cmflags & M_CM_VERIFY))
    {
      if (cur->security & GOODSIGN)
      {
	if (!crypt_smime_verify_sender(cur))
	  mutt_message ( _("S/MIME signature successfully verified."));
	else
	  mutt_error ( _("S/MIME certificate owner does not match sender."));
      }
      else if (cur->security & PARTSIGN)
	mutt_message (_("Warning: Part of this message has not been signed."));
      else if (cur->security & SIGN || cur->security & BADSIGN)
	mutt_error ( _("S/MIME signature could NOT be verified."));
    }

    if (WithCrypto 
        && (cur->security & APPLICATION_PGP) && (cmflags & M_CM_VERIFY))
    {
      if (cur->security & GOODSIGN)
	mutt_message (_("PGP signature successfully verified."));
      else if (cur->security & PARTSIGN)
	mutt_message (_("Warning: Part of this message has not been signed."));
      else if (cur->security & SIGN)
	mutt_message (_("PGP signature could NOT be verified."));
    }

    /* Invoke the builtin pager */
    memset (&info, 0, sizeof (pager_t));
    info.hdr = cur;
    info.ctx = Context;
    rc = mutt_pager (NULL, tempfile, M_PAGER_MESSAGE, &info);
  }
  else
  {
    int r;

    mutt_endwin (NULL);
    snprintf (buf, sizeof (buf), "%s %s", NONULL(Pager), tempfile);
    if ((r = mutt_system (buf)) == -1)
      mutt_error (_("Error running \"%s\"!"), buf);
    unlink (tempfile);
    if (!option (OPTNOCURSES))
      keypad (stdscr, TRUE);
    if (r != -1)
      mutt_set_flag (Context, cur, M_READ, 1);
    if (r != -1 && option (OPTPROMPTAFTER))
    {
      mutt_unget_event (mutt_any_key_to_continue _("Command: "), 0);
      rc = km_dokey (MENU_PAGER);
    }
    else
      rc = 0;
  }

  return rc;
}
示例#4
0
文件: pop.cpp 项目: badeip/neomutt
/* fetch message from POP server */
int pop_fetch_message(MESSAGE *msg, CONTEXT *ctx, int msgno)
{
    int ret;
    void *uidl;
    char buf[LONG_STRING];
    char path[_POSIX_PATH_MAX];
    progress_t progressbar;
    POP_DATA *pop_data = (POP_DATA *)ctx->data;
    POP_CACHE *cache;
    HEADER *h = ctx->hdrs[msgno];
    unsigned short bcache = 1;

    /* see if we already have the message in body cache */
    if ((msg->fp = mutt_bcache_get(pop_data->bcache, h->data)))
        return 0;

    /*
     * see if we already have the message in our cache in
     * case $message_cachedir is unset
     */
    cache = &pop_data->cache[h->index % POP_CACHE_LEN];

    if (cache->path) {
        if (cache->index == h->index) {
            /* yes, so just return a pointer to the message */
            msg->fp = fopen(cache->path, "r");

            if (msg->fp)
                return 0;

            mutt_perror(cache->path);
            mutt_sleep(2);
            return -1;
        } else {
            /* clear the previous entry */
            unlink(cache->path);
            safe_free(&cache->path);
        }
    }

    FOREVER
    {
        if (pop_reconnect(ctx) < 0)
            return -1;

        /* verify that massage index is correct */
        if (h->refno < 0) {
            mutt_error _(
                "The message index is incorrect. Try reopening the mailbox.");
            mutt_sleep(2);
            return -1;
        }

        mutt_progress_init(&progressbar, _(
                               "Fetching message..."),
                           M_PROGRESS_SIZE, NetInc,
                           h->content->length + h->content->offset - 1);

        /* see if we can put in body cache; use our cache as fallback */
        if (!(msg->fp = mutt_bcache_put(pop_data->bcache, h->data, 1))) {
            /* no */
            bcache = 0;
            mutt_mktemp(path, sizeof(path));

            if (!(msg->fp = safe_fopen(path, "w+"))) {
                mutt_perror(path);
                mutt_sleep(2);
                return -1;
            }
        }

        snprintf(buf, sizeof(buf), "RETR %d\r\n", h->refno);

        ret =
            pop_fetch_data(pop_data, buf, &progressbar, fetch_message, msg->fp);

        if (ret == 0)
            break;

        safe_fclose(&msg->fp);

        /* if RETR failed (e.g. connection closed), be sure to remove either
         * the file in bcache or from POP's own cache since the next iteration
         * of the loop will re-attempt to put() the message */
        if (!bcache)
            unlink(path);

        if (ret == -2) {
            mutt_error("%s", pop_data->err_msg);
            mutt_sleep(2);
            return -1;
        }

        if (ret == -3) {
            mutt_error _("Can't write message to temporary file!");
            mutt_sleep(2);
            return -1;
        }
    }

    /* Update the header information.  Previously, we only downloaded a
     * portion of the headers, those required for the main display.
     */
    if (bcache)
        mutt_bcache_commit(pop_data->bcache, h->data);
    else {
        cache->index = h->index;
        cache->path = safe_strdup(path);
    }
    rewind(msg->fp);
    uidl = h->data;

    /* we replace envelop, key in subj_hash has to be updated as well */
    if (ctx->subj_hash
        && h->env->real_subj)
        hash_delete(ctx->subj_hash, h->env->real_subj, h, NULL);
    mutt_free_envelope(&h->env);
    h->env = mutt_read_rfc822_header(msg->fp, h, 0, 0);

    if (ctx->subj_hash
        && h->env->real_subj)
        hash_insert(ctx->subj_hash, h->env->real_subj, h, 1);

    h->data = uidl;
    h->lines = 0;
    fgets(buf, sizeof(buf), msg->fp);

    while (!feof(msg->fp)) {
        ctx->hdrs[msgno]->lines++;
        fgets(buf, sizeof(buf), msg->fp);
    }

    h->content->length = ftello(msg->fp) - h->content->offset;

    /* This needs to be done in case this is a multipart message */
    if (!WithCrypto)
        h->security = crypt_query(h->content);

    mutt_clear_error();
    rewind(msg->fp);

    return 0;
}