コード例 #1
0
ファイル: pop_lib.c プロジェクト: 2ion/mutt-1.5.22
/*
 * This function calls  funct(*line, *data)  for each received line,
 * funct(NULL, *data)  if  rewind(*data)  needs, exits when fail or done.
 * Returned codes:
 *  0 - successful,
 * -1 - connection lost,
 * -2 - invalid command or execution error,
 * -3 - error in funct(*line, *data)
 */
int pop_fetch_data (POP_DATA *pop_data, char *query, progress_t *progressbar,
		    int (*funct) (char *, void *), void *data)
{
  char buf[LONG_STRING];
  char *inbuf;
  char *p;
  int ret, chunk = 0;
  long pos = 0;
  size_t lenbuf = 0;

  strfcpy (buf, query, sizeof (buf));
  ret = pop_query (pop_data, buf, sizeof (buf));
  if (ret < 0)
    return ret;

  inbuf = safe_malloc (sizeof (buf));

  FOREVER
  {
    chunk = mutt_socket_readln_d (buf, sizeof (buf), pop_data->conn, M_SOCK_LOG_HDR);
    if (chunk < 0)
    {
      pop_data->status = POP_DISCONNECTED;
      ret = -1;
      break;
    }

    p = buf;
    if (!lenbuf && buf[0] == '.')
    {
      if (buf[1] != '.')
	break;
      p++;
    }

    strfcpy (inbuf + lenbuf, p, sizeof (buf));
    pos += chunk;

    /* cast is safe since we break out of the loop when chunk<=0 */
    if ((size_t)chunk >= sizeof (buf))
    {
      lenbuf += strlen (p);
    }
    else
    {
      if (progressbar)
	mutt_progress_update (progressbar, pos, -1);
      if (ret == 0 && funct (inbuf, data) < 0)
	ret = -3;
      lenbuf = 0;
    }

    safe_realloc (&inbuf, lenbuf + sizeof (buf));
  }

  FREE (&inbuf);
  return ret;
}
コード例 #2
0
ファイル: pop.cpp プロジェクト: badeip/neomutt
/* update POP mailbox - delete messages from server */
int pop_sync_mailbox(CONTEXT *ctx, int *index_hint)
{
    int i, j, ret = 0;
    char buf[LONG_STRING];
    POP_DATA *pop_data = (POP_DATA *)ctx->data;
    progress_t progress;

    pop_data->check_time = 0;

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

        mutt_progress_init(&progress, _("Marking messages deleted..."),
                           M_PROGRESS_MSG, WriteInc, ctx->deleted);

        for (i = 0, j = 0, ret = 0; ret == 0
             && i < ctx->msgcount; i++) {
            if (ctx->hdrs[i]->deleted
                && (ctx->hdrs[i]->refno != -1)) {
                j++;

                if (!ctx->quiet)
                    mutt_progress_update(&progress, j, -1);
                snprintf(buf, sizeof(buf), "DELE %d\r\n", ctx->hdrs[i]->refno);

                if ((ret = pop_query(pop_data, buf, sizeof(buf))) == 0) {
                    mutt_bcache_del(pop_data->bcache, ctx->hdrs[i]->data);
                }
            }

        }

        if (ret == 0) {
            strfcpy(buf, "QUIT\r\n", sizeof(buf));
            ret = pop_query(pop_data, buf, sizeof(buf));
        }

        if (ret == 0) {
            pop_data->clear_cache = 1;
            pop_clear_cache(pop_data);
            pop_data->status = POP_DISCONNECTED;
            return 0;
        }

        if (ret == -2) {
            mutt_error("%s", pop_data->err_msg);
            mutt_sleep(2);
            return -1;
        }
    }
}
コード例 #3
0
ファイル: progress.c プロジェクト: darnir/neomutt
/**
 * mutt_progress_init - Set up a progress bar
 * @param progress Progress bar
 * @param msg      Message to display
 * @param flags    Flags, e.g. #MUTT_PROGRESS_SIZE
 * @param inc      Increments to display (0 disables updates)
 * @param size     Total size of expected file / traffic
 */
void mutt_progress_init(struct Progress *progress, const char *msg,
                        unsigned short flags, unsigned short inc, size_t size)
{
  struct timeval tv = { 0, 0 };

  if (!progress)
    return;
  if (OptNoCurses)
    return;

  memset(progress, 0, sizeof(struct Progress));
  progress->inc = inc;
  progress->flags = flags;
  progress->msg = msg;
  progress->size = size;
  if (progress->size != 0)
  {
    if (progress->flags & MUTT_PROGRESS_SIZE)
    {
      mutt_str_pretty_size(progress->sizestr, sizeof(progress->sizestr),
                           progress->size);
    }
    else
      snprintf(progress->sizestr, sizeof(progress->sizestr), "%zu", progress->size);
  }
  if (inc == 0)
  {
    if (size != 0)
      mutt_message("%s (%s)", msg, progress->sizestr);
    else
      mutt_message(msg);
    return;
  }
  if (gettimeofday(&tv, NULL) < 0)
    mutt_debug(LL_DEBUG1, "gettimeofday failed: %d\n", errno);
  /* if timestamp is 0 no time-based suppression is done */
  if (C_TimeInc != 0)
  {
    progress->timestamp =
        ((unsigned int) tv.tv_sec * 1000) + (unsigned int) (tv.tv_usec / 1000);
  }
  mutt_progress_update(progress, 0, 0);
}
コード例 #4
0
ファイル: mutt_notmuch.c プロジェクト: ceyusa/mutt-kz
static void nm_progress_update(CONTEXT *ctx, notmuch_query_t *q)
{
    struct nm_ctxdata *data = get_ctxdata(ctx);

    if (ctx->quiet || data->noprogress)
        return;

    if (!data->progress_ready && q) {
        static char msg[STRING];
        snprintf(msg, sizeof(msg), _("Reading messages..."));

        mutt_progress_init(&data->progress, msg, M_PROGRESS_MSG,
                           ReadInc, notmuch_query_count_messages(q));
        data->progress_ready = 1;
    }

    if (data->progress_ready)
        mutt_progress_update(&data->progress,
                             ctx->msgcount + data->ignmsgcount
                             - data->oldmsgcount, -1);
}
コード例 #5
0
ファイル: message.c プロジェクト: aschrab/mutt
int imap_append_message (CONTEXT *ctx, MESSAGE *msg)
{
  IMAP_DATA* idata;
  FILE *fp;
  char buf[LONG_STRING];
  char mbox[LONG_STRING];
  char mailbox[LONG_STRING];
  char internaldate[IMAP_DATELEN];
  char imap_flags[SHORT_STRING];
  size_t len;
  progress_t progressbar;
  size_t sent;
  int c, last;
  IMAP_MBOX mx;
  int rc;

  idata = (IMAP_DATA*) ctx->data;

  if (imap_parse_path (ctx->path, &mx))
    return -1;

  imap_fix_path (idata, mx.mbox, mailbox, sizeof (mailbox));
  if (!*mailbox)
    strfcpy (mailbox, "INBOX", sizeof (mailbox));

  if ((fp = fopen (msg->path, "r")) == NULL)
  {
    mutt_perror (msg->path);
    goto fail;
  }

  /* currently we set the \Seen flag on all messages, but probably we
   * should scan the message Status header for flag info. Since we're
   * already rereading the whole file for length it isn't any more
   * expensive (it'd be nice if we had the file size passed in already
   * by the code that writes the file, but that's a lot of changes.
   * Ideally we'd have a HEADER structure with flag info here... */
  for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c)
  {
    if(c == '\n' && last != '\r')
      len++;

    len++;
  }
  rewind (fp);

  mutt_progress_init (&progressbar, _("Uploading message..."),
		      MUTT_PROGRESS_SIZE, NetInc, len);

  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
  imap_make_date (internaldate, msg->received);

  imap_flags[0] = imap_flags[1] = 0;
  if (msg->flags.read)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Seen");
  if (msg->flags.replied)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Answered");
  if (msg->flags.flagged)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Flagged");
  if (msg->flags.draft)
    safe_strcat (imap_flags, sizeof (imap_flags), " \\Draft");

  snprintf (buf, sizeof (buf), "APPEND %s (%s) \"%s\" {%lu}", mbox,
            imap_flags + 1,
	    internaldate,
	    (unsigned long) len);

  imap_cmd_start (idata, buf);

  do
    rc = imap_cmd_step (idata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    char *pc;

    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
		idata->buf));

    pc = idata->buf + SEQLEN;
    SKIPWS (pc);
    pc = imap_next_word (pc);
    mutt_error ("%s", pc);
    mutt_sleep (1);
    safe_fclose (&fp);
    goto fail;
  }

  for (last = EOF, sent = len = 0; (c = fgetc(fp)) != EOF; last = c)
  {
    if (c == '\n' && last != '\r')
      buf[len++] = '\r';

    buf[len++] = c;

    if (len > sizeof(buf) - 3)
    {
      sent += len;
      flush_buffer(buf, &len, idata->conn);
      mutt_progress_update (&progressbar, sent, -1);
    }
  }

  if (len)
    flush_buffer(buf, &len, idata->conn);

  mutt_socket_write (idata->conn, "\r\n");
  safe_fclose (&fp);

  do
    rc = imap_cmd_step (idata);
  while (rc == IMAP_CMD_CONTINUE);

  if (!imap_code (idata->buf))
  {
    char *pc;

    dprint (1, (debugfile, "imap_append_message(): command failed: %s\n",
		idata->buf));
    pc = idata->buf + SEQLEN;
    SKIPWS (pc);
    pc = imap_next_word (pc);
    mutt_error ("%s", pc);
    mutt_sleep (1);
    goto fail;
  }

  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&mx.mbox);
  return -1;
}
コード例 #6
0
ファイル: message.c プロジェクト: aschrab/mutt
/* imap_read_headers:
 * Changed to read many headers instead of just one. It will return the
 * msgno of the last message read. It will return a value other than
 * msgend if mail comes in while downloading headers (in theory).
 */
int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
{
  CONTEXT* ctx;
  char *hdrreq = NULL;
  FILE *fp;
  char tempfile[_POSIX_PATH_MAX];
  int msgno, idx = msgbegin - 1;
  IMAP_HEADER h;
  IMAP_STATUS* status;
  int rc, mfhrc, oldmsgcount;
  int fetchlast = 0;
  int maxuid = 0;
  static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL";
  progress_t progress;
  int retval = -1;

#if USE_HCACHE
  char buf[LONG_STRING];
  unsigned int *uid_validity = NULL;
  unsigned int *puidnext = NULL;
  unsigned int uidnext = 0;
  int evalhc = 0;
#endif /* USE_HCACHE */

  ctx = idata->ctx;

  if (mutt_bit_isset (idata->capabilities,IMAP4REV1))
  {
    safe_asprintf (&hdrreq, "BODY.PEEK[HEADER.FIELDS (%s%s%s)]",
                           want_headers, ImapHeaders ? " " : "", NONULL (ImapHeaders));
  }
  else if (mutt_bit_isset (idata->capabilities,IMAP4))
  {
    safe_asprintf (&hdrreq, "RFC822.HEADER.LINES (%s%s%s)",
                           want_headers, ImapHeaders ? " " : "", NONULL (ImapHeaders));
  }
  else
  {	/* Unable to fetch headers for lower versions */
    mutt_error _("Unable to fetch headers from this IMAP server version.");
    mutt_sleep (2);	/* pause a moment to let the user see the error */
    goto error_out_0;
  }

  /* instead of downloading all headers and then parsing them, we parse them
   * as they come in. */
  mutt_mktemp (tempfile, sizeof (tempfile));
  if (!(fp = safe_fopen (tempfile, "w+")))
  {
    mutt_error (_("Could not create temporary file %s"), tempfile);
    mutt_sleep (2);
    goto error_out_0;
  }
  unlink (tempfile);

  /* make sure context has room to hold the mailbox */
  while ((msgend) >= idata->ctx->hdrmax)
    mx_alloc_memory (idata->ctx);

  oldmsgcount = ctx->msgcount;
  idata->reopen &= ~(IMAP_REOPEN_ALLOW|IMAP_NEWMAIL_PENDING);
  idata->newMailCount = 0;

#if USE_HCACHE
  idata->hcache = imap_hcache_open (idata, NULL);

  if (idata->hcache && !msgbegin)
  {
    uid_validity = mutt_hcache_fetch_raw (idata->hcache, "/UIDVALIDITY", imap_hcache_keylen);
    puidnext = mutt_hcache_fetch_raw (idata->hcache, "/UIDNEXT", imap_hcache_keylen);
    if (puidnext)
    {
      uidnext = *puidnext;
      FREE (&puidnext);
    }
    if (uid_validity && uidnext && *uid_validity == idata->uid_validity)
      evalhc = 1;
    FREE (&uid_validity);
  }
  if (evalhc)
  {
    /* L10N:
       Comparing the cached data with the IMAP server's data */
    mutt_progress_init (&progress, _("Evaluating cache..."),
			MUTT_PROGRESS_MSG, ReadInc, msgend + 1);

    snprintf (buf, sizeof (buf),
      "UID FETCH 1:%u (UID FLAGS)", uidnext - 1);

    imap_cmd_start (idata, buf);

    rc = IMAP_CMD_CONTINUE;
    for (msgno = msgbegin; rc == IMAP_CMD_CONTINUE; msgno++)
    {
      mutt_progress_update (&progress, msgno + 1, -1);

      memset (&h, 0, sizeof (h));
      h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
      do
      {
        mfhrc = 0;

        rc = imap_cmd_step (idata);
        if (rc != IMAP_CMD_CONTINUE)
	{
	  imap_free_header_data (&h.data);
          break;
	}

        /* hole in the header cache */
        if (!evalhc)
          continue;

        if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, NULL)) == -1)
          continue;
        else if (mfhrc < 0)
	{
	  imap_free_header_data (&h.data);
          break;
	}

        if (!h.data->uid)
        {
          dprint (2, (debugfile, "imap_read_headers: skipping hcache FETCH "
                      "response for unknown message number %d\n", h.sid));
          mfhrc = -1;
          continue;
        }

        idx++;
        ctx->hdrs[idx] = imap_hcache_get (idata, h.data->uid);
        if (ctx->hdrs[idx])
        {
  	  ctx->hdrs[idx]->index = idx;
  	  /* messages which have not been expunged are ACTIVE (borrowed from mh
  	   * folders) */
  	  ctx->hdrs[idx]->active = 1;
          ctx->hdrs[idx]->read = h.data->read;
          ctx->hdrs[idx]->old = h.data->old;
          ctx->hdrs[idx]->deleted = h.data->deleted;
          ctx->hdrs[idx]->flagged = h.data->flagged;
          ctx->hdrs[idx]->replied = h.data->replied;
          ctx->hdrs[idx]->changed = h.data->changed;
          /*  ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */
          ctx->hdrs[idx]->data = (void *) (h.data);

          ctx->msgcount++;
          ctx->size += ctx->hdrs[idx]->content->length;
        }
	else
        {
	  /* bad header in the cache, we'll have to refetch. */
          dprint (3, (debugfile, "bad cache entry at %d, giving up\n", h.sid - 1));
          imap_free_header_data(&h.data);
          evalhc = 0;
          idx--;
        }
      }
      while (rc != IMAP_CMD_OK && mfhrc == -1);
      if (rc == IMAP_CMD_OK)
        break;
      if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK)))
      {
        imap_free_header_data (&h.data);
        imap_hcache_close (idata);
	goto error_out_1;
      }
    }
    /* could also look for first null header in case hcache is holey */
    msgbegin = ctx->msgcount;
  }
#endif /* USE_HCACHE */

  mutt_progress_init (&progress, _("Fetching message headers..."),
		      MUTT_PROGRESS_MSG, ReadInc, msgend + 1);

  for (msgno = msgbegin; msgno <= msgend ; msgno++)
  {
    mutt_progress_update (&progress, msgno + 1, -1);

    /* we may get notification of new mail while fetching headers */
    if (msgno + 1 > fetchlast)
    {
      char *cmd;

      fetchlast = msgend + 1;
      safe_asprintf (&cmd, "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)",
                     msgno + 1, fetchlast, hdrreq);
      imap_cmd_start (idata, cmd);
      FREE (&cmd);
    }

    rewind (fp);
    memset (&h, 0, sizeof (h));
    h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));

    /* this DO loop does two things:
     * 1. handles untagged messages, so we can try again on the same msg
     * 2. fetches the tagged response at the end of the last message.
     */
    do
    {
      mfhrc = 0;

      rc = imap_cmd_step (idata);
      if (rc != IMAP_CMD_CONTINUE)
	break;

      if ((mfhrc = msg_fetch_header (ctx, &h, idata->buf, fp)) == -1)
	continue;
      else if (mfhrc < 0)
	break;

      if (!ftello (fp))
      {
        dprint (2, (debugfile, "msg_fetch_header: ignoring fetch response with no body\n"));
        mfhrc = -1;
        msgend--;
        continue;
      }

      /* make sure we don't get remnants from older larger message headers */
      fputs ("\n\n", fp);

      idx++;
      if (idx > msgend)
      {
        dprint (1, (debugfile, "imap_read_headers: skipping FETCH response for "
                    "unknown message number %d\n", h.sid));
        mfhrc = -1;
        idx--;
        continue;
      }
      /* May receive FLAGS updates in a separate untagged response (#2935) */
      if (idx < ctx->msgcount)
      {
	dprint (2, (debugfile, "imap_read_headers: message %d is not new\n",
		    h.sid));
        idx--;
	continue;
      }

      ctx->hdrs[idx] = mutt_new_header ();

      ctx->hdrs[idx]->index = h.sid - 1;
      /* messages which have not been expunged are ACTIVE (borrowed from mh
       * folders) */
      ctx->hdrs[idx]->active = 1;
      ctx->hdrs[idx]->read = h.data->read;
      ctx->hdrs[idx]->old = h.data->old;
      ctx->hdrs[idx]->deleted = h.data->deleted;
      ctx->hdrs[idx]->flagged = h.data->flagged;
      ctx->hdrs[idx]->replied = h.data->replied;
      ctx->hdrs[idx]->changed = h.data->changed;
      ctx->hdrs[idx]->received = h.received;
      ctx->hdrs[idx]->data = (void *) (h.data);

      if (maxuid < h.data->uid)
        maxuid = h.data->uid;

      rewind (fp);
      /* NOTE: if Date: header is missing, mutt_read_rfc822_header depends
       *   on h.received being set */
      ctx->hdrs[idx]->env = mutt_read_rfc822_header (fp, ctx->hdrs[idx],
        0, 0);
      /* content built as a side-effect of mutt_read_rfc822_header */
      ctx->hdrs[idx]->content->length = h.content_length;
      ctx->size += h.content_length;

#if USE_HCACHE
      imap_hcache_put (idata, ctx->hdrs[idx]);
#endif /* USE_HCACHE */

      ctx->msgcount++;
    }
    while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) ||
      ((msgno + 1) >= fetchlast)));

    if ((mfhrc < -1) || ((rc != IMAP_CMD_CONTINUE) && (rc != IMAP_CMD_OK)))
    {
      imap_free_header_data (&h.data);
#if USE_HCACHE
      imap_hcache_close (idata);
#endif
      goto error_out_1;
    }

    /* in case we get new mail while fetching the headers */
    if (idata->reopen & IMAP_NEWMAIL_PENDING)
    {
      msgend = idata->newMailCount - 1;
      while ((msgend) >= ctx->hdrmax)
	mx_alloc_memory (ctx);
      idata->reopen &= ~IMAP_NEWMAIL_PENDING;
      idata->newMailCount = 0;
    }
  }

  if (maxuid && (status = imap_mboxcache_get (idata, idata->mailbox, 0)) &&
      (status->uidnext < maxuid + 1))
    status->uidnext = maxuid + 1;

#if USE_HCACHE
  mutt_hcache_store_raw (idata->hcache, "/UIDVALIDITY", &idata->uid_validity,
                         sizeof (idata->uid_validity), imap_hcache_keylen);
  if (maxuid && idata->uidnext < maxuid + 1)
  {
    dprint (2, (debugfile, "Overriding UIDNEXT: %u -> %u\n", idata->uidnext, maxuid + 1));
    idata->uidnext = maxuid + 1;
  }
  if (idata->uidnext > 1)
    mutt_hcache_store_raw (idata->hcache, "/UIDNEXT", &idata->uidnext,
			   sizeof (idata->uidnext), imap_hcache_keylen);

  imap_hcache_close (idata);
#endif /* USE_HCACHE */

  if (ctx->msgcount > oldmsgcount)
  {
    mx_alloc_memory(ctx);
    mx_update_context (ctx, ctx->msgcount - oldmsgcount);
  }

  idata->reopen |= IMAP_REOPEN_ALLOW;

  retval = msgend;

error_out_1:
  safe_fclose (&fp);

error_out_0:
  FREE (&hdrreq);

  return retval;
}
コード例 #7
0
ファイル: smtp.c プロジェクト: tejux/mutt-hacks
static int
smtp_data (CONNECTION * conn, const char *msgfile)
{
        char buf[1024];
        FILE *fp = 0;
        progress_t progress;
        struct stat st;
        int r, term = 0;
        size_t buflen = 0;

        fp = fopen (msgfile, "r");
        if (!fp) {
                mutt_error (_("SMTP session failed: unable to open %s"), msgfile);
                return -1;
        }
        stat (msgfile, &st);
        unlink (msgfile);
        mutt_progress_init (&progress, _("Sending message..."), M_PROGRESS_SIZE,
                NetInc, st.st_size);

        snprintf (buf, sizeof (buf), "DATA\r\n");
        if (mutt_socket_write (conn, buf) == -1) {
                safe_fclose (&fp);
                return smtp_err_write;
        }
        if ((r = smtp_get_resp (conn))) {
                safe_fclose (&fp);
                return r;
        }

        while (fgets (buf, sizeof (buf) - 1, fp)) {
                buflen = mutt_strlen (buf);
                term = buf[buflen-1] == '\n';
                if (buflen && buf[buflen-1] == '\n'
                        && (buflen == 1 || buf[buflen - 2] != '\r'))
                        snprintf (buf + buflen - 1, sizeof (buf) - buflen + 1, "\r\n");
                if (buf[0] == '.') {
                        if (mutt_socket_write_d (conn, ".", -1, M_SOCK_LOG_FULL) == -1) {
                                safe_fclose (&fp);
                                return smtp_err_write;
                        }
                }
                if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) == -1) {
                        safe_fclose (&fp);
                        return smtp_err_write;
                }
                mutt_progress_update (&progress, ftell (fp), -1);
        }
        if (!term && buflen &&
        mutt_socket_write_d (conn, "\r\n", -1, M_SOCK_LOG_FULL) == -1) {
                safe_fclose (&fp);
                return smtp_err_write;
        }
        safe_fclose (&fp);

/* terminate the message body */
        if (mutt_socket_write (conn, ".\r\n") == -1)
                return smtp_err_write;

        if ((r = smtp_get_resp (conn)))
                return r;

        return 0;
}
コード例 #8
0
ファイル: mbox.c プロジェクト: kdave/neomutt
/**
 * mbox_parse_mailbox - Read a mailbox from disk
 * @param m Mailbox
 * @retval  0 Success
 * @retval -1 Error
 * @retval -2 Aborted
 *
 * Note that this function is also called when new mail is appended to the
 * currently open folder, and NOT just when the mailbox is initially read.
 *
 * NOTE: it is assumed that the mailbox being read has been locked before this
 * routine gets called.  Strange things could happen if it's not!
 */
static int mbox_parse_mailbox(struct Mailbox *m)
{
  if (!m)
    return -1;

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

  struct stat sb;
  char buf[8192], return_path[256];
  struct Email *e_cur = NULL;
  time_t t;
  int count = 0, lines = 0;
  LOFF_T loc;
  struct Progress progress;

  /* Save information about the folder at the time we opened it. */
  if (stat(m->path, &sb) == -1)
  {
    mutt_perror(m->path);
    return -1;
  }

  m->size = sb.st_size;
  mutt_file_get_stat_timespec(&m->mtime, &sb, MUTT_STAT_MTIME);
  mutt_file_get_stat_timespec(&adata->atime, &sb, MUTT_STAT_ATIME);

  if (!m->readonly)
    m->readonly = access(m->path, W_OK) ? true : false;

  if (!m->quiet)
  {
    char msgbuf[256];
    snprintf(msgbuf, sizeof(msgbuf), _("Reading %s..."), m->path);
    mutt_progress_init(&progress, msgbuf, MUTT_PROGRESS_MSG, C_ReadInc, 0);
  }

  if (!m->emails)
  {
    /* Allocate some memory to get started */
    m->email_max = m->msg_count;
    m->msg_count = 0;
    m->msg_unread = 0;
    m->vcount = 0;
    mx_alloc_memory(m);
  }

  loc = ftello(adata->fp);
  while ((fgets(buf, sizeof(buf), adata->fp)) && (SigInt != 1))
  {
    if (is_from(buf, return_path, sizeof(return_path), &t))
    {
      /* Save the Content-Length of the previous message */
      if (count > 0)
      {
        struct Email *e = m->emails[m->msg_count - 1];
        if (e->content->length < 0)
        {
          e->content->length = loc - e->content->offset - 1;
          if (e->content->length < 0)
            e->content->length = 0;
        }
        if (!e->lines)
          e->lines = lines ? lines - 1 : 0;
      }

      count++;

      if (!m->quiet)
      {
        mutt_progress_update(&progress, count,
                             (int) (ftello(adata->fp) / (m->size / 100 + 1)));
      }

      if (m->msg_count == m->email_max)
        mx_alloc_memory(m);

      m->emails[m->msg_count] = mutt_email_new();
      e_cur = m->emails[m->msg_count];
      e_cur->received = t - mutt_date_local_tz(t);
      e_cur->offset = loc;
      e_cur->index = m->msg_count;

      e_cur->env = mutt_rfc822_read_header(adata->fp, e_cur, false, false);

      /* if we know how long this message is, either just skip over the body,
       * or if we don't know how many lines there are, count them now (this will
       * save time by not having to search for the next message marker).  */
      if (e_cur->content->length > 0)
      {
        LOFF_T tmploc;

        loc = ftello(adata->fp);

        /* The test below avoids a potential integer overflow if the
         * content-length is huge (thus necessarily invalid).  */
        tmploc = (e_cur->content->length < m->size) ?
                     (loc + e_cur->content->length + 1) :
                     -1;

        if ((tmploc > 0) && (tmploc < m->size))
        {
          /* check to see if the content-length looks valid.  we expect to
           * to see a valid message separator at this point in the stream */
          if ((fseeko(adata->fp, tmploc, SEEK_SET) != 0) ||
              !fgets(buf, sizeof(buf), adata->fp) ||
              !mutt_str_startswith(buf, "From ", CASE_MATCH))
          {
            mutt_debug(LL_DEBUG1, "bad content-length in message %d (cl=" OFF_T_FMT ")\n",
                       e_cur->index, e_cur->content->length);
            mutt_debug(LL_DEBUG1, "\tLINE: %s", buf);
            /* nope, return the previous position */
            if ((loc < 0) || (fseeko(adata->fp, loc, SEEK_SET) != 0))
            {
              mutt_debug(LL_DEBUG1, "#1 fseek() failed\n");
            }
            e_cur->content->length = -1;
          }
        }
        else if (tmploc != m->size)
        {
          /* content-length would put us past the end of the file, so it
           * must be wrong */
          e_cur->content->length = -1;
        }

        if (e_cur->content->length != -1)
        {
          /* good content-length.  check to see if we know how many lines
           * are in this message.  */
          if (e_cur->lines == 0)
          {
            int cl = e_cur->content->length;

            /* count the number of lines in this message */
            if ((loc < 0) || (fseeko(adata->fp, loc, SEEK_SET) != 0))
              mutt_debug(LL_DEBUG1, "#2 fseek() failed\n");
            while (cl-- > 0)
            {
              if (fgetc(adata->fp) == '\n')
                e_cur->lines++;
            }
          }

          /* return to the offset of the next message separator */
          if (fseeko(adata->fp, tmploc, SEEK_SET) != 0)
            mutt_debug(LL_DEBUG1, "#3 fseek() failed\n");
        }
      }

      m->msg_count++;

      if (!e_cur->env->return_path && return_path[0])
      {
        e_cur->env->return_path = mutt_addr_parse_list(e_cur->env->return_path, return_path);
      }

      if (!e_cur->env->from)
        e_cur->env->from = mutt_addr_copy_list(e_cur->env->return_path, false);

      lines = 0;
    }
    else
      lines++;

    loc = ftello(adata->fp);
  }

  /* Only set the content-length of the previous message if we have read more
   * than one message during _this_ invocation.  If this routine is called
   * when new mail is received, we need to make sure not to clobber what
   * previously was the last message since the headers may be sorted.  */
  if (count > 0)
  {
    struct Email *e = m->emails[m->msg_count - 1];
    if (e->content->length < 0)
    {
      e->content->length = ftello(adata->fp) - e->content->offset - 1;
      if (e->content->length < 0)
        e->content->length = 0;
    }

    if (!e->lines)
      e->lines = lines ? lines - 1 : 0;
  }

  if (SigInt == 1)
  {
    SigInt = 0;
    return -2; /* action aborted */
  }

  return 0;
}
コード例 #9
0
ファイル: mbox.c プロジェクト: kdave/neomutt
/**
 * mmdf_parse_mailbox - Read a mailbox in MMDF format
 * @param m Mailbox
 * @retval  0 Success
 * @retval -1 Failure
 * @retval -2 Aborted
 */
static int mmdf_parse_mailbox(struct Mailbox *m)
{
  if (!m)
    return -1;

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

  char buf[8192];
  char return_path[1024];
  int count = 0;
  int lines;
  time_t t;
  LOFF_T loc, tmploc;
  struct Email *e = NULL;
  struct stat sb;
  struct Progress progress;

  if (stat(m->path, &sb) == -1)
  {
    mutt_perror(m->path);
    return -1;
  }
  mutt_file_get_stat_timespec(&adata->atime, &sb, MUTT_STAT_ATIME);
  mutt_file_get_stat_timespec(&m->mtime, &sb, MUTT_STAT_MTIME);
  m->size = sb.st_size;

  buf[sizeof(buf) - 1] = '\0';

  if (!m->quiet)
  {
    char msgbuf[256];
    snprintf(msgbuf, sizeof(msgbuf), _("Reading %s..."), m->path);
    mutt_progress_init(&progress, msgbuf, MUTT_PROGRESS_MSG, C_ReadInc, 0);
  }

  while (true)
  {
    if (!fgets(buf, sizeof(buf) - 1, adata->fp))
      break;

    if (SigInt == 1)
      break;

    if (mutt_str_strcmp(buf, MMDF_SEP) == 0)
    {
      loc = ftello(adata->fp);
      if (loc < 0)
        return -1;

      count++;
      if (!m->quiet)
        mutt_progress_update(&progress, count, (int) (loc / (m->size / 100 + 1)));

      if (m->msg_count == m->email_max)
        mx_alloc_memory(m);
      e = mutt_email_new();
      m->emails[m->msg_count] = e;
      e->offset = loc;
      e->index = m->msg_count;

      if (!fgets(buf, sizeof(buf) - 1, adata->fp))
      {
        /* TODO: memory leak??? */
        mutt_debug(LL_DEBUG1, "unexpected EOF\n");
        break;
      }

      return_path[0] = '\0';

      if (!is_from(buf, return_path, sizeof(return_path), &t))
      {
        if (fseeko(adata->fp, loc, SEEK_SET) != 0)
        {
          mutt_debug(LL_DEBUG1, "#1 fseek() failed\n");
          mutt_error(_("Mailbox is corrupt"));
          return -1;
        }
      }
      else
        e->received = t - mutt_date_local_tz(t);

      e->env = mutt_rfc822_read_header(adata->fp, e, false, false);

      loc = ftello(adata->fp);
      if (loc < 0)
        return -1;

      if ((e->content->length > 0) && (e->lines > 0))
      {
        tmploc = loc + e->content->length;

        if ((tmploc > 0) && (tmploc < m->size))
        {
          if ((fseeko(adata->fp, tmploc, SEEK_SET) != 0) ||
              !fgets(buf, sizeof(buf) - 1, adata->fp) ||
              (mutt_str_strcmp(MMDF_SEP, buf) != 0))
          {
            if (fseeko(adata->fp, loc, SEEK_SET) != 0)
              mutt_debug(LL_DEBUG1, "#2 fseek() failed\n");
            e->content->length = -1;
          }
        }
        else
          e->content->length = -1;
      }
      else
        e->content->length = -1;

      if (e->content->length < 0)
      {
        lines = -1;
        do
        {
          loc = ftello(adata->fp);
          if (loc < 0)
            return -1;
          if (!fgets(buf, sizeof(buf) - 1, adata->fp))
            break;
          lines++;
        } while (mutt_str_strcmp(buf, MMDF_SEP) != 0);

        e->lines = lines;
        e->content->length = loc - e->content->offset;
      }

      if (!e->env->return_path && return_path[0])
        e->env->return_path = mutt_addr_parse_list(e->env->return_path, return_path);

      if (!e->env->from)
        e->env->from = mutt_addr_copy_list(e->env->return_path, false);

      m->msg_count++;
    }
    else
    {
      mutt_debug(LL_DEBUG1, "corrupt mailbox\n");
      mutt_error(_("Mailbox is corrupt"));
      return -1;
    }
  }

  if (SigInt == 1)
  {
    SigInt = 0;
    return -2; /* action aborted */
  }

  return 0;
}
コード例 #10
0
ファイル: mbox.c プロジェクト: kdave/neomutt
/**
 * mbox_mbox_sync - Implements MxOps::mbox_sync()
 */
static int mbox_mbox_sync(struct Mailbox *m, int *index_hint)
{
  if (!m)
    return -1;

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

  char tempfile[PATH_MAX];
  char buf[32];
  int i, j;
  enum SortType save_sort = SORT_ORDER;
  int rc = -1;
  int need_sort = 0; /* flag to resort mailbox if new mail arrives */
  int first = -1;    /* first message to be written */
  LOFF_T offset;     /* location in mailbox to write changed messages */
  struct stat statbuf;
  struct MUpdate *new_offset = NULL;
  struct MUpdate *old_offset = NULL;
  FILE *fp = NULL;
  struct Progress progress;
  char msgbuf[PATH_MAX + 64];

  /* sort message by their position in the mailbox on disk */
  if (C_Sort != SORT_ORDER)
  {
    save_sort = C_Sort;
    C_Sort = SORT_ORDER;
    mutt_mailbox_changed(m, MBN_RESORT);
    C_Sort = save_sort;
    need_sort = 1;
  }

  /* need to open the file for writing in such a way that it does not truncate
   * the file, so use read-write mode.  */
  adata->fp = freopen(m->path, "r+", adata->fp);
  if (!adata->fp)
  {
    mx_fastclose_mailbox(m);
    mutt_error(_("Fatal error!  Could not reopen mailbox!"));
    return -1;
  }

  mutt_sig_block();

  if (mbox_lock_mailbox(m, true, true) == -1)
  {
    mutt_sig_unblock();
    mutt_error(_("Unable to lock mailbox"));
    goto bail;
  }

  /* Check to make sure that the file hasn't changed on disk */
  i = mbox_mbox_check(m, index_hint);
  if ((i == MUTT_NEW_MAIL) || (i == MUTT_REOPENED))
  {
    /* new mail arrived, or mailbox reopened */
    rc = i;
    goto bail;
  }
  else if (i < 0)
  {
    /* fatal error */
    return -1;
  }

  /* Create a temporary file to write the new version of the mailbox in. */
  mutt_mktemp(tempfile, sizeof(tempfile));
  int fd = open(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600);
  if ((fd == -1) || !(fp = fdopen(fd, "w")))
  {
    if (fd != -1)
    {
      close(fd);
      unlink(tempfile);
    }
    mutt_error(_("Could not create temporary file"));
    goto bail;
  }

  /* find the first deleted/changed message.  we save a lot of time by only
   * rewriting the mailbox from the point where it has actually changed.  */
  for (i = 0; (i < m->msg_count) && !m->emails[i]->deleted &&
              !m->emails[i]->changed && !m->emails[i]->attach_del;
       i++)
  {
  }
  if (i == m->msg_count)
  {
    /* this means ctx->changed or m->msg_deleted was set, but no
     * messages were found to be changed or deleted.  This should
     * never happen, is we presume it is a bug in neomutt.  */
    mutt_error(
        _("sync: mbox modified, but no modified messages (report this bug)"));
    mutt_debug(LL_DEBUG1, "no modified messages\n");
    unlink(tempfile);
    goto bail;
  }

  /* save the index of the first changed/deleted message */
  first = i;
  /* where to start overwriting */
  offset = m->emails[i]->offset;

  /* the offset stored in the header does not include the MMDF_SEP, so make
   * sure we seek to the correct location */
  if (m->magic == MUTT_MMDF)
    offset -= (sizeof(MMDF_SEP) - 1);

  /* allocate space for the new offsets */
  new_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));
  old_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));

  if (!m->quiet)
  {
    snprintf(msgbuf, sizeof(msgbuf), _("Writing %s..."), m->path);
    mutt_progress_init(&progress, msgbuf, MUTT_PROGRESS_MSG, C_WriteInc, m->msg_count);
  }

  for (i = first, j = 0; i < m->msg_count; i++)
  {
    if (!m->quiet)
      mutt_progress_update(&progress, i, (int) (ftello(adata->fp) / (m->size / 100 + 1)));
    /* back up some information which is needed to restore offsets when
     * something fails.  */

    old_offset[i - first].valid = true;
    old_offset[i - first].hdr = m->emails[i]->offset;
    old_offset[i - first].body = m->emails[i]->content->offset;
    old_offset[i - first].lines = m->emails[i]->lines;
    old_offset[i - first].length = m->emails[i]->content->length;

    if (!m->emails[i]->deleted)
    {
      j++;

      if (m->magic == MUTT_MMDF)
      {
        if (fputs(MMDF_SEP, fp) == EOF)
        {
          mutt_perror(tempfile);
          unlink(tempfile);
          goto bail;
        }
      }

      /* save the new offset for this message.  we add 'offset' because the
       * temporary file only contains saved message which are located after
       * 'offset' in the real mailbox */
      new_offset[i - first].hdr = ftello(fp) + offset;

      if (mutt_copy_message_ctx(fp, m, m->emails[i], MUTT_CM_UPDATE,
                                CH_FROM | CH_UPDATE | CH_UPDATE_LEN) != 0)
      {
        mutt_perror(tempfile);
        unlink(tempfile);
        goto bail;
      }

      /* Since messages could have been deleted, the offsets stored in memory
       * will be wrong, so update what we can, which is the offset of this
       * message, and the offset of the body.  If this is a multipart message,
       * we just flush the in memory cache so that the message will be reparsed
       * if the user accesses it later.  */
      new_offset[i - first].body = ftello(fp) - m->emails[i]->content->length + offset;
      mutt_body_free(&m->emails[i]->content->parts);

      switch (m->magic)
      {
        case MUTT_MMDF:
          if (fputs(MMDF_SEP, fp) == EOF)
          {
            mutt_perror(tempfile);
            unlink(tempfile);
            goto bail;
          }
          break;
        default:
          if (fputs("\n", fp) == EOF)
          {
            mutt_perror(tempfile);
            unlink(tempfile);
            goto bail;
          }
      }
    }
  }

  if (fclose(fp) != 0)
  {
    fp = NULL;
    mutt_debug(LL_DEBUG1, "mutt_file_fclose (&) returned non-zero\n");
    unlink(tempfile);
    mutt_perror(tempfile);
    goto bail;
  }
  fp = NULL;

  /* Save the state of this folder. */
  if (stat(m->path, &statbuf) == -1)
  {
    mutt_perror(m->path);
    unlink(tempfile);
    goto bail;
  }

  fp = fopen(tempfile, "r");
  if (!fp)
  {
    mutt_sig_unblock();
    mx_fastclose_mailbox(m);
    mutt_debug(LL_DEBUG1, "unable to reopen temp copy of mailbox!\n");
    mutt_perror(tempfile);
    FREE(&new_offset);
    FREE(&old_offset);
    return -1;
  }

  if ((fseeko(adata->fp, offset, SEEK_SET) != 0) || /* seek the append location */
      /* do a sanity check to make sure the mailbox looks ok */
      !fgets(buf, sizeof(buf), adata->fp) ||
      ((m->magic == MUTT_MBOX) && !mutt_str_startswith(buf, "From ", CASE_MATCH)) ||
      ((m->magic == MUTT_MMDF) && (mutt_str_strcmp(MMDF_SEP, buf) != 0)))
  {
    mutt_debug(LL_DEBUG1, "message not in expected position\n");
    mutt_debug(LL_DEBUG1, "\tLINE: %s\n", buf);
    i = -1;
  }
  else
  {
    if (fseeko(adata->fp, offset, SEEK_SET) != 0) /* return to proper offset */
    {
      i = -1;
      mutt_debug(LL_DEBUG1, "fseek() failed\n");
    }
    else
    {
      /* copy the temp mailbox back into place starting at the first
       * change/deleted message */
      if (!m->quiet)
        mutt_message(_("Committing changes..."));
      i = mutt_file_copy_stream(fp, adata->fp);

      if (ferror(adata->fp))
        i = -1;
    }
    if (i == 0)
    {
      m->size = ftello(adata->fp); /* update the mailbox->size of the mailbox */
      if ((m->size < 0) || (ftruncate(fileno(adata->fp), m->size) != 0))
      {
        i = -1;
        mutt_debug(LL_DEBUG1, "ftruncate() failed\n");
      }
    }
  }

  mutt_file_fclose(&fp);
  fp = NULL;
  mbox_unlock_mailbox(m);

  if ((mutt_file_fclose(&adata->fp) != 0) || (i == -1))
  {
    /* error occurred while writing the mailbox back, so keep the temp copy around */

    char savefile[PATH_MAX];

    snprintf(savefile, sizeof(savefile), "%s/neomutt.%s-%s-%u", NONULL(C_Tmpdir),
             NONULL(Username), NONULL(ShortHostname), (unsigned int) getpid());
    rename(tempfile, savefile);
    mutt_sig_unblock();
    mx_fastclose_mailbox(m);
    mutt_pretty_mailbox(savefile, sizeof(savefile));
    mutt_error(_("Write failed!  Saved partial mailbox to %s"), savefile);
    FREE(&new_offset);
    FREE(&old_offset);
    return -1;
  }

  /* Restore the previous access/modification times */
  mbox_reset_atime(m, &statbuf);

  /* reopen the mailbox in read-only mode */
  adata->fp = fopen(m->path, "r");
  if (!adata->fp)
  {
    unlink(tempfile);
    mutt_sig_unblock();
    mx_fastclose_mailbox(m);
    mutt_error(_("Fatal error!  Could not reopen mailbox!"));
    FREE(&new_offset);
    FREE(&old_offset);
    return -1;
  }

  /* update the offsets of the rewritten messages */
  for (i = first, j = first; i < m->msg_count; i++)
  {
    if (!m->emails[i]->deleted)
    {
      m->emails[i]->offset = new_offset[i - first].hdr;
      m->emails[i]->content->hdr_offset = new_offset[i - first].hdr;
      m->emails[i]->content->offset = new_offset[i - first].body;
      m->emails[i]->index = j++;
    }
  }
  FREE(&new_offset);
  FREE(&old_offset);
  unlink(tempfile); /* remove partial copy of the mailbox */
  mutt_sig_unblock();

  if (C_CheckMboxSize)
  {
    struct Mailbox *tmp = mutt_find_mailbox(m->path);
    if (tmp && !tmp->has_new)
      mutt_update_mailbox(tmp);
  }

  return 0; /* signal success */

bail: /* Come here in case of disaster */

  mutt_file_fclose(&fp);

  /* restore offsets, as far as they are valid */
  if ((first >= 0) && old_offset)
  {
    for (i = first; (i < m->msg_count) && old_offset[i - first].valid; i++)
    {
      m->emails[i]->offset = old_offset[i - first].hdr;
      m->emails[i]->content->hdr_offset = old_offset[i - first].hdr;
      m->emails[i]->content->offset = old_offset[i - first].body;
      m->emails[i]->lines = old_offset[i - first].lines;
      m->emails[i]->content->length = old_offset[i - first].length;
    }
  }

  /* this is ok to call even if we haven't locked anything */
  mbox_unlock_mailbox(m);

  mutt_sig_unblock();
  FREE(&new_offset);
  FREE(&old_offset);

  adata->fp = freopen(m->path, "r", adata->fp);
  if (!adata->fp)
  {
    mutt_error(_("Could not reopen mailbox"));
    mx_fastclose_mailbox(m);
    return -1;
  }

  if (need_sort)
  {
    /* if the mailbox was reopened, the thread tree will be invalid so make
     * sure to start threading from scratch.  */
    mutt_mailbox_changed(m, MBN_RESORT);
  }

  return rc;
}
コード例 #11
0
ファイル: mbox.cpp プロジェクト: badeip/neomutt
/* return values:
 *	0	success
 *	-1	failure
 */
int mbox_sync_mailbox(CONTEXT *ctx, int *index_hint)
{
    char tempfile[_POSIX_PATH_MAX];
    char buf[32];
    int i, j, save_sort = SORT_ORDER;
    int rc = -1;
    int need_sort = 0; /* flag to resort mailbox if new mail arrives */
    int first = -1;    /* first message to be written */
    LOFF_T offset;     /* location in mailbox to write changed messages */
    struct stat statbuf;
    struct m_update_t *newOffset = NULL;
    struct m_update_t *oldOffset = NULL;
    FILE *fp = NULL;
    progress_t progress;
    char msgbuf[STRING];

    /* sort message by their position in the mailbox on disk */
    if (Sort != SORT_ORDER) {
        save_sort = Sort;
        Sort = SORT_ORDER;
        mutt_sort_headers(ctx, 0);
        Sort = save_sort;
        need_sort = 1;
    }

    /* need to open the file for writing in such a way that it does not truncate
     * the file, so use read-write mode.
     */
    if ((ctx->fp = freopen(ctx->path, "r+", ctx->fp)) == NULL) {
        mx_fastclose_mailbox(ctx);
        mutt_error _("Fatal error!  Could not reopen mailbox!");
        return -1;
    }

    mutt_block_signals();

    if (mbox_lock_mailbox(ctx, 1, 1) == -1) {
        mutt_unblock_signals();
        mutt_error _("Unable to lock mailbox!");
        goto bail;
    }

    /* Check to make sure that the file hasn't changed on disk */
    if (((i = mbox_check_mailbox(ctx, index_hint)) == M_NEW_MAIL)
        || (i == M_REOPENED)) {
        /* new mail arrived, or mailbox reopened */
        need_sort = i;
        rc = i;
        goto bail;
    } else if (i < 0)
        /* fatal error */
        return -1;

    /* Create a temporary file to write the new version of the mailbox in. */
    mutt_mktemp(tempfile, sizeof(tempfile));

    if (((i = open(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
        || ((fp = fdopen(i, "w")) == NULL)) {
        if (-1 != i) {
            close(i);
            unlink(tempfile);
        }
        mutt_error _("Could not create temporary file!");
        mutt_sleep(5);
        goto bail;
    }

    /* find the first deleted/changed message.  we save a lot of time by only
     * rewriting the mailbox from the point where it has actually changed.
     */
    for (i = 0; i < ctx->msgcount
         && !ctx->hdrs[i]->deleted
         && !ctx->hdrs[i]->changed
         && !ctx->hdrs[i]->attach_del; i++)
        ;

    if (i == ctx->msgcount) {
        /* this means ctx->changed or ctx->deleted was set, but no
         * messages were found to be changed or deleted.  This should
         * never happen, is we presume it is a bug in mutt.
         */
        mutt_error _(
            "sync: mbox modified, but no modified messages! (report this bug)");
        mutt_sleep(5); /* the mutt_error /will/ get cleared! */
        dprint(1, "mbox_sync_mailbox(): no modified messages.\n");
        unlink(tempfile);
        goto bail;
    }

    /* save the index of the first changed/deleted message */
    first = i;

    /* where to start overwriting */
    offset = ctx->hdrs[i]->offset;

    /* the offset stored in the header does not include the MMDF_SEP, so make
     * sure we seek to the correct location
     */
    if (ctx->magic == M_MMDF)
        offset -= (sizeof MMDF_SEP - 1);

    /* allocate space for the new offsets */
    newOffset = (__typeof__(newOffset)) safe_calloc(ctx->msgcount - first, sizeof(struct m_update_t));
    oldOffset = (__typeof__(oldOffset)) safe_calloc(ctx->msgcount - first, sizeof(struct m_update_t));

    if (!ctx->quiet) {
        snprintf(msgbuf, sizeof(msgbuf), _("Writing %s..."), ctx->path);
        mutt_progress_init(&progress,
                           msgbuf,
                           M_PROGRESS_MSG,
                           WriteInc,
                           ctx->msgcount);
    }

    for (i = first, j = 0; i < ctx->msgcount; i++) {
        if (!ctx->quiet)
            mutt_progress_update(&progress, i,
                                 (int)(ftello(ctx->fp) /
                                       (ctx->size / 100 + 1)));

        /*
         * back up some information which is needed to restore offsets when
         * something fails.
         */

        oldOffset[i - first].valid  = 1;
        oldOffset[i - first].hdr    = ctx->hdrs[i]->offset;
        oldOffset[i - first].body   = ctx->hdrs[i]->content->offset;
        oldOffset[i - first].lines  = ctx->hdrs[i]->lines;
        oldOffset[i - first].length = ctx->hdrs[i]->content->length;

        if (!ctx->hdrs[i]->deleted) {
            j++;

            if (ctx->magic == M_MMDF) {
                if (fputs(MMDF_SEP, fp) == EOF) {
                    mutt_perror(tempfile);
                    mutt_sleep(5);
                    unlink(tempfile);
                    goto bail;
                }
            }

            /* save the new offset for this message.  we add `offset' because
               the
             * temporary file only contains saved message which are located
             *after
             * `offset' in the real mailbox
             */
            newOffset[i - first].hdr = ftello(fp) + offset;

            if (mutt_copy_message(fp, ctx, ctx->hdrs[i], M_CM_UPDATE,
                                  CH_FROM | CH_UPDATE | CH_UPDATE_LEN) != 0) {
                mutt_perror(tempfile);
                mutt_sleep(5);
                unlink(tempfile);
                goto bail;
            }

            /* Since messages could have been deleted, the offsets stored in
               memory
             * will be wrong, so update what we can, which is the offset of this
             * message, and the offset of the body.  If this is a multipart
             *message,
             * we just flush the in memory cache so that the message will be
             *reparsed
             * if the user accesses it later.
             */
            newOffset[i - first].body = ftello(fp) -
                                        ctx->hdrs[i]->content->length + offset;
            mutt_free_body(&ctx->hdrs[i]->content->parts);

            switch (ctx->magic) {
            case M_MMDF:

                if (fputs(MMDF_SEP, fp) == EOF) {
                    mutt_perror(tempfile);
                    mutt_sleep(5);
                    unlink(tempfile);
                    goto bail;
                }
                break;

            default:

                if (fputs("\n", fp) == EOF) {
                    mutt_perror(tempfile);
                    mutt_sleep(5);
                    unlink(tempfile);
                    goto bail;
                }
            }
        }
    }

    if (fclose(fp) != 0) {
        fp = NULL;
        dprint(1, "mbox_sync_mailbox: safe_fclose (&) returned non-zero.\n");
        unlink(tempfile);
        mutt_perror(tempfile);
        mutt_sleep(5);
        goto bail;
    }
    fp = NULL;

    /* Save the state of this folder. */
    if (stat(ctx->path, &statbuf) == -1) {
        mutt_perror(ctx->path);
        mutt_sleep(5);
        unlink(tempfile);
        goto bail;
    }

    if ((fp = fopen(tempfile, "r")) == NULL) {
        mutt_unblock_signals();
        mx_fastclose_mailbox(ctx);
        dprint(1, "mbox_sync_mailbox: unable to reopen temp copy of mailbox!\n");
        mutt_perror(tempfile);
        mutt_sleep(5);
        return -1;
    }

    if ((fseeko(ctx->fp, offset, SEEK_SET) != 0) /* seek the append location */
        ||/* do a sanity check to make sure the mailbox looks ok */
        (fgets(buf, sizeof(buf), ctx->fp) == NULL)
        || ((ctx->magic == M_MBOX)
            && (mutt_strncmp("From ", buf, 5) != 0))
        || ((ctx->magic == M_MMDF)
            && (mutt_strcmp(MMDF_SEP, buf) != 0))) {
        dprint(1, "mbox_sync_mailbox: message not in expected position.");
        dprint(1, "\tLINE: %s\n", buf);
        i = -1;
    } else {
        if (fseeko(ctx->fp, offset, SEEK_SET) != 0) { /* return to proper offset
                                                         */
            i = -1;
            dprint(1, "mbox_sync_mailbox: fseek() failed\n");
        } else {
            /* copy the temp mailbox back into place starting at the first
             * change/deleted message
             */
            if (!ctx->quiet)
                mutt_message _("Committing changes...");
            i = mutt_copy_stream(fp, ctx->fp);

            if (ferror(ctx->fp))
                i = -1;
        }

        if (i == 0) {
            ctx->size = ftello(ctx->fp); /* update the size of the mailbox */
            ftruncate(fileno(ctx->fp), ctx->size);
        }
    }

    safe_fclose(&fp);
    fp = NULL;
    mbox_unlock_mailbox(ctx);

    if ((fclose(ctx->fp) != 0)
        || (i == -1)) {
        /* error occurred while writing the mailbox back, so keep the temp copy
         * around
         */

        char savefile[_POSIX_PATH_MAX];

        snprintf(savefile, sizeof(savefile), "%s/mutt.%s-%s-%u",
                 NONULL(Tempdir), NONULL(Username), NONULL(Hostname),
                 (unsigned int)getpid());
        rename(tempfile, savefile);
        mutt_unblock_signals();
        mx_fastclose_mailbox(ctx);
        mutt_pretty_mailbox(savefile, sizeof(savefile));
        mutt_error(_("Write failed!  Saved partial mailbox to %s"), savefile);
        mutt_sleep(5);
        return -1;
    }

    /* Restore the previous access/modification times */
    mbox_reset_atime(ctx, &statbuf);

    /* reopen the mailbox in read-only mode */
    if ((ctx->fp = fopen(ctx->path, "r")) == NULL) {
        unlink(tempfile);
        mutt_unblock_signals();
        mx_fastclose_mailbox(ctx);
        mutt_error _("Fatal error!  Could not reopen mailbox!");
        return -1;
    }

    /* update the offsets of the rewritten messages */
    for (i = first, j = first; i < ctx->msgcount; i++) {
        if (!ctx->hdrs[i]->deleted) {
            ctx->hdrs[i]->offset = newOffset[i - first].hdr;
            ctx->hdrs[i]->content->hdr_offset = newOffset[i - first].hdr;
            ctx->hdrs[i]->content->offset = newOffset[i - first].body;
            ctx->hdrs[i]->index = j++;
        }
    }
    safe_free(&newOffset);
    safe_free(&oldOffset);
    unlink(tempfile); /* remove partial copy of the mailbox */
    mutt_unblock_signals();

    return 0;         /* signal success */

    bail:             /* Come here in case of disaster */

    safe_fclose(&fp);

    /* restore offsets, as far as they are valid */
    if ((first >= 0)
        && oldOffset) {
        for (i = first; i < ctx->msgcount
             && oldOffset[i - first].valid; i++) {
            ctx->hdrs[i]->offset = oldOffset[i - first].hdr;
            ctx->hdrs[i]->content->hdr_offset = oldOffset[i - first].hdr;
            ctx->hdrs[i]->content->offset = oldOffset[i - first].body;
            ctx->hdrs[i]->lines = oldOffset[i - first].lines;
            ctx->hdrs[i]->content->length = oldOffset[i - first].length;
        }
    }

    /* this is ok to call even if we haven't locked anything */
    mbox_unlock_mailbox(ctx);

    mutt_unblock_signals();
    safe_free(&newOffset);
    safe_free(&oldOffset);

    if ((ctx->fp = freopen(ctx->path, "r", ctx->fp)) == NULL) {
        mutt_error _("Could not reopen mailbox!");
        mx_fastclose_mailbox(ctx);
        return -1;
    }

    if (need_sort)
        /* if the mailbox was reopened, the thread tree will be invalid so make
         * sure to start threading from scratch.  */
        mutt_sort_headers(ctx, (need_sort == M_REOPENED));

    return rc;
}
コード例 #12
0
ファイル: mbox.cpp プロジェクト: badeip/neomutt
int mmdf_parse_mailbox(CONTEXT *ctx)
{
    char buf[HUGE_STRING];
    char return_path[LONG_STRING];
    int count = 0, oldmsgcount = ctx->msgcount;
    int lines;
    time_t t;
    LOFF_T loc, tmploc;
    HEADER *hdr;
    struct stat sb;

#ifdef NFS_ATTRIBUTE_HACK
    struct utimbuf newtime;
#endif /* ifdef NFS_ATTRIBUTE_HACK */
    progress_t progress;
    char msgbuf[STRING];

    if (stat(ctx->path, &sb) == -1) {
        mutt_perror(ctx->path);
        return -1;
    }
    ctx->atime = sb.st_atime;
    ctx->mtime = sb.st_mtime;
    ctx->size = sb.st_size;

#ifdef NFS_ATTRIBUTE_HACK

    if (sb.st_mtime > sb.st_atime) {
        newtime.modtime = sb.st_mtime;
        newtime.actime = time(NULL);
        utime(ctx->path, &newtime);
    }
#endif /* ifdef NFS_ATTRIBUTE_HACK */

    buf[sizeof(buf) - 1] = 0;

    if (!ctx->quiet) {
        snprintf(msgbuf, sizeof(msgbuf), _("Reading %s..."), ctx->path);
        mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG, ReadInc, 0);
    }

    FOREVER
    {
        if (fgets(buf, sizeof(buf) - 1, ctx->fp) == NULL)
            break;

        if (mutt_strcmp(buf, MMDF_SEP) == 0) {
            loc = ftello(ctx->fp);

            count++;

            if (!ctx->quiet)
                mutt_progress_update(&progress, count,
                                     (int)(loc / (ctx->size / 100 + 1)));

            if (ctx->msgcount == ctx->hdrmax)
                mx_alloc_memory(ctx);
            ctx->hdrs[ctx->msgcount] = hdr = mutt_new_header();
            hdr->offset = loc;
            hdr->index = ctx->msgcount;

            if (fgets(buf, sizeof(buf) - 1, ctx->fp) == NULL) {
                /* TODO: memory leak??? */
                dprint(1, "mmdf_parse_mailbox: unexpected EOF\n");
                break;
            }

            return_path[0] = 0;

            if (!is_from(buf, return_path, sizeof(return_path), &t)) {
                if (fseeko(ctx->fp, loc, SEEK_SET) != 0) {
                    dprint(1, "mmdf_parse_mailbox: fseek() failed\n");
                    mutt_error _("Mailbox is corrupt!");
                    return -1;
                }
            } else
                hdr->received = t - mutt_local_tz(t);

            hdr->env = mutt_read_rfc822_header(ctx->fp, hdr, 0, 0);

            loc = ftello(ctx->fp);

            if ((hdr->content->length > 0)
                && (hdr->lines > 0)) {
                tmploc = loc + hdr->content->length;

                if ((0 < tmploc)
                    && (tmploc < ctx->size)) {
                    if ((fseeko(ctx->fp, tmploc, SEEK_SET) != 0)
                        || (fgets(buf, sizeof(buf) - 1, ctx->fp) == NULL)
                        || (mutt_strcmp(MMDF_SEP, buf) != 0)) {
                        if (fseeko(ctx->fp, loc, SEEK_SET) != 0)
                            dprint(1, "mmdf_parse_mailbox: fseek() failed\n");
                        hdr->content->length = -1;
                    }
                } else
                    hdr->content->length = -1;
            } else
                hdr->content->length = -1;

            if (hdr->content->length < 0) {
                lines = -1;

                do {
                    loc = ftello(ctx->fp);

                    if (fgets(buf, sizeof(buf) - 1, ctx->fp) == NULL)
                        break;
                    lines++;
                } while (mutt_strcmp(buf, MMDF_SEP) != 0);

                hdr->lines = lines;
                hdr->content->length = loc - hdr->content->offset;
            }

            if (!hdr->env->return_path
                && return_path[0])
                hdr->env->return_path = rfc822_parse_adrlist(
                    hdr->env->return_path,
                    return_path);

            if (!hdr->env->from)
                hdr->env->from = rfc822_cpy_adr(hdr->env->return_path, 0);

            ctx->msgcount++;
        } else {
            dprint(1, "mmdf_parse_mailbox: corrupt mailbox!\n");
            mutt_error _("Mailbox is corrupt!");
            return -1;
        }
    }

    if (ctx->msgcount > oldmsgcount)
        mx_update_context(ctx, ctx->msgcount - oldmsgcount);

    return 0;
}
コード例 #13
0
ファイル: mbox.cpp プロジェクト: badeip/neomutt
/* Note that this function is also called when new mail is appended to the
 * currently open folder, and NOT just when the mailbox is initially read.
 *
 * NOTE: it is assumed that the mailbox being read has been locked before
 * this routine gets called.  Strange things could happen if it's not!
 */
int mbox_parse_mailbox(CONTEXT *ctx)
{
    struct stat sb;
    char buf[HUGE_STRING], return_path[STRING];
    HEADER *curhdr;
    time_t t;
    int count = 0, lines = 0;
    LOFF_T loc;

#ifdef NFS_ATTRIBUTE_HACK
    struct utimbuf newtime;
#endif /* ifdef NFS_ATTRIBUTE_HACK */
    progress_t progress;
    char msgbuf[STRING];

    /* Save information about the folder at the time we opened it. */
    if (stat(ctx->path, &sb) == -1) {
        mutt_perror(ctx->path);
        return -1;
    }

    ctx->size = sb.st_size;
    ctx->mtime = sb.st_mtime;
    ctx->atime = sb.st_atime;

#ifdef NFS_ATTRIBUTE_HACK

    if (sb.st_mtime > sb.st_atime) {
        newtime.modtime = sb.st_mtime;
        newtime.actime = time(NULL);
        utime(ctx->path, &newtime);
    }
#endif /* ifdef NFS_ATTRIBUTE_HACK */

    if (!ctx->readonly)
        ctx->readonly = access(ctx->path, W_OK) ? 1 : 0;

    if (!ctx->quiet) {
        snprintf(msgbuf, sizeof(msgbuf), _("Reading %s..."), ctx->path);
        mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG, ReadInc, 0);
    }

    loc = ftello(ctx->fp);

    while (fgets(buf, sizeof(buf), ctx->fp) != NULL) {
        if (is_from(buf, return_path, sizeof(return_path), &t)) {
            /* Save the Content-Length of the previous message */
            if (count > 0) {
#define PREV ctx->hdrs[ctx->msgcount - 1]

                if (PREV->content->length < 0) {
                    PREV->content->length = loc - PREV->content->offset - 1;

                    if (PREV->content->length < 0)
                        PREV->content->length = 0;
                }

                if (!PREV->lines)
                    PREV->lines = lines ? lines - 1 : 0;
            }

            count++;

            if (!ctx->quiet)
                mutt_progress_update(&progress, count,
                                     (int)(ftello(ctx->fp) /
                                           (ctx->size / 100 + 1)));

            if (ctx->msgcount == ctx->hdrmax)
                mx_alloc_memory(ctx);

            curhdr = ctx->hdrs[ctx->msgcount] = mutt_new_header();
            curhdr->received = t - mutt_local_tz(t);
            curhdr->offset = loc;
            curhdr->index = ctx->msgcount;

            curhdr->env = mutt_read_rfc822_header(ctx->fp, curhdr, 0, 0);

            /* if we know how long this message is, either just skip over the
               body,
             * or if we don't know how many lines there are, count them now
             *(this will
             * save time by not having to search for the next message marker).
             */
            if (curhdr->content->length > 0) {
                LOFF_T tmploc;

                loc = ftello(ctx->fp);
                tmploc = loc + curhdr->content->length + 1;

                if ((0 < tmploc)
                    && (tmploc < ctx->size)) {
                    /*
                     * check to see if the content-length looks valid.  we
                     *expect to
                     * to see a valid message separator at this point in the
                     *stream
                     */
                    if ((fseeko(ctx->fp, tmploc, SEEK_SET) != 0)
                        || (fgets(buf, sizeof(buf), ctx->fp) == NULL)
                        || (mutt_strncmp("From ", buf, 5) != 0)) {
                        dprint(1, "mbox_parse_mailbox: bad content-length in message %d (cl="
                                OFF_T_FMT ")\n", curhdr->index, curhdr->content->length);
                        dprint(1, "\tLINE: %s", buf);

                        if (fseeko(ctx->fp, loc, SEEK_SET) != 0) { /* nope,
                                                                      return the
                                                                      previous
                                                                      position
                                                                      */
                            dprint(1, "mbox_parse_mailbox: fseek() failed\n");
                        }
                        curhdr->content->length = -1;
                    }
                } else if (tmploc != ctx->size) {
                    /* content-length would put us past the end of the file, so
                       it
                     * must be wrong
                     */
                    curhdr->content->length = -1;
                }

                if (curhdr->content->length != -1) {
                    /* good content-length.  check to see if we know how many
                       lines
                     * are in this message.
                     */
                    if (curhdr->lines == 0) {
                        int cl = curhdr->content->length;

                        /* count the number of lines in this message */
                        if (fseeko(ctx->fp, loc, SEEK_SET) != 0)
                            dprint(1, "mbox_parse_mailbox: fseek() failed\n");

                        while (cl-- > 0) {
                            if (fgetc(ctx->fp) == '\n')
                                curhdr->lines++;
                        }
                    }

                    /* return to the offset of the next message separator */
                    if (fseeko(ctx->fp, tmploc, SEEK_SET) != 0)
                        dprint(1, "mbox_parse_mailbox: fseek() failed\n");
                }
            }

            ctx->msgcount++;

            if (!curhdr->env->return_path
                && return_path[0])
                curhdr->env->return_path = rfc822_parse_adrlist(
                    curhdr->env->return_path,
                    return_path);

            if (!curhdr->env->from)
                curhdr->env->from = rfc822_cpy_adr(curhdr->env->return_path, 0);


            lines = 0;
        } else
            lines++;

        loc = ftello(ctx->fp);
    }

    /*
     * Only set the content-length of the previous message if we have read more
     * than one message during _this_ invocation.  If this routine is called
     * when new mail is received, we need to make sure not to clobber what
     * previously was the last message since the headers may be sorted.
     */
    if (count > 0) {
        if (PREV->content->length < 0) {
            PREV->content->length = ftello(ctx->fp) - PREV->content->offset - 1;

            if (PREV->content->length < 0)
                PREV->content->length = 0;
        }

        if (!PREV->lines)
            PREV->lines = lines ? lines - 1 : 0;

        mx_update_context(ctx, count);
    }

    return 0;
}
コード例 #14
0
ファイル: pop.cpp プロジェクト: badeip/neomutt
/*
 * Read headers
 * returns:
 *  0 on success
 * -1 - connection lost,
 * -2 - invalid command or execution error,
 * -3 - error writing to tempfile
 */
static int pop_fetch_headers(CONTEXT *ctx)
{
    int i, ret, old_count, new_count, deleted;
    unsigned short hcached = 0, bcached;
    POP_DATA *pop_data = (POP_DATA *)ctx->data;
    progress_t progress;

    time(&pop_data->check_time);
    pop_data->clear_cache = 0;

    for (i = 0; i < ctx->msgcount; i++)
        ctx->hdrs[i]->refno = -1;

    old_count = ctx->msgcount;
    ret = pop_fetch_data(pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx);
    new_count = ctx->msgcount;
    ctx->msgcount = old_count;

    if (pop_data->cmd_uidl == 2) {
        if (ret == 0) {
            pop_data->cmd_uidl = 1;

            dprint(1, "pop_fetch_headers: set UIDL capability\n");
        }

        if ((ret == -2)
            && (pop_data->cmd_uidl == 2)) {
            pop_data->cmd_uidl = 0;

            dprint(1, "pop_fetch_headers: unset UIDL capability\n");
            snprintf(pop_data->err_msg, sizeof(pop_data->err_msg),
                     _("Command UIDL is not supported by server."));
        }
    }

    if (!ctx->quiet)
        mutt_progress_init(&progress, _("Fetching message headers..."),
                           M_PROGRESS_MSG, ReadInc, new_count - old_count);

    if (ret == 0) {
        for (i = 0, deleted = 0; i < old_count; i++) {
            if (ctx->hdrs[i]->refno == -1) {
                ctx->hdrs[i]->deleted = 1;
                deleted++;
            }
        }

        if (deleted > 0) {
            mutt_error(_(
                           "%d messages have been lost. Try reopening the mailbox."),
                       deleted);
            mutt_sleep(2);
        }

        for (i = old_count; i < new_count; i++) {
            if (!ctx->quiet)
                mutt_progress_update(&progress, i + 1 - old_count, -1);
            if ((ret = pop_read_header(pop_data, ctx->hdrs[i])) < 0)
                break;
            /*
             * faked support for flags works like this:
             * - if 'hcached' is 1, we have the message in our hcache:
             *        - if we also have a body: read
             *        - if we don't have a body: old
             *          (if $mark_old is set which is maybe wrong as
             *          $mark_old should be considered for syncing the
             *          folder and not when opening it XXX)
             * - if 'hcached' is 0, we don't have the message in our hcache:
             *        - if we also have a body: read
             *        - if we don't have a body: new
             */
            bcached =
                mutt_bcache_exists(pop_data->bcache, ctx->hdrs[i]->data) == 0;
            ctx->hdrs[i]->old = 0;
            ctx->hdrs[i]->read = 0;

            if (hcached) {
                if (bcached)
                    ctx->hdrs[i]->read = 1;
                else if (option(OPTMARKOLD))
                    ctx->hdrs[i]->old = 1;
            } else {
                if (bcached)
                    ctx->hdrs[i]->read = 1;
            }

            ctx->msgcount++;
        }

        if (i > old_count)
            mx_update_context(ctx, i - old_count);
    }

    if (ret < 0) {
        for (i = ctx->msgcount; i < new_count; i++)
            mutt_free_header(&ctx->hdrs[i]);
        return ret;
    }

    /* after putting the result into our structures,
     * clean up cache, i.e. wipe messages deleted outside
     * the availability of our cache
     */
    if (option(OPTMESSAGECACHECLEAN))
        mutt_bcache_list(pop_data->bcache, msg_cache_check, (void *)ctx);

    mutt_clear_error();
    return new_count - old_count;
}
コード例 #15
0
ファイル: pop.c プロジェクト: harishpillay/mutt-kz
/* update POP mailbox - delete messages from server */
int pop_sync_mailbox (CONTEXT *ctx, int *index_hint)
{
  int i, j, ret = 0;
  char buf[LONG_STRING];
  POP_DATA *pop_data = (POP_DATA *)ctx->data;
  progress_t progress;
#ifdef USE_HCACHE
  header_cache_t *hc = NULL;
#endif

  pop_data->check_time = 0;

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

    mutt_progress_init (&progress, _("Marking messages deleted..."),
			M_PROGRESS_MSG, WriteInc, ctx->deleted);

#if USE_HCACHE
    hc = pop_hcache_open (pop_data, ctx->path);
#endif

    for (i = 0, j = 0, ret = 0; ret == 0 && i < ctx->msgcount; i++)
    {
      if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->refno != -1)
      {
	j++;
	if (!ctx->quiet)
	  mutt_progress_update (&progress, j, -1);
	snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno);
	if ((ret = pop_query (pop_data, buf, sizeof (buf))) == 0)
	{
	  mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data);
#if USE_HCACHE
	  mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen);
#endif
	}
      }

#if USE_HCACHE
      if (ctx->hdrs[i]->changed)
      {
	mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY);
      }
#endif

    }

#if USE_HCACHE
    mutt_hcache_close (hc);
#endif

    if (ret == 0)
    {
      strfcpy (buf, "QUIT\r\n", sizeof (buf));
      ret = pop_query (pop_data, buf, sizeof (buf));
    }

    if (ret == 0)
    {
      pop_data->clear_cache = 1;
      pop_clear_cache (pop_data);
      pop_data->status = POP_DISCONNECTED;
      return 0;
    }

    if (ret == -2)
    {
      mutt_error ("%s", pop_data->err_msg);
      mutt_sleep (2);
      return -1;
    }
  }
}
コード例 #16
0
ファイル: pop.c プロジェクト: harishpillay/mutt-kz
/*
 * Read headers
 * returns:
 *  0 on success
 * -1 - conection lost,
 * -2 - invalid command or execution error,
 * -3 - error writing to tempfile
 */
static int pop_fetch_headers (CONTEXT *ctx)
{
  int i, ret, old_count, new_count, deleted;
  unsigned short hcached = 0, bcached;
  POP_DATA *pop_data = (POP_DATA *)ctx->data;
  progress_t progress;

#ifdef USE_HCACHE
  header_cache_t *hc = NULL;
  void *data;

  hc = pop_hcache_open (pop_data, ctx->path);
#endif

  time (&pop_data->check_time);
  pop_data->clear_cache = 0;

  for (i = 0; i < ctx->msgcount; i++)
    ctx->hdrs[i]->refno = -1;

  old_count = ctx->msgcount;
  ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx);
  new_count = ctx->msgcount;
  ctx->msgcount = old_count;

  if (pop_data->cmd_uidl == 2)
  {
    if (ret == 0)
    {
      pop_data->cmd_uidl = 1;

      dprint (1, (debugfile, "pop_fetch_headers: set UIDL capability\n"));
    }

    if (ret == -2 && pop_data->cmd_uidl == 2)
    {
      pop_data->cmd_uidl = 0;

      dprint (1, (debugfile, "pop_fetch_headers: unset UIDL capability\n"));
      snprintf (pop_data->err_msg, sizeof (pop_data->err_msg),
	      _("Command UIDL is not supported by server."));
    }
  }

  if (!ctx->quiet)
    mutt_progress_init (&progress, _("Fetching message headers..."),
                        M_PROGRESS_MSG, ReadInc, new_count - old_count);

  if (ret == 0)
  {
    for (i = 0, deleted = 0; i < old_count; i++)
    {
      if (ctx->hdrs[i]->refno == -1)
      {
	ctx->hdrs[i]->deleted = 1;
	deleted++;
      }
    }
    if (deleted > 0)
    {
      mutt_error (_("%d messages have been lost. Try reopening the mailbox."),
		  deleted);
      mutt_sleep (2);
    }

    for (i = old_count; i < new_count; i++)
    {
      if (!ctx->quiet)
	mutt_progress_update (&progress, i + 1 - old_count, -1);
#if USE_HCACHE
      if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen)))
      {
	char *uidl = safe_strdup (ctx->hdrs[i]->data);
	int refno = ctx->hdrs[i]->refno;
	int index = ctx->hdrs[i]->index;
	/*
	 * - POP dynamically numbers headers and relies on h->refno
	 *   to map messages; so restore header and overwrite restored
	 *   refno with current refno, same for index
	 * - h->data needs to a separate pointer as it's driver-specific
	 *   data freed separately elsewhere
	 *   (the old h->data should point inside a malloc'd block from
	 *   hcache so there shouldn't be a memleak here)
	 */
	HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL);
	mutt_free_header (&ctx->hdrs[i]);
	ctx->hdrs[i] = h;
	ctx->hdrs[i]->refno = refno;
	ctx->hdrs[i]->index = index;
	ctx->hdrs[i]->data = uidl;
	ret = 0;
	hcached = 1;
      }
      else
#endif
      if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0)
	break;
#if USE_HCACHE
      else
      {
	mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY);
      }

      FREE(&data);
#endif

      /*
       * faked support for flags works like this:
       * - if 'hcached' is 1, we have the message in our hcache:
       *        - if we also have a body: read
       *        - if we don't have a body: old
       *          (if $mark_old is set which is maybe wrong as
       *          $mark_old should be considered for syncing the
       *          folder and not when opening it XXX)
       * - if 'hcached' is 0, we don't have the message in our hcache:
       *        - if we also have a body: read
       *        - if we don't have a body: new
       */
      bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0;
      ctx->hdrs[i]->old = 0;
      ctx->hdrs[i]->read = 0;
      if (hcached)
      {
        if (bcached)
          ctx->hdrs[i]->read = 1;
        else if (option (OPTMARKOLD))
          ctx->hdrs[i]->old = 1;
      }
      else
      {
        if (bcached)
          ctx->hdrs[i]->read = 1;
      }

      ctx->msgcount++;
    }

    if (i > old_count)
      mx_update_context (ctx, i - old_count);
  }

#if USE_HCACHE
    mutt_hcache_close (hc);
#endif

  if (ret < 0)
  {
    for (i = ctx->msgcount; i < new_count; i++)
      mutt_free_header (&ctx->hdrs[i]);
    return ret;
  }

  /* after putting the result into our structures,
   * clean up cache, i.e. wipe messages deleted outside
   * the availability of our cache
   */
  if (option (OPTMESSAGECACHECLEAN))
    mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx);

  mutt_clear_error ();
  return (new_count - old_count);
}