Example #1
0
/* open a mbox or mmdf style mailbox */
int mbox_open_mailbox(CONTEXT *ctx)
{
    int rc;

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

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

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

    mbox_unlock_mailbox(ctx);
    mutt_unblock_signals();
    return rc;
}
Example #2
0
/* return 0 on success, -1 on failure */
int mutt_sync_compressed (CONTEXT * ctx)
{
    char *cmd;
    int rc = 0;
    FILE *fp;
    COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;

    if (!ctx->quiet)
        mutt_message (_("Compressing %s..."), ctx->realpath);

    cmd = get_compression_cmd (ci->close, ctx);
    if (cmd == NULL)
        return (-1);

    if ((fp = fopen (ctx->realpath, "a")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        store_size (ctx);

        mem_free (&cmd);
        return (-1);
    }

    debug_print (2, ("CompressCommand: '%s'\n", cmd));

    endwin ();
    fflush (stdout);
    sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
    mutt_system (echo_cmd);
    if (mutt_system (cmd)) {
        mutt_any_key_to_continue (NULL);
        mutt_error (_
                    ("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"),
                    ctx->path);
        rc = -1;
    }

    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);

    mem_free (&cmd);

    store_size (ctx);

    return (rc);
}
Example #3
0
/* 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;
}
Example #4
0
int mutt_slow_close_compressed (CONTEXT * ctx)
{
    FILE *fp;
    const char *append;
    char *cmd;
    COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;

    debug_print (2, ("called on '%s'\n", ctx->path));

    if (!(ctx->append && ((append = get_append_command (ctx->realpath, ctx))
                          || (append = ci->close)))) {
        /* if we can not or should not append,
                                         * we only have to remove the compressed info, because sync was already
                                         * called
                                         */
        mutt_fast_close_compressed (ctx);
        return (0);
    }

    if (ctx->fp)
        fclose (ctx->fp);
    ctx->fp = NULL;

    if (!ctx->quiet) {
        if (append == ci->close)
            mutt_message (_("Compressing %s..."), ctx->realpath);
        else
            mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
    }

    cmd = get_compression_cmd (append, ctx);
    if (cmd == NULL)
        return (-1);

    if ((fp = fopen (ctx->realpath, "a")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        mem_free (&cmd);
        return (-1);
    }

    debug_print (2, ("CompressCmd: '%s'\n", cmd));

    endwin ();
    fflush (stdout);

    if (append == ci->close)
        sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
    else
        sprintf (echo_cmd, _("echo Compressed-appending to %s..."),
                 ctx->realpath);
    mutt_system (echo_cmd);

    if (mutt_system (cmd)) {
        mutt_any_key_to_continue (NULL);
        mutt_error (_
                    (" %s: Error compressing mailbox!  Uncompressed one kept!\n"),
                    ctx->path);
        mem_free (&cmd);
        mbox_unlock_compressed (ctx, fp);
        mutt_unblock_signals ();
        fclose (fp);
        return (-1);
    }

    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);
    remove_file (ctx);
    restore_path (ctx);
    mem_free (&cmd);
    mem_free (&ctx->compressinfo);

    return (0);
}
Example #5
0
int mutt_open_read_compressed (CONTEXT * ctx)
{
    char *cmd;
    FILE *fp;
    int rc;

    COMPRESS_INFO *ci = set_compress_info (ctx);

    if (!ci->open) {
        ctx->magic = 0;
        mem_free (ctx->compressinfo);
        return (-1);
    }
    if (!ci->close || access (ctx->path, W_OK) != 0)
        ctx->readonly = 1;

    set_path (ctx);
    store_size (ctx);

    if (!ctx->quiet)
        mutt_message (_("Decompressing %s..."), ctx->realpath);

    cmd = get_compression_cmd (ci->open, ctx);
    if (cmd == NULL)
        return (-1);
    debug_print (2, ("DecompressCmd: '%s'\n", cmd));

    if ((fp = fopen (ctx->realpath, "r")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 0, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        mem_free (&cmd);
        return (-1);
    }

    endwin ();
    fflush (stdout);
    sprintf (echo_cmd, _("echo Decompressing %s..."), ctx->realpath);
    mutt_system (echo_cmd);
    rc = mutt_system (cmd);
    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);

    if (rc) {
        mutt_any_key_to_continue (NULL);
        ctx->magic = 0;
        mem_free (ctx->compressinfo);
        mutt_error (_("Error executing: %s : unable to open the mailbox!\n"),
                    cmd);
    }
    mem_free (&cmd);
    if (rc)
        return (-1);

    if (mutt_check_mailbox_compressed (ctx))
        return (-1);

    ctx->magic = mx_get_magic (ctx->path);

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

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

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

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

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

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

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

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

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

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

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

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

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

    /* fatal error */

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