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); + }