Example #1
0
File: mbox.c Project: kdave/neomutt
/**
 * mbox_mbox_open - Implements MxOps::mbox_open()
 */
static int mbox_mbox_open(struct Mailbox *m)
{
  if (init_mailbox(m) != 0)
    return -1;

  struct MboxAccountData *adata = mbox_adata_get(m);
  if (!adata)
    return -1;

  adata->fp = fopen(m->path, "r+");
  if (!adata->fp)
  {
    mutt_perror(m->path);
    return -1;
  }
  mutt_sig_block();
  if (mbox_lock_mailbox(m, false, true) == -1)
  {
    mutt_sig_unblock();
    return -1;
  }

  int rc;
  if (m->magic == MUTT_MBOX)
    rc = mbox_parse_mailbox(m);
  else if (m->magic == MUTT_MMDF)
    rc = mmdf_parse_mailbox(m);
  else
    rc = -1;
  mutt_file_touch_atime(fileno(adata->fp));

  mbox_unlock_mailbox(m);
  mutt_sig_unblock();
  return rc;
}
Example #2
0
/* open a mbox or mmdf style mailbox */
int mbox_open_mailbox(CONTEXT *ctx)
{
    int rc;

    if ((ctx->fp = fopen(ctx->path, "r")) == NULL) {
        mutt_perror(ctx->path);
        return -1;
    }
    mutt_block_signals();

    if (mbox_lock_mailbox(ctx, 0, 1) == -1) {
        mutt_unblock_signals();
        return -1;
    }

    if (ctx->magic == M_MBOX)
        rc = mbox_parse_mailbox(ctx);
    else if (ctx->magic == M_MMDF)
        rc = mmdf_parse_mailbox(ctx);
    else
        rc = -1;

    mbox_unlock_mailbox(ctx);
    mutt_unblock_signals();
    return rc;
}
Example #3
0
File: mbox.c Project: kdave/neomutt
/**
 * mbox_mbox_check - Implements MxOps::mbox_check()
 * @param[in]  m          Mailbox
 * @param[out] index_hint Keep track of current index selection
 * @retval #MUTT_REOPENED  Mailbox has been reopened
 * @retval #MUTT_NEW_MAIL  New mail has arrived
 * @retval #MUTT_LOCKED    Couldn't lock the file
 * @retval 0               No change
 * @retval -1              Error
 */
static int mbox_mbox_check(struct Mailbox *m, int *index_hint)
{
  if (!m)
    return -1;

  struct MboxAccountData *adata = mbox_adata_get(m);
  if (!adata)
    return -1;

  if (!adata->fp)
  {
    if (mbox_mbox_open(m) < 0)
      return -1;
    mutt_mailbox_changed(m, MBN_INVALID);
  }

  struct stat st;
  bool unlock = false;
  bool modified = false;

  if (stat(m->path, &st) == 0)
  {
    if ((mutt_file_stat_timespec_compare(&st, MUTT_STAT_MTIME, &m->mtime) == 0) &&
        (st.st_size == m->size))
    {
      return 0;
    }

    if (st.st_size == m->size)
    {
      /* the file was touched, but it is still the same length, so just exit */
      mutt_file_get_stat_timespec(&m->mtime, &st, MUTT_STAT_MTIME);
      return 0;
    }

    if (st.st_size > m->size)
    {
      /* lock the file if it isn't already */
      if (!adata->locked)
      {
        mutt_sig_block();
        if (mbox_lock_mailbox(m, false, false) == -1)
        {
          mutt_sig_unblock();
          /* we couldn't lock the mailbox, but nothing serious happened:
           * probably the new mail arrived: no reason to wait till we can
           * parse it: we'll get it on the next pass */
          return MUTT_LOCKED;
        }
        unlock = 1;
      }

      /* Check to make sure that the only change to the mailbox is that
       * message(s) were appended to this file.  My heuristic is that we should
       * see the message separator at *exactly* what used to be the end of the
       * folder.  */
      char buf[1024];
      if (fseeko(adata->fp, m->size, SEEK_SET) != 0)
        mutt_debug(LL_DEBUG1, "#1 fseek() failed\n");
      if (fgets(buf, sizeof(buf), adata->fp))
      {
        if (((m->magic == MUTT_MBOX) && mutt_str_startswith(buf, "From ", CASE_MATCH)) ||
            ((m->magic == MUTT_MMDF) && (mutt_str_strcmp(buf, MMDF_SEP) == 0)))
        {
          if (fseeko(adata->fp, m->size, SEEK_SET) != 0)
            mutt_debug(LL_DEBUG1, "#2 fseek() failed\n");

          int old_msg_count = m->msg_count;
          if (m->magic == MUTT_MBOX)
            mbox_parse_mailbox(m);
          else
            mmdf_parse_mailbox(m);

          if (m->msg_count > old_msg_count)
            mutt_mailbox_changed(m, MBN_INVALID);

          /* Only unlock the folder if it was locked inside of this routine.
           * It may have been locked elsewhere, like in
           * mutt_checkpoint_mailbox().  */
          if (unlock)
          {
            mbox_unlock_mailbox(m);
            mutt_sig_unblock();
          }

          return MUTT_NEW_MAIL; /* signal that new mail arrived */
        }
        else
          modified = true;
      }
      else
      {
        mutt_debug(LL_DEBUG1, "fgets returned NULL\n");
        modified = true;
      }
    }
    else
      modified = true;
  }

  if (modified)
  {
    if (reopen_mailbox(m, index_hint) != -1)
    {
      mutt_mailbox_changed(m, MBN_INVALID);
      if (unlock)
      {
        mbox_unlock_mailbox(m);
        mutt_sig_unblock();
      }
      return MUTT_REOPENED;
    }
  }

  /* fatal error */

  mbox_unlock_mailbox(m);
  mx_fastclose_mailbox(m);
  mutt_sig_unblock();
  mutt_error(_("Mailbox was corrupted"));
  return -1;
}
Example #4
0
File: mbox.c Project: kdave/neomutt
/**
 * reopen_mailbox - Close and reopen a mailbox
 * @param m          Mailbox
 * @param index_hint Current email
 * @retval >0 Success, e.g. #MUTT_REOPENED, #MUTT_NEW_MAIL
 * @retval -1 Error
 */
static int reopen_mailbox(struct Mailbox *m, int *index_hint)
{
  if (!m)
    return -1;

  struct MboxAccountData *adata = mbox_adata_get(m);
  if (!adata)
    return -1;

  bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
  struct Email **old_hdrs = NULL;
  int old_msg_count;
  bool msg_mod = false;
  int rc = -1;

  /* silent operations */
  m->quiet = true;

  if (!m->quiet)
    mutt_message(_("Reopening mailbox..."));

  /* our heuristics require the old mailbox to be unsorted */
  if (C_Sort != SORT_ORDER)
  {
    short old_sort = C_Sort;
    C_Sort = SORT_ORDER;
    mutt_mailbox_changed(m, MBN_RESORT);
    C_Sort = old_sort;
  }

  old_hdrs = NULL;
  old_msg_count = 0;

  /* simulate a close */
  mutt_mailbox_changed(m, MBN_CLOSED);
  mutt_hash_free(&m->id_hash);
  mutt_hash_free(&m->subj_hash);
  mutt_hash_free(&m->label_hash);
  FREE(&m->v2r);
  if (m->readonly)
  {
    for (int i = 0; i < m->msg_count; i++)
      mutt_email_free(&(m->emails[i])); /* nothing to do! */
    FREE(&m->emails);
  }
  else
  {
    /* save the old headers */
    old_msg_count = m->msg_count;
    old_hdrs = m->emails;
    m->emails = NULL;
  }

  m->email_max = 0; /* force allocation of new headers */
  m->msg_count = 0;
  m->vcount = 0;
  m->msg_tagged = 0;
  m->msg_deleted = 0;
  m->msg_new = 0;
  m->msg_unread = 0;
  m->msg_flagged = 0;
  m->changed = false;
  m->id_hash = NULL;
  m->subj_hash = NULL;
  mutt_make_label_hash(m);

  switch (m->magic)
  {
    case MUTT_MBOX:
    case MUTT_MMDF:
      cmp_headers = mutt_email_cmp_strict;
      mutt_file_fclose(&adata->fp);
      adata->fp = mutt_file_fopen(m->path, "r");
      if (!adata->fp)
        rc = -1;
      else if (m->magic == MUTT_MBOX)
        rc = mbox_parse_mailbox(m);
      else
        rc = mmdf_parse_mailbox(m);
      break;

    default:
      rc = -1;
      break;
  }

  if (rc == -1)
  {
    /* free the old headers */
    for (int i = 0; i < old_msg_count; i++)
      mutt_email_free(&(old_hdrs[i]));
    FREE(&old_hdrs);

    m->quiet = false;
    return -1;
  }

  mutt_file_touch_atime(fileno(adata->fp));

  /* now try to recover the old flags */

  if (!m->readonly)
  {
    for (int i = 0; i < m->msg_count; i++)
    {
      bool found = false;

      /* some messages have been deleted, and new  messages have been
       * appended at the end; the heuristic is that old messages have then
       * "advanced" towards the beginning of the folder, so we begin the
       * search at index "i" */
      int j;
      for (j = i; j < old_msg_count; j++)
      {
        if (!old_hdrs[j])
          continue;
        if (cmp_headers(m->emails[i], old_hdrs[j]))
        {
          found = true;
          break;
        }
      }
      if (!found)
      {
        for (j = 0; (j < i) && (j < old_msg_count); j++)
        {
          if (!old_hdrs[j])
            continue;
          if (cmp_headers(m->emails[i], old_hdrs[j]))
          {
            found = true;
            break;
          }
        }
      }

      if (found)
      {
        /* this is best done here */
        if (index_hint && (*index_hint == j))
          *index_hint = i;

        if (old_hdrs[j]->changed)
        {
          /* Only update the flags if the old header was changed;
           * otherwise, the header may have been modified externally,
           * and we don't want to lose _those_ changes */
          mutt_set_flag(m, m->emails[i], MUTT_FLAG, old_hdrs[j]->flagged);
          mutt_set_flag(m, m->emails[i], MUTT_REPLIED, old_hdrs[j]->replied);
          mutt_set_flag(m, m->emails[i], MUTT_OLD, old_hdrs[j]->old);
          mutt_set_flag(m, m->emails[i], MUTT_READ, old_hdrs[j]->read);
        }
        mutt_set_flag(m, m->emails[i], MUTT_DELETE, old_hdrs[j]->deleted);
        mutt_set_flag(m, m->emails[i], MUTT_PURGE, old_hdrs[j]->purge);
        mutt_set_flag(m, m->emails[i], MUTT_TAG, old_hdrs[j]->tagged);

        /* we don't need this header any more */
        mutt_email_free(&(old_hdrs[j]));
      }
    }

    /* free the remaining old headers */
    for (int j = 0; j < old_msg_count; j++)
    {
      if (old_hdrs[j])
      {
        mutt_email_free(&(old_hdrs[j]));
        msg_mod = true;
      }
    }
    FREE(&old_hdrs);
  }

  m->quiet = false;

  return (m->changed || msg_mod) ? MUTT_REOPENED : MUTT_NEW_MAIL;
}
Example #5
0
/* check to see if the mailbox has changed on disk.
 *
 * return values:
 *	M_REOPENED	mailbox has been reopened
 *	M_NEW_MAIL	new mail has arrived!
 *	M_LOCKED	couldn't lock the file
 *	0		no change
 *	-1		error
 */
int mbox_check_mailbox(CONTEXT *ctx, int *index_hint)
{
    struct stat st;
    char buffer[LONG_STRING];
    int unlock = 0;
    int modified = 0;

    if (stat(ctx->path, &st) == 0) {
        if ((st.st_mtime == ctx->mtime)
            && (st.st_size == ctx->size))
            return 0;

        if (st.st_size == ctx->size) {
            /* the file was touched, but it is still the same length, so just
               exit */
            ctx->mtime = st.st_mtime;
            return 0;
        }

        if (st.st_size > ctx->size) {
            /* lock the file if it isn't already */
            if (!ctx->locked) {
                mutt_block_signals();

                if (mbox_lock_mailbox(ctx, 0, 0) == -1) {
                    mutt_unblock_signals();

                    /* we couldn't lock the mailbox, but nothing serious
                       happened:
                     * probably the new mail arrived: no reason to wait till we
                     *can
                     * parse it: we'll get it on the next pass
                     */
                    return M_LOCKED;
                }
                unlock = 1;
            }

            /*
             * Check to make sure that the only change to the mailbox is that
             * message(s) were appended to this file.  My heuristic is that we
             *should
             * see the message separator at *exactly* what used to be the end of
             *the
             * folder.
             */
            if (fseeko(ctx->fp, ctx->size, SEEK_SET) != 0)
                dprint(1, "mbox_check_mailbox: fseek() failed\n");

            if (fgets(buffer, sizeof(buffer), ctx->fp) != NULL) {
                if (((ctx->magic == M_MBOX)
                     && (mutt_strncmp("From ", buffer, 5) == 0))
                    || ((ctx->magic == M_MMDF)
                        && (mutt_strcmp(MMDF_SEP, buffer) == 0))) {
                    if (fseeko(ctx->fp, ctx->size, SEEK_SET) != 0)
                        dprint(1, "mbox_check_mailbox: fseek() failed\n");

                    if (ctx->magic == M_MBOX)
                        mbox_parse_mailbox(ctx);
                    else
                        mmdf_parse_mailbox(ctx);

                    /* Only unlock the folder if it was locked inside of this
                       routine.
                     * It may have been locked elsewhere, like in
                     * mutt_checkpoint_mailbox().
                     */

                    if (unlock) {
                        mbox_unlock_mailbox(ctx);
                        mutt_unblock_signals();
                    }

                    return M_NEW_MAIL; /* signal that new mail arrived */
                } else
                    modified = 1;
            } else {
                dprint(1, "mbox_check_mailbox: fgets returned NULL.\n");
                modified = 1;
            }
        } else
            modified = 1;
    }

    if (modified) {
        if (mutt_reopen_mailbox(ctx, index_hint) != -1) {
            if (unlock) {
                mbox_unlock_mailbox(ctx);
                mutt_unblock_signals();
            }
            return M_REOPENED;
        }
    }

    /* fatal error */

    mbox_unlock_mailbox(ctx);
    mx_fastclose_mailbox(ctx);
    mutt_unblock_signals();
    mutt_error _("Mailbox was corrupted!");
    return -1;
}