changeset: 6884:99f5624d1f52
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Dec 04 16:01:32 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/99f5624d1f52

automatic post-release commit for mutt-1.7.2

changeset: 6885:954f9049e4b3
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Dec 04 16:01:49 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/954f9049e4b3

Added tag mutt-1-7-2-rel for changeset 99f5624d1f52

changeset: 6886:b9d34372a940
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Dec 04 16:03:00 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/b9d34372a940

mutt-1.7.2 signed

changeset: 6887:d930e39ec095
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Dec 04 16:04:29 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/d930e39ec095

merge stable

diffs (truncated from 9666 to 950 lines):

diff -r a0a970530a8b -r d930e39ec095 .hgsigs
--- a/.hgsigs   Sat Nov 26 00:57:42 2016 +0100
+++ b/.hgsigs   Sun Dec 04 16:04:29 2016 -0800
@@ -13,3 +13,4 @@
 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
diff -r a0a970530a8b -r d930e39ec095 .hgtags
--- a/.hgtags   Sat Nov 26 00:57:42 2016 +0100
+++ b/.hgtags   Sun Dec 04 16:04:29 2016 -0800
@@ -105,3 +105,4 @@
 7ccd4417bd70373d873c5f9d38e4d22aa5df9afe mutt-1-6-2-rel
 a4e83f60e42f80599e71df90bfc69db4704e5f97 mutt-1-7-rel
 0ce5f9bff1fdfe86c91109312329c7e8849b347b mutt-1-7-1-rel
+99f5624d1f52ac1e9ddd55867c07b07e3bdd4fd7 mutt-1-7-2-rel
diff -r a0a970530a8b -r d930e39ec095 ChangeLog
--- a/ChangeLog Sat Nov 26 00:57:42 2016 +0100
+++ b/ChangeLog Sun Dec 04 16:04:29 2016 -0800
@@ -1,3 +1,98 @@
+2016-11-26 00:57 +0100  Vincent Lefevre  <vinc...@vinc17.net>  (a0a970530a8b)
+
+       * crypt-gpgme.c, crypt-gpgme.h, crypt-mod-pgp-gpgme.c: Fix build
+       failure with GPGME 1.8: do not steal the gpgme_ prefix.
+
+2016-11-19 19:35 -0800  Kevin McCarthy  <ke...@8t8.us>  (10c4761cea89)
+
+       * mutt_ssl.c: 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.
+
+2016-09-07 20:00 -0700  TAKAHASHI Tamotsu  <tta...@lapis.plala.or.jp>  
(2c1d79d3edd5)
+
+       * configure.ac, mutt_ssl.c: Fix openssl 1.1 compilation issues.
+       (closes #3870)
+
+       With these changes, Mutt will no longer compile for versions less
+       than 0.9.6.
+
+2016-10-23 14:46 -0700  Kevin McCarthy  <ke...@8t8.us>  (c6704c7f8e23)
+
+       * pager.c: Fix pager segfault when lineInfo.chunks overflows. (closes
+       #3888)
+
+       The reporter had an html attachment with extremely long lines,
+       combined with a color pattern of "color body default default ." This
+       overflowed the lineInfo.chunks, causing a segfault.
+
+       Abort the body color patterns if this happens.
+
+2016-10-23 13:43 -0700  Kevin McCarthy  <ke...@8t8.us>  (a8203b4463c1)
+
+       * date.c: Prevent an integer overflow in mutt_mktime() (closes #3880)
+
+       Check to make sure the year passed in isn't bigger than can be
+       represented using time_t on the platform.
+
+       Also add a (time_t) cast to an intermediate "years * 365"
+       calculation to prevent an overflow there.
+
+       Thanks to TAKAHASHI Tamotsu for his patch, and to Vincent Lefèvre
+       for his improvement. I merely took their code and commited it.
+
+2016-10-17 11:22 -0700  Kevin McCarthy  <ke...@8t8.us>  (113b73b0b616)
+
+       * crypt-gpgme.c: Actually fix gpgme segfault in
+       create_recipient_set().
+
+       Changeset 6e44bfa16096 did not fix the segv. (Sorry, I made the fix
+       based off a report on IRC but didn't trigger the segv myself: it was
+       caused by an out-of-tree patch).
+
+       The actual problem was that the rset was only resized on a
+       successful gpgme_get_key(). However, on error, the array still needs
+       to be NULL-terminated before calling free_recipient_set().
+
+       Move the resize so it always takes place. This obviates the need for
+       the NULL check added in 6e44bfa16096.
+
+2016-10-16 15:12 -0700  Kevin McCarthy  <ke...@8t8.us>  (783dce6dfcd4)
+
+       * sidebar.c: Use mutt_strlen and mutt_strncmp in sidebar.c.
+
+       This prevents a segv if folder is unset.
+
+2016-10-16 14:16 -0700  Kevin McCarthy  <ke...@8t8.us>  (6e44bfa16096)
+
+       * crypt-gpgme.c: Fix gpgme segfault in create_recipient_set().
+
+       If gpgme_get_key() errors on the first key, the rset will not be
+       allocated yet. Attempting to null-terminate (and then free) the
+       array causes a segfault.
+
+2016-10-08 12:57 -0700  Kevin McCarthy  <ke...@8t8.us>  (58f4b38312bf)
+
+       * .hgsigs: mutt-1.7.1 signed
+
+2016-10-08 12:56 -0700  Kevin McCarthy  <ke...@8t8.us>  (e8d9ae6f41d3)
+
+       * .hgtags: Added tag mutt-1-7-1-rel for changeset 0ce5f9bff1fd
+
+2016-10-08 12:56 -0700  Kevin McCarthy  <ke...@8t8.us>  (0ce5f9bff1fd)
+
+       * ChangeLog, UPDATING, VERSION, po/bg.po, po/ca.po, po/cs.po,
+       po/da.po, po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po,
+       po/eu.po, po/fr.po, po/ga.po, po/gl.po, po/hu.po, po/id.po,
+       po/it.po, po/ja.po, po/ko.po, po/lt.po, po/nl.po, po/pl.po,
+       po/pt_BR.po, po/ru.po, po/sk.po, po/sv.po, po/tr.po, po/uk.po,
+       po/zh_CN.po, po/zh_TW.po: automatic post-release commit for
+       mutt-1.7.1
+
 2016-10-04 11:13 -0700  Kevin McCarthy  <ke...@8t8.us>  (5c5848dfa4ea)
 
        * muttlib.c: Preserve forwarded attachment names in d_filename.
diff -r a0a970530a8b -r d930e39ec095 INSTALL
--- a/INSTALL   Sat Nov 26 00:57:42 2016 +0100
+++ b/INSTALL   Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 Makefile.am
--- a/Makefile.am       Sat Nov 26 00:57:42 2016 +0100
+++ b/Makefile.am       Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 OPS
--- a/OPS       Sat Nov 26 00:57:42 2016 +0100
+++ b/OPS       Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 UPDATING
--- a/UPDATING  Sat Nov 26 00:57:42 2016 +0100
+++ b/UPDATING  Sun Dec 04 16:04:29 2016 -0800
@@ -4,6 +4,11 @@
 The keys used are:
   !: modified feature, -: deleted feature, +: new feature
 
+1.7.2 (2016-12-04):
+
+  ! Bug fix release.  No features were modified or added.
+  ! Fixes for OpenSSL 1.1.  Versions less than 0.9.6 are no longer supported.
+
 1.7.1 (2016-10-08):
 
   ! Bug fix release.  No features were modified or added.
diff -r a0a970530a8b -r d930e39ec095 VERSION
--- a/VERSION   Sat Nov 26 00:57:42 2016 +0100
+++ b/VERSION   Sun Dec 04 16:04:29 2016 -0800
@@ -1,1 +1,1 @@
-1.7.1
+1.7.2
diff -r a0a970530a8b -r d930e39ec095 attach.c
--- a/attach.c  Sat Nov 26 00:57:42 2016 +0100
+++ b/attach.c  Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 browser.c
--- a/browser.c Sat Nov 26 00:57:42 2016 +0100
+++ b/browser.c Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 compose.c
--- a/compose.c Sat Nov 26 00:57:42 2016 +0100
+++ b/compose.c Sun Dec 04 16:04:29 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 a0a970530a8b -r d930e39ec095 compress.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/compress.c        Sun Dec 04 16:04:29 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);
+  }

Reply via email to