Example #1
0
static void maildir_add_to_context(CONTEXT *ctx, struct maildir *md)
{
  while(md)
  {
    
    dprint(2, (debugfile, "%s:%d maildir_add_to_context(): Considering %s\n",
	       __FILE__, __LINE__, md->canon_fname));
    
    if(md->h)
    {

      dprint(2, (debugfile, "%s:%d Adding header structure. Flags: %s%s%s%s%s\n", __FILE__, __LINE__,
		 md->h->flagged ? "f" : "",
		 md->h->deleted ? "D" : "",
		 md->h->replied ? "r" : "",
		 md->h->old     ? "O" : "",
		 md->h->read    ? "R" : ""));
      if(ctx->msgcount == ctx->hdrmax)
	mx_alloc_memory(ctx);
      
      ctx->hdrs[ctx->msgcount] = md->h;
      ctx->hdrs[ctx->msgcount]->index = ctx->msgcount;
      ctx->size +=
	md->h->content->length + md->h->content->offset - md->h->content->hdr_offset;
      
      md->h = NULL;
      mx_update_context(ctx);
    }
    md = md->next;
  }
}
Example #2
0
int nm_read_entire_thread(CONTEXT *ctx, HEADER *h)
{
    struct nm_ctxdata *data = get_ctxdata(ctx);
    const char *id;
    char *qstr = NULL;
    notmuch_query_t *q = NULL;
    notmuch_database_t *db = NULL;
    notmuch_message_t *msg = NULL;
    int rc = -1;

    if (!data)
        return -1;
    if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h)))
        goto done;

    dprint(1, (debugfile, "nm: reading entire-thread messages...[current count=%d]\n",
               ctx->msgcount));

    nm_progress_reset(ctx);
    id = notmuch_message_get_thread_id(msg);
    if (!id)
        goto done;
    append_str_item(&qstr, "thread:", 0);
    append_str_item(&qstr, id, 0);

    q = notmuch_query_create(db, qstr);
    FREE(&qstr);
    if (!q)
        goto done;
    apply_exclude_tags(q);
    notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);

    read_threads_query(ctx, q, 1, 0);
    ctx->mtime = time(NULL);
    rc = 0;

    if (ctx->msgcount > data->oldmsgcount)
        mx_update_context(ctx, ctx->msgcount - data->oldmsgcount);
done:
    if (q)
        notmuch_query_destroy(q);
    if (!is_longrun(data))
        release_db(data);

    if (ctx->msgcount == data->oldmsgcount)
        mutt_message _("No more messages in the thread.");

    data->oldmsgcount = 0;
    dprint(1, (debugfile, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
               rc, ctx->msgcount));
    return rc;
}
Example #3
0
int nm_read_query(CONTEXT *ctx)
{
    notmuch_query_t *q;
    struct nm_ctxdata *data;
    int rc = -1;

    if (init_context(ctx) != 0)
        return -1;

    data = get_ctxdata(ctx);
    if (!data)
        return -1;

    dprint(1, (debugfile, "nm: reading messages...[current count=%d]\n",
               ctx->msgcount));

    nm_progress_reset(ctx);

    q = get_query(data, FALSE);
    if (q) {
        switch(get_query_type(data)) {
        case NM_QUERY_TYPE_MESGS:
            read_mesgs_query(ctx, q, 0);
            break;
        case NM_QUERY_TYPE_THREADS:
            read_threads_query(ctx, q, 0, get_limit(data));
            break;
        }
        notmuch_query_destroy(q);
        rc = 0;

    }

    if (!is_longrun(data))
        release_db(data);

    ctx->mtime = time(NULL);

    mx_update_context(ctx, ctx->msgcount);
    data->oldmsgcount = 0;

    dprint(1, (debugfile, "nm: reading messages... done [rc=%d, count=%d]\n",
               rc, ctx->msgcount));
    return rc;
}
Example #4
0
/* 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;
}
Example #5
0
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;
}
Example #6
0
/* 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;
}
Example #7
0
/*
 * 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;
}
Example #8
0
/*
 * 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);
}