📄 mbox.c
字号:
if ((ctx->magic == M_MBOX && mutt_strncmp ("From ", buffer, 5) == 0) || (ctx->magic == M_MMDF && mutt_strcmp (MMDF_SEP, buffer) == 0)) { if (fseeko (ctx->fp, ctx->size, SEEK_SET) != 0) dprint (1, (debugfile, "mbox_check_mailbox: fseek() failed\n")); if (ctx->magic == M_MBOX) mbox_parse_mailbox (ctx); else mmdf_parse_mailbox (ctx); /* Only unlock the folder if it was locked inside of this routine. * It may have been locked elsewhere, like in * mutt_checkpoint_mailbox(). */ if (unlock) { mbox_unlock_mailbox (ctx); mutt_unblock_signals (); } return (M_NEW_MAIL); /* signal that new mail arrived */ } else modified = 1; } else { dprint (1, (debugfile, "mbox_check_mailbox: fgets returned NULL.\n")); modified = 1; } } else modified = 1; } if (modified) { if (mutt_reopen_mailbox (ctx, index_hint) != -1) { if (unlock) { mbox_unlock_mailbox (ctx); mutt_unblock_signals (); } return (M_REOPENED); } } /* fatal error */ mbox_unlock_mailbox (ctx); mx_fastclose_mailbox (ctx); mutt_unblock_signals (); mutt_error _("Mailbox was corrupted!"); return (-1);}/* 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 utimbuf utimebuf; struct m_update_t *newOffset = NULL; struct m_update_t *oldOffset = NULL; FILE *fp = NULL; /* 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); 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, (debugfile, "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 = safe_calloc (ctx->msgcount - first, sizeof (struct m_update_t)); oldOffset = safe_calloc (ctx->msgcount - first, sizeof (struct m_update_t)); for (i = first, j = 0; i < ctx->msgcount; i++) { /* * 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->quiet && WriteInc && ((i % WriteInc) == 0 || j == 1)) mutt_message (_("Writing messages... %d (%d%%)"), i, (int)(ftell (ctx->fp) / (ctx->size / 100 + 1))); 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) == -1) { 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, (debugfile, "mbox_sync_mailbox: 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, (debugfile, "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, (debugfile, "mbox_sync_mailbox: message not in expected position.")); dprint (1, (debugfile, "\tLINE: %s\n", buf)); i = -1; } else { if (fseeko (ctx->fp, offset, SEEK_SET) != 0) /* return to proper offset */ { i = -1; dprint (1, (debugfile, "mbox_sync_mailbox: fseek() failed\n")); } else { /* copy the temp mailbox back into place starting at the first * change/deleted message */ 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); } } fclose (fp); fp = NULL; mbox_unlock_mailbox (ctx); if (fclose (ctx->fp) != 0 || i == -1) { /* error occured 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); mutt_error (_("Write failed! Saved partial mailbox to %s"), savefile); mutt_sleep (5); return (-1); } /* Restore the previous access/modification times */ utimebuf.actime = statbuf.st_atime; utimebuf.modtime = statbuf.st_mtime; utime (ctx->path, &utimebuf); /* 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++; } } FREE (&newOffset); 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 (); FREE (&newOffset); 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;}/* close a mailbox opened in write-mode */int mbox_close_mailbox (CONTEXT *ctx){ mx_unlock_file (ctx->path, fileno (ctx->fp), 1); mutt_unblock_signals (); mx_fastclose_mailbox (ctx); return 0;}int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint){ int (*cmp_headers) (const HEADER *, const HEADER *) = NULL; HEADER **old_hdrs; int old_msgcount; int msg_mod = 0; int index_hint_set; int i, j; int rc = -1; /* silent operations */ ctx->quiet = 1; mutt_message _("Reopening mailbox..."); /* our heuristics require the old mailbox to be unsorted */ if (Sort != SORT_ORDER) { short old_sort; old_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers (ctx, 1); Sort = old_sort; } old_hdrs = NULL; old_msgcount = 0; /* simulate a close */ if (ctx->id_hash) hash_destroy (&ctx->id_hash, NULL); if (ctx->subj_hash) hash_destroy (&ctx->subj_hash, NULL); mutt_clear_threads (ctx); FREE (&ctx->v2r); if (ctx->readonly) { for (i = 0; i < ctx->msgcount; i++) mutt_free_header (&(ctx->hdrs[i])); /* nothing to do! */ FREE (&ctx->hdrs); } else { /* save the old headers */ old_msgcount = ctx->msgcount; old_hdrs = ctx->hdrs; ctx->hdrs = NULL; } ctx->hdrmax = 0; /* force allocation of new headers */ ctx->msgcount = 0; ctx->vcount = 0; ctx->tagged = 0; ctx->deleted = 0; ctx->new = 0; ctx->unread = 0; ctx->flagged = 0; ctx->changed = 0; ctx->id_hash = NULL; ctx->subj_hash = NULL; switch (ctx->magic) { case M_MBOX: case M_MMDF: if (fseek (ctx->fp, 0, SEEK_SET) != 0) { dprint (1, (debugfile, "mutt_reopen_mailbox: fseek() failed\n")); rc = -1; } else { cmp_headers = mbox_strict_cmp_headers; rc = ((ctx->magic == M_MBOX) ? mbox_parse_mailbox : mmdf_parse_mailbox) (ctx); } break; default: rc = -1; break; } if (rc == -1) { /* free the old headers */ for (j = 0; j < old_msgcount; j++) mutt_free_header (&(old_hdrs[j])); FREE (&old_hdrs); ctx->quiet = 0; return (-1); } /* now try to recover the old flags */ index_hint_set = (index_hint == NULL); if (!ctx->readonly) { for (i = 0; i < ctx->msgcount; i++) { int found = 0; /* some messages have been deleted, and new messages have been * appended at the end; the heuristic is that old messages have then * "advanced" towards the beginning of the folder, so we begin the * search at index "i" */ for (j = i; j < old_msgcount; j++) { if (old_hdrs[j] == NULL) continue; if (cmp_headers (ctx->hdrs[i], old_hdrs[j])) { found = 1; break; } } if (!found) { for (j = 0; j < i && j < old_msgcount; j++) { if (old_hdrs[j] == NULL) continue; if (cmp_headers (ctx->hdrs[i], old_hdrs[j])) { found = 1; break; } } } if (found) { /* this is best done here */ if (!index_hint_set && *index_hint == j) *index_hint = i; if (old_hdrs[j]->changed) { /* Only update the flags if the old header was changed; * otherwise, the header may have been modified externally, * and we don't want to lose _those_ changes */ mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged); mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied); mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old); mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read); } mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted); mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged); /* we don't need this header any more */ mutt_free_header (&(old_hdrs[j])); } } /* free the remaining old headers */ for (j = 0; j < old_msgcount; j++) { if (old_hdrs[j]) { mutt_free_header (&(old_hdrs[j])); msg_mod = 1; } } FREE (&old_hdrs); } ctx->quiet = 0; return ((ctx->changed || msg_mod) ? M_REOPENED : M_NEW_MAIL);}/* * Returns: * 1 if the mailbox is not empty * 0 if the mailbox is empty * -1 on error */int mbox_check_empty (const char *path){ struct stat st; if (stat (path, &st) == -1) return -1; return ((st.st_size == 0));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -