changeset: 6880:2c1d79d3edd5
user:      TAKAHASHI Tamotsu <tta...@lapis.plala.or.jp>
date:      Wed Sep 07 20:00:04 2016 -0700
link:      http://dev.mutt.org/hg/mutt/rev/2c1d79d3edd5

Fix openssl 1.1 compilation issues. (closes #3870)

With these changes, Mutt will no longer compile for versions less than
0.9.6.

changeset: 6881:10c4761cea89
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sat Nov 19 19:35:07 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/10c4761cea89

More openssl1.1 fixes: remove uses of X509->name in debugging. (closes #3870)

X509->name was a shortcut for the longer
  name = X509_NAME_oneline (X509_get_subject_name (cert),
                            buf, sizeof (buf));
invocation.  Change the debugging to print the cert name and chain
names in the ssl_check_certificate() loop instead.

changeset: 6882:a0a970530a8b
user:      Vincent Lefevre <vinc...@vinc17.net>
date:      Sat Nov 26 00:57:42 2016 +0100
link:      http://dev.mutt.org/hg/mutt/rev/a0a970530a8b

Fix build failure with GPGME 1.8: do not steal the gpgme_ prefix.

changeset: 6883:a17189b58284
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Dec 04 15:41:33 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/a17189b58284

merge stable

diffs (truncated from 9681 to 950 lines):

diff -r c6704c7f8e23 -r a17189b58284 INSTALL
--- a/INSTALL   Sun Oct 23 14:46:37 2016 -0700
+++ b/INSTALL   Sun Dec 04 15:41:33 2016 -0800
@@ -29,7 +29,7 @@
 - If you are building from Mercurial, or if you are changing parts of mutt,
   particularly the build system, do read doc/devel-notes.txt.
 
-- An ANSI C compiler (such as GCC) is required.
+- A C99 compiler (such as GCC) is required.
 
 - You must also have a SysV compatible curses library, or you must
   install either
diff -r c6704c7f8e23 -r a17189b58284 Makefile.am
--- a/Makefile.am       Sun Oct 23 14:46:37 2016 -0700
+++ b/Makefile.am       Sun Dec 04 15:41:33 2016 -0800
@@ -5,12 +5,16 @@
 AUTOMAKE_OPTIONS = 1.6 foreign
 EXTRA_PROGRAMS = mutt_dotlock pgpring pgpewrap mutt_md5
 
+if BUILD_DOC
+DOC_SUBDIR = doc
+endif
+
 if BUILD_IMAP
 IMAP_SUBDIR = imap
 IMAP_INCLUDES = -I$(top_srcdir)/imap
 endif
 
-SUBDIRS = m4 po intl doc contrib $(IMAP_SUBDIR)
+SUBDIRS = m4 po intl $(DOC_SUBDIR) contrib $(IMAP_SUBDIR)
 
 bin_SCRIPTS = muttbug flea $(SMIMEAUX_TARGET)
 
@@ -50,7 +54,7 @@
 
 AM_CPPFLAGS=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(GPGME_CFLAGS) -Iintl
 
-EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.c \
+EXTRA_mutt_SOURCES = account.c bcache.c compress.c crypt-gpgme.c 
crypt-mod-pgp-classic.c \
        crypt-mod-pgp-gpgme.c crypt-mod-smime-classic.c \
        crypt-mod-smime-gpgme.c dotlock.c gnupgparse.c hcache.c md5.c \
        mutt_idna.c mutt_sasl.c mutt_socket.c mutt_ssl.c mutt_ssl_gnutls.c \
@@ -61,7 +65,7 @@
 
 EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
        configure account.h \
-       attach.h buffy.h charset.h copy.h crypthash.h dotlock.h functions.h 
gen_defs \
+       attach.h buffy.h charset.h compress.h copy.h crypthash.h dotlock.h 
functions.h gen_defs \
        globals.h hash.h history.h init.h keymap.h mutt_crypt.h \
        mailbox.h mapping.h md5.h mime.h mutt.h mutt_curses.h mutt_menu.h \
        mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
diff -r c6704c7f8e23 -r a17189b58284 OPS
--- a/OPS       Sun Oct 23 14:46:37 2016 -0700
+++ b/OPS       Sun Dec 04 15:41:33 2016 -0800
@@ -36,6 +36,7 @@
 OP_COMPOSE_NEW_MIME "compose new attachment using mailcap entry"
 OP_COMPOSE_TOGGLE_RECODE "toggle recoding of this attachment"
 OP_COMPOSE_POSTPONE_MESSAGE "save this message to send later"
+OP_COMPOSE_RENAME_ATTACHMENT "send attachment with a different name"
 OP_COMPOSE_RENAME_FILE "rename/move an attached file"
 OP_COMPOSE_SEND_MESSAGE "send the message"
 OP_COMPOSE_TOGGLE_DISPOSITION "toggle disposition between inline/attachment"
@@ -124,11 +125,13 @@
 OP_MAIN_PREV_UNREAD "jump to the previous unread message"
 OP_MAIN_READ_THREAD "mark the current thread as read"
 OP_MAIN_READ_SUBTHREAD "mark the current subthread as read"
+OP_MAIN_ROOT_MESSAGE "jump to root message in thread"
 OP_MAIN_SET_FLAG "set a status flag on a message"
 OP_MAIN_SYNC_FOLDER "save changes to mailbox"
 OP_MAIN_TAG_PATTERN "tag messages matching a pattern"
 OP_MAIN_UNDELETE_PATTERN "undelete messages matching a pattern"
 OP_MAIN_UNTAG_PATTERN "untag messages matching a pattern"
+OP_MARK_MSG "create a hotkey macro for the current message"
 OP_MIDDLE_PAGE "move to the middle of the page"
 OP_NEXT_ENTRY "move to the next entry"
 OP_NEXT_LINE "scroll down one line"
diff -r c6704c7f8e23 -r a17189b58284 attach.c
--- a/attach.c  Sun Oct 23 14:46:37 2016 -0700
+++ b/attach.c  Sun Dec 04 15:41:33 2016 -0800
@@ -620,6 +620,8 @@
     STATE s;
 
     memset (&s, 0, sizeof (STATE));
+    /* perform charset conversion on text attachments when piping */
+    s.flags = MUTT_CHARCONV;
 
     if (outfile && *outfile)
       thepid = mutt_create_filter_fd (path, &s.fpout, NULL, NULL, -1, out, -1);
diff -r c6704c7f8e23 -r a17189b58284 browser.c
--- a/browser.c Sun Oct 23 14:46:37 2016 -0700
+++ b/browser.c Sun Dec 04 15:41:33 2016 -0800
@@ -176,11 +176,12 @@
          tnow = time (NULL);
          t_fmt = tnow - folder->ff->mtime < 31536000 ? "%b %d %H:%M" : "%b %d  
%Y";
        }
-       if (do_locales)
-         setlocale(LC_TIME, NONULL (Locale)); /* use environment if $locale is 
not set */
-       else
-         setlocale(LC_TIME, "C");
-       strftime (date, sizeof (date), t_fmt, localtime (&folder->ff->mtime));
+
+        if (!do_locales)
+          setlocale (LC_TIME, "C");
+        strftime (date, sizeof (date), t_fmt, localtime (&folder->ff->mtime));
+        if (!do_locales)
+          setlocale (LC_TIME, "");
 
        mutt_format_s (dest, destlen, fmt, date);
       }
diff -r c6704c7f8e23 -r a17189b58284 compose.c
--- a/compose.c Sun Oct 23 14:46:37 2016 -0700
+++ b/compose.c Sun Dec 04 15:41:33 2016 -0800
@@ -1019,7 +1019,32 @@
 
         /* No send2hook since this doesn't change the message. */
         break;
-      
+
+      case OP_COMPOSE_RENAME_ATTACHMENT:
+        {
+          char *src;
+          int ret;
+
+          CHECK_COUNT;
+          if (idx[menu->current]->content->d_filename)
+            src = idx[menu->current]->content->d_filename;
+          else
+            src = idx[menu->current]->content->filename;
+          strfcpy (fname, mutt_basename (NONULL (src)), sizeof (fname));
+          ret = mutt_get_field (_("Send attachment with name: "),
+                                fname, sizeof (fname), MUTT_FILE);
+          if (ret == 0)
+          {
+            /*
+             * As opposed to RENAME_FILE, we don't check fname[0] because it's
+             * valid to set an empty string here, to erase what was set
+             */
+            mutt_str_replace (&idx[menu->current]->content->d_filename, fname);
+            menu->redraw = REDRAW_CURRENT;
+          }
+        }
+        break;
+
       case OP_COMPOSE_RENAME_FILE:
        CHECK_COUNT;
        strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname));
diff -r c6704c7f8e23 -r a17189b58284 compress.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/compress.c        Sun Dec 04 15:41:33 2016 -0800
@@ -0,0 +1,961 @@
+/* Copyright (C) 1997 Alain Penders <al...@finale-dev.com>
+ * Copyright (C) 2016 Richard Russon <r...@flatcap.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "mutt.h"
+#include "mailbox.h"
+#include "mutt_curses.h"
+#include "mx.h"
+#include "compress.h"
+
+/* Notes:
+ * Any references to compressed files also apply to encrypted files.
+ * ctx->path     == plaintext file
+ * ctx->realpath == compressed file
+ */
+
+/**
+ * struct COMPRESS_INFO - Private data for compress
+ *
+ * This object gets attached to the mailbox's CONTEXT.
+ */
+typedef struct
+{
+  const char *append;             /* append-hook command */
+  const char *close;              /* close-hook  command */
+  const char *open;               /* open-hook   command */
+  off_t size;                     /* size of the compressed file */
+  struct mx_ops *child_ops;       /* callbacks of de-compressed file */
+  int locked;                     /* if realpath is locked */
+  FILE *lockfp;                   /* fp used for locking */
+} COMPRESS_INFO;
+
+
+/**
+ * lock_realpath - Try to lock the ctx->realpath
+ * @ctx:  Mailbox to lock
+ * @excl: Lock exclusively?
+ *
+ * Try to (exclusively) lock the mailbox.  If we succeed, then we mark the
+ * mailbox as locked.  If we fail, but we didn't want exclusive rights, then
+ * the mailbox will be marked readonly.
+ *
+ * Returns:
+ *      1: Success (locked or readonly)
+ *      0: Error (can't lock the file)
+ */
+static int
+lock_realpath (CONTEXT *ctx, int excl)
+{
+  if (!ctx)
+    return 0;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return 0;
+
+  if (ci->locked)
+    return 1;
+
+  if (excl)
+    ci->lockfp = fopen (ctx->realpath, "a");
+  else
+    ci->lockfp = fopen (ctx->realpath, "r");
+  if (!ci->lockfp)
+  {
+    mutt_perror (ctx->realpath);
+    return 0;
+  }
+
+  int r = mx_lock_file (ctx->realpath, fileno (ci->lockfp), excl, 1, 1);
+
+  if (r == 0)
+    ci->locked = 1;
+  else if (excl == 0)
+  {
+    safe_fclose (&ci->lockfp);
+    ctx->readonly = 1;
+    return 1;
+  }
+
+  return (r == 0);
+}
+
+/**
+ * unlock_realpath - Unlock the ctx->realpath
+ * @ctx: Mailbox to unlock
+ *
+ * Unlock a mailbox previously locked by lock_mailbox().
+ */
+static void
+unlock_realpath (CONTEXT *ctx)
+{
+  if (!ctx)
+    return;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return;
+
+  if (!ci->locked)
+    return;
+
+  mx_unlock_file (ctx->realpath, fileno (ci->lockfp), 1);
+
+  ci->locked = 0;
+  safe_fclose (&ci->lockfp);
+}
+
+/**
+ * setup_paths - Set the mailbox paths
+ * @ctx: Mailbox to modify
+ *
+ * Save the compressed filename in ctx->realpath.
+ * Create a temporary filename and put its name in ctx->path.
+ * The temporary file is created to prevent symlink attacks.
+ *
+ * Returns:
+ *      0: Success
+ *      -1: Error
+ */
+static int
+setup_paths (CONTEXT *ctx)
+{
+  if (!ctx)
+    return -1;
+
+  char tmppath[_POSIX_PATH_MAX];
+  FILE *tmpfp;
+
+  /* Setup the right paths */
+  FREE(&ctx->realpath);
+  ctx->realpath = ctx->path;
+
+  /* We will uncompress to /tmp */
+  mutt_mktemp (tmppath, sizeof (tmppath));
+  ctx->path = safe_strdup (tmppath);
+
+  if ((tmpfp = safe_fopen (ctx->path, "w")) == NULL)
+    return -1;
+
+  safe_fclose (&tmpfp);
+  return 0;
+}
+
+/**
+ * get_size - Get the size of a file
+ * @path: File to measure
+ *
+ * Returns:
+ *      number: Size in bytes
+ *      0:      On error
+ */
+static int
+get_size (const char *path)
+{
+  if (!path)
+    return 0;
+
+  struct stat sb;
+  if (stat (path, &sb) != 0)
+    return 0;
+
+  return sb.st_size;
+}
+
+/**
+ * store_size - Save the size of the compressed file
+ * @ctx: Mailbox
+ *
+ * Save the compressed file size in the compress_info struct.
+ */
+static void
+store_size (const CONTEXT *ctx)
+{
+  if (!ctx)
+    return;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return;
+
+  ci->size = get_size (ctx->realpath);
+}
+
+/**
+ * find_hook - Find a hook to match a path
+ * @type: Type of hook, e.g. MUTT_CLOSEHOOK
+ * @path: Filename to test
+ *
+ * Each hook has a type and a pattern.
+ * Find a command that matches the type and path supplied. e.g.
+ *
+ * User config:
+ *      open-hook '\.gz$' "gzip -cd '%f' > '%t'"
+ *
+ * Call:
+ *      find_hook (MUTT_OPENHOOK, "myfile.gz");
+ *
+ * Returns:
+ *      string: Matching hook command
+ *      NULL:   No matches
+ */
+static const char *
+find_hook (int type, const char *path)
+{
+  if (!path)
+    return NULL;
+
+  const char *c = mutt_find_hook (type, path);
+  if (!c || !*c)
+    return NULL;
+
+  return c;
+}
+
+/**
+ * set_compress_info - Find the compress hooks for a mailbox
+ * @ctx: Mailbox to examine
+ *
+ * When a mailbox is opened, we check if there are any matching hooks.
+ *
+ * Returns:
+ *      COMPRESS_INFO: Hook info for the mailbox's path
+ *      NULL:          On error
+ */
+static COMPRESS_INFO *
+set_compress_info (CONTEXT *ctx)
+{
+  if (!ctx || !ctx->path)
+    return NULL;
+
+  if (ctx->compress_info)
+    return ctx->compress_info;
+
+  /* Open is compulsory */
+  const char *o = find_hook (MUTT_OPENHOOK,   ctx->path);
+  if (!o)
+    return NULL;
+
+  const char *c = find_hook (MUTT_CLOSEHOOK,  ctx->path);
+  const char *a = find_hook (MUTT_APPENDHOOK, ctx->path);
+
+  COMPRESS_INFO *ci = safe_calloc (1, sizeof (COMPRESS_INFO));
+  ctx->compress_info = ci;
+
+  ci->open   = safe_strdup (o);
+  ci->close  = safe_strdup (c);
+  ci->append = safe_strdup (a);
+
+  return ci;
+}
+
+/**
+ * mutt_free_compress_info - Frees the compress info members and structure.
+ * @ctx: Mailbox to free compress_info for.
+ */
+void
+mutt_free_compress_info (CONTEXT *ctx)
+{
+  COMPRESS_INFO *ci;
+
+  if (!ctx || !ctx->compress_info)
+    return;
+
+  ci = ctx->compress_info;
+  FREE (&ci->open);
+  FREE (&ci->close);
+  FREE (&ci->append);
+
+  unlock_realpath (ctx);
+
+  FREE (&ctx->compress_info);
+}
+
+/**
+ * escape_path - Escapes single quotes in a path for a command string.
+ * @src - the path to escape.
+ *
+ * Returns: a pointer to the escaped string.
+ */
+static char *
+escape_path (char *src)
+{
+  static char dest[HUGE_STRING];
+  char *destp = dest;
+  int destsize = 0;
+
+  if (!src)
+    return NULL;
+
+  while (*src && (destsize < sizeof(dest) - 1))
+  {
+    if (*src != '\'')
+    {
+      *destp++ = *src++;
+      destsize++;
+    }
+    else
+    {
+      /* convert ' into '\'' */
+      if (destsize + 4 < sizeof(dest))
+      {
+        *destp++ = *src++;
+        *destp++ = '\\';
+        *destp++ = '\'';
+        *destp++ = '\'';
+        destsize += 4;
+      }
+      else
+        break;
+    }
+  }
+  *destp = '\0';
+
+  return dest;
+}
+
+/**
+ * cb_format_str - Expand the filenames in the command string
+ * @dest:        Buffer in which to save string
+ * @destlen:     Buffer length
+ * @col:         Starting column, UNUSED
+ * @cols:        Number of screen columns, UNUSED
+ * @op:          printf-like operator, e.g. 't'
+ * @src:         printf-like format string
+ * @fmt:         Field formatting string, UNUSED
+ * @ifstring:    If condition is met, display this string, UNUSED
+ * @elsestring:  Otherwise, display this string, UNUSED
+ * @data:        Pointer to the mailbox CONTEXT
+ * @flags:       Format flags, UNUSED
+ *
+ * cb_format_str is a callback function for mutt_FormatString.  It understands
+ * two operators. '%f' : 'from' filename, '%t' : 'to' filename.
+ *
+ * Returns: src (unchanged)
+ */
+static const char *
+cb_format_str (char *dest, size_t destlen, size_t col, int cols, char op, 
const char *src,
+  const char *fmt, const char *ifstring, const char *elsestring,
+  unsigned long data, format_flag flags)
+{
+  if (!dest || (data == 0))
+    return src;
+
+  CONTEXT *ctx = (CONTEXT *) data;
+
+  switch (op)
+  {
+    case 'f':
+      /* Compressed file */
+      snprintf (dest, destlen, "%s", NONULL (escape_path (ctx->realpath)));
+      break;
+    case 't':
+      /* Plaintext, temporary file */
+      snprintf (dest, destlen, "%s", NONULL (escape_path (ctx->path)));
+      break;
+  }
+  return src;
+}
+
+/**
+ * expand_command_str - Expand placeholders in command string
+ * @ctx:    Mailbox for paths
+ * @buf:    Buffer to store the command
+ * @buflen: Size of the buffer
+ *
+ * This function takes a hook command and expands the filename placeholders
+ * within it.  The function calls mutt_FormatString() to do the replacement
+ * which calls our callback function cb_format_str(). e.g.
+ *
+ * Template command:
+ *      gzip -cd '%f' > '%t'
+ *
+ * Result:
+ *      gzip -dc '~/mail/abc.gz' > '/tmp/xyz'
+ */
+static void
+expand_command_str (const CONTEXT *ctx, const char *cmd, char *buf, int buflen)
+{
+  if (!ctx || !cmd || !buf)
+    return;
+
+  mutt_FormatString (buf, buflen, 0, buflen, cmd, cb_format_str, (unsigned 
long) ctx, 0);
+}
+
+/**
+ * execute_command - Run a system command
+ * @ctx:         Mailbox to work with
+ * @command:     Command string to execute
+ * @progress:    Message to show the user
+ *
+ * Run the supplied command, taking care of all the Mutt requirements,
+ * such as locking files and blocking signals.
+ *
+ * Returns:
+ *      1: Success
+ *      0: Failure
+ */
+static int
+execute_command (CONTEXT *ctx, const char *command, const char *progress)
+{
+  int rc = 1;
+  char sys_cmd[HUGE_STRING];
+
+  if (!ctx || !command || !progress)
+    return 0;
+
+  if (!ctx->quiet)
+    mutt_message (progress, ctx->realpath);
+
+  mutt_block_signals();
+  endwin();
+  fflush (stdout);
+
+  expand_command_str (ctx, command, sys_cmd, sizeof (sys_cmd));
+
+  if (mutt_system (sys_cmd) != 0)
+  {
+    rc = 0;
+    mutt_any_key_to_continue (NULL);
+    mutt_error (_("Error running \"%s\"!"), sys_cmd);
+  }
+
+  mutt_unblock_signals();
+
+  return rc;
+}
+
+/**
+ * open_mailbox - Open a compressed mailbox
+ * @ctx: Mailbox to open
+ *
+ * Set up a compressed mailbox to be read.
+ * Decompress the mailbox and set up the paths and hooks needed.
+ * Then determine the type of the mailbox so we can delegate the handling of
+ * messages.
+ */
+static int
+open_mailbox (CONTEXT *ctx)
+{
+  if (!ctx || (ctx->magic != MUTT_COMPRESSED))
+    return -1;
+
+  COMPRESS_INFO *ci = set_compress_info (ctx);
+  if (!ci)
+    return -1;
+
+  /* If there's no close-hook, or the file isn't writable */
+  if (!ci->close || (access (ctx->path, W_OK) != 0))
+    ctx->readonly = 1;
+
+  if (setup_paths (ctx) != 0)
+    goto or_fail;
+  store_size (ctx);
+
+  if (!lock_realpath (ctx, 0))
+  {
+    mutt_error (_("Unable to lock mailbox!"));
+    goto or_fail;
+  }
+
+  int rc = execute_command (ctx, ci->open, _("Decompressing %s"));
+  if (rc == 0)
+    goto or_fail;
+
+  unlock_realpath (ctx);
+
+  ctx->magic = mx_get_magic (ctx->path);
+  if (ctx->magic == 0)
+  {
+    mutt_error (_("Can't identify the contents of the compressed file"));
+    goto or_fail;
+  }
+
+  ci->child_ops = mx_get_ops (ctx->magic);
+  if (!ci->child_ops)
+  {
+    mutt_error (_("Can't find mailbox ops for mailbox type %d"), ctx->magic);
+    goto or_fail;
+  }
+
+  return ci->child_ops->open (ctx);
+
+or_fail:
+  /* remove the partial uncompressed file */
+  remove (ctx->path);
+  mutt_free_compress_info (ctx);
+  return -1;
+}
+
+/**
+ * open_append_mailbox - Open a compressed mailbox for appending
+ * @ctx:   Mailbox to open
+ * @flags: e.g. Does the file already exist?
+ *
+ * To append to a compressed mailbox we need an append-hook (or both open- and
+ * close-hooks).
+ *
+ * Returns:
+ *       0: Success
+ *      -1: Failure
+ */
+static int
+open_append_mailbox (CONTEXT *ctx, int flags)
+{
+  if (!ctx)
+    return -1;
+
+  /* If this succeeds, we know there's an open-hook */
+  COMPRESS_INFO *ci = set_compress_info (ctx);
+  if (!ci)
+    return -1;
+
+  /* To append we need an append-hook or a close-hook */
+  if (!ci->append && !ci->close)
+  {
+    mutt_error (_("Cannot append without an append-hook or close-hook : %s"), 
ctx->path);
+    goto oa_fail1;
+  }
+
+  if (setup_paths (ctx) != 0)
+    goto oa_fail2;
+
+  /* Lock the realpath for the duration of the append.
+   * It will be unlocked in the close */
+  if (!lock_realpath (ctx, 1))
+  {
+    mutt_error (_("Unable to lock mailbox!"));
+    goto oa_fail2;
+  }
+
+  /* Open the existing mailbox, unless we are appending */
+  if (!ci->append && (get_size (ctx->realpath) > 0))
+  {
+    int rc = execute_command (ctx, ci->open, _("Decompressing %s"));
+    if (rc == 0)
+    {
+      mutt_error (_("Compress command failed: %s"), ci->open);
+      goto oa_fail2;
+    }
+    ctx->magic = mx_get_magic (ctx->path);
+  }
+  else
+    ctx->magic = DefaultMagic;
+
+  /* We can only deal with mbox and mmdf mailboxes */
+  if ((ctx->magic != MUTT_MBOX) && (ctx->magic != MUTT_MMDF))
+  {
+    mutt_error (_("Unsupported mailbox type for appending."));
+    goto oa_fail2;
+  }
+
+  ci->child_ops = mx_get_ops (ctx->magic);
+  if (!ci->child_ops)
+  {
+    mutt_error (_("Can't find mailbox ops for mailbox type %d"), ctx->magic);
+    goto oa_fail2;
+  }
+
+  if (ci->child_ops->open_append (ctx, flags) != 0)
+    goto oa_fail2;
+
+  return 0;
+
+oa_fail2:
+  /* remove the partial uncompressed file */
+  remove (ctx->path);
+oa_fail1:
+  /* Free the compress_info to prevent close from trying to recompress */
+  mutt_free_compress_info (ctx);
+
+  return -1;
+}
+
+/**
+ * close_mailbox - Close a compressed mailbox
+ * @ctx: Mailbox to close
+ *
+ * If the mailbox has been changed then re-compress the tmp file.
+ * Then delete the tmp file.
+ *
+ * Returns:
+ *       0: Success
+ *      -1: Failure
+ */
+static int
+close_mailbox (CONTEXT *ctx)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  ops->close (ctx);
+
+  /* sync has already been called, so we only need to delete some files */
+  if (!ctx->append)
+  {
+    /* If the file was removed, remove the compressed folder too */
+    if ((access (ctx->path, F_OK) != 0) && !option (OPTSAVEEMPTY))
+    {
+      remove (ctx->realpath);
+    }
+    else
+    {
+      remove (ctx->path);
+    }
+
+    return 0;
+  }
+
+  const char *append;
+  const char *msg;
+
+  /* The file exists and we can append */
+  if ((access (ctx->realpath, F_OK) == 0) && ci->append)
+  {
+    append = ci->append;
+    msg = _("Compressed-appending to %s...");
+  }
+  else
+  {
+    append = ci->close;
+    msg = _("Compressing %s...");
+  }
+
+  int rc = execute_command (ctx, append, msg);
+  if (rc == 0)
+  {
+    mutt_any_key_to_continue (NULL);
+    mutt_error (_("Error. Preserving temporary file: %s"), ctx->path);
+  }
+  else
+    remove (ctx->path);
+
+  unlock_realpath (ctx);
+
+  return 0;
+}
+
+/**
+ * check_mailbox - Check for changes in the compressed file
+ * @ctx: Mailbox
+ *
+ * If the compressed file changes in size but the mailbox hasn't been changed
+ * in Mutt, then we can close and reopen the mailbox.
+ *
+ * If the mailbox has been changed in Mutt, warn the user.
+ *
+ * The return codes are picked to match mx_check_mailbox().
+ *
+ * Returns:
+ *      0:              Mailbox OK
+ *      MUTT_REOPENED:  The mailbox was closed and reopened
+ *      -1:             Mailbox bad
+ */
+static int
+check_mailbox (CONTEXT *ctx, int *index_hint)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  int size = get_size (ctx->realpath);
+  if (size == ci->size)
+    return 0;
+
+  if (!lock_realpath (ctx, 0))
+  {
+    mutt_error (_("Unable to lock mailbox!"));
+    return -1;
+  }
+
+  int rc = execute_command (ctx, ci->open, _("Decompressing %s"));
+  store_size (ctx);
+  unlock_realpath (ctx);
+  if (rc == 0)
+    return -1;
+
+  return ops->check (ctx, index_hint);
+}
+
+
+/**
+ * open_message - Delegated to mbox handler
+ */
+static int
+open_message (CONTEXT *ctx,  MESSAGE *msg, int msgno)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  /* Delegate */
+  return ops->open_msg (ctx, msg, msgno);
+}
+
+/**
+ * close_message - Delegated to mbox handler
+ */
+static int
+close_message (CONTEXT *ctx, MESSAGE *msg)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  /* Delegate */
+  return ops->close_msg (ctx, msg);
+}
+
+/**
+ * commit_message - Delegated to mbox handler
+ */
+static int
+commit_message (CONTEXT *ctx, MESSAGE *msg)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  /* Delegate */
+  return ops->commit_msg (ctx, msg);
+}
+
+/**
+ * open_new_message - Delegated to mbox handler
+ */
+static int
+open_new_message (MESSAGE *msg, CONTEXT *ctx, HEADER *hdr)
+{
+  if (!ctx)
+    return -1;
+
+  COMPRESS_INFO *ci = ctx->compress_info;
+  if (!ci)
+    return -1;
+
+  struct mx_ops *ops = ci->child_ops;
+  if (!ops)
+    return -1;
+
+  /* Delegate */

Reply via email to