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; } }
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; }
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; }
/* 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; }
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; }
/* 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; }
/* * 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; }
/* * 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); }