2 * Copyright notice from original mutt:
3 * Copyright (C) 1997 Alain Penders <Alain@Finale-Dev.com>
5 * This file is part of mutt-ng, see http://www.muttng.org/.
6 * It's licensed under the GNU General Public License,
7 * please see the file GPL in the top level source directory.
10 #include <lib-lib/lib-lib.h>
12 #include <lib-sys/mutt_signal.h>
13 #include <lib-sys/unix.h>
15 #include <lib-ui/curses.h>
23 const char *close; /* close-hook command */
24 const char *open; /* open-hook command */
25 const char *append; /* append-hook command */
26 off_t size; /* size of real folder */
29 char echo_cmd[HUGE_STRING];
32 * ctx - context to lock
33 * excl - exclusive lock?
34 * retry - should retry if unable to lock?
36 int mbox_lock_compressed (CONTEXT * ctx, FILE * fp, int excl, int retry)
40 if ((r = mx_lock_file (ctx->realpath, fileno (fp), excl, 1, retry)) == 0)
42 else if (retry && !excl) {
50 void mbox_unlock_compressed (CONTEXT * ctx, FILE * fp)
55 mx_unlock_file (ctx->realpath, fileno (fp), 1);
60 static int is_new (const char *path)
62 return (access (path, W_OK) != 0 && errno == ENOENT) ? 1 : 0;
65 static const char *find_compress_hook (int type, const char *path)
67 const char *c = mutt_find_hook (type, path);
69 return (!c || !*c) ? NULL : c;
72 int mutt_can_read_compressed (const char *path)
74 return find_compress_hook (M_OPENHOOK, path) ? 1 : 0;
77 /* if the file is new, we really do not append, but create, and so use
78 * close-hook, and not append-hook
80 static const char *get_append_command (const char *path, const CONTEXT * ctx)
82 COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
84 return (is_new (path)) ? ci->close : ci->append;
87 int mutt_can_append_compressed (const char *path)
92 return (find_compress_hook (M_CLOSEHOOK, path) ? 1 : 0);
94 magic = mx_get_magic (path);
96 if (magic != 0 && magic != M_COMPRESSED)
99 return (find_compress_hook (M_APPENDHOOK, path)
100 || (find_compress_hook (M_OPENHOOK, path)
101 && find_compress_hook (M_CLOSEHOOK, path))) ? 1 : 0;
104 /* open a compressed mailbox */
105 static COMPRESS_INFO *set_compress_info (CONTEXT * ctx)
109 /* Now lets uncompress this thing */
110 ci = p_new(COMPRESS_INFO, 1);
111 ctx->compressinfo = (void *) ci;
112 ci->append = find_compress_hook (M_APPENDHOOK, ctx->path);
113 ci->open = find_compress_hook (M_OPENHOOK, ctx->path);
114 ci->close = find_compress_hook (M_CLOSEHOOK, ctx->path);
118 static void set_path (CONTEXT * ctx)
120 char tmppath[_POSIX_PATH_MAX];
122 /* Setup the right paths */
123 ctx->realpath = ctx->path;
125 /* Uncompress to /tmp */
126 mutt_mktemp (tmppath);
127 ctx->path = p_dupstr(tmppath, m_strlen(tmppath));
130 static int get_size (const char *path)
134 if (stat (path, &sb) != 0)
139 static void store_size (CONTEXT * ctx)
141 COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
143 ci->size = get_size (ctx->realpath);
146 static const char *compresshook_format_str (char *dest, ssize_t destlen,
147 char op, const char *src,
149 const char *ifstring __attribute__ ((unused)),
150 const char *elsestring __attribute__ ((unused)),
152 format_flag flags __attribute__ ((unused)))
154 char tmp[SHORT_STRING];
156 CONTEXT *ctx = (CONTEXT *) data;
160 snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
161 snprintf (dest, destlen, tmp, ctx->realpath);
164 snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
165 snprintf (dest, destlen, tmp, ctx->path);
171 /* check that the command has both %f and %t
172 * 0 means OK, -1 means error
174 int mutt_test_compress_command (const char *cmd)
176 return (strstr (cmd, "%f") && strstr (cmd, "%t")) ? 0 : -1;
179 static char *get_compression_cmd (const char *cmd, const CONTEXT * ctx)
181 char expanded[_POSIX_PATH_MAX];
183 mutt_FormatString (expanded, sizeof (expanded), cmd,
184 compresshook_format_str, (unsigned long) ctx, 0);
185 return m_strdup(expanded);
188 int mutt_check_mailbox_compressed (CONTEXT * ctx)
190 COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
192 if (ci->size != get_size (ctx->realpath)) {
193 p_delete(&ctx->compressinfo);
194 p_delete(&ctx->realpath);
195 mutt_error _("Mailbox was corrupted!");
202 int mutt_open_read_compressed (CONTEXT * ctx)
208 COMPRESS_INFO *ci = set_compress_info (ctx);
212 p_delete(&ctx->compressinfo);
215 if (!ci->close || access (ctx->path, W_OK) != 0)
222 mutt_message (_("Decompressing %s..."), ctx->realpath);
224 cmd = get_compression_cmd (ci->open, ctx);
228 if ((fp = fopen (ctx->realpath, "r")) == NULL) {
229 mutt_perror (ctx->realpath);
233 mutt_block_signals ();
234 if (mbox_lock_compressed (ctx, fp, 0, 1) == -1) {
236 mutt_unblock_signals ();
237 mutt_error _("Unable to lock mailbox!");
245 sprintf (echo_cmd, _("echo Decompressing %s..."), ctx->realpath);
246 mutt_system (echo_cmd);
247 rc = mutt_system (cmd);
248 mbox_unlock_compressed (ctx, fp);
249 mutt_unblock_signals ();
253 mutt_any_key_to_continue (NULL);
255 p_delete(&ctx->compressinfo);
256 mutt_error (_("Error executing: %s : unable to open the mailbox!\n"),
263 if (mutt_check_mailbox_compressed (ctx))
266 ctx->magic = mx_get_magic (ctx->path);
271 void restore_path (CONTEXT * ctx)
273 p_delete(&ctx->path);
274 ctx->path = ctx->realpath;
277 /* remove the temporary mailbox */
278 void remove_file (CONTEXT * ctx)
280 if (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
284 int mutt_open_append_compressed (CONTEXT * ctx)
287 COMPRESS_INFO *ci = set_compress_info (ctx);
289 if (!get_append_command (ctx->path, ctx)) {
290 if (ci->open && ci->close)
291 return (mutt_open_read_compressed (ctx));
294 p_delete(&ctx->compressinfo);
300 ctx->magic = DefaultMagic;
302 if (!is_new (ctx->realpath))
303 if (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
304 if ((fh = safe_fopen (ctx->path, "w")))
306 /* No error checking - the parent function will catch it */
311 /* close a compressed mailbox */
312 void mutt_fast_close_compressed (CONTEXT * ctx)
314 if (ctx->compressinfo) {
318 /* if the folder was removed, remove the gzipped folder too */
319 if (access (ctx->path, F_OK) != 0 && !option (OPTSAVEEMPTY))
320 remove (ctx->realpath);
325 p_delete(&ctx->compressinfo);
329 /* return 0 on success, -1 on failure */
330 int mutt_sync_compressed (CONTEXT * ctx)
335 COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
338 mutt_message (_("Compressing %s..."), ctx->realpath);
340 cmd = get_compression_cmd (ci->close, ctx);
344 if ((fp = fopen (ctx->realpath, "a")) == NULL) {
345 mutt_perror (ctx->realpath);
349 mutt_block_signals ();
350 if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
352 mutt_unblock_signals ();
353 mutt_error _("Unable to lock mailbox!");
363 sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
364 mutt_system (echo_cmd);
365 if (mutt_system (cmd)) {
366 mutt_any_key_to_continue (NULL);
368 ("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"),
373 mbox_unlock_compressed (ctx, fp);
374 mutt_unblock_signals ();
384 int mutt_slow_close_compressed (CONTEXT * ctx)
389 COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
391 if (!(ctx->append && ((append = get_append_command (ctx->realpath, ctx))
392 || (append = ci->close)))) { /* if we can not or should not append,
393 * we only have to remove the compressed info, because sync was already
396 mutt_fast_close_compressed (ctx);
405 if (append == ci->close)
406 mutt_message (_("Compressing %s..."), ctx->realpath);
408 mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
411 cmd = get_compression_cmd (append, ctx);
415 if ((fp = fopen (ctx->realpath, "a")) == NULL) {
416 mutt_perror (ctx->realpath);
420 mutt_block_signals ();
421 if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
423 mutt_unblock_signals ();
424 mutt_error _("Unable to lock mailbox!");
433 if (append == ci->close)
434 sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
436 sprintf (echo_cmd, _("echo Compressed-appending to %s..."),
438 mutt_system (echo_cmd);
440 if (mutt_system (cmd)) {
441 mutt_any_key_to_continue (NULL);
443 (" %s: Error compressing mailbox! Uncompressed one kept!\n"),
446 mbox_unlock_compressed (ctx, fp);
447 mutt_unblock_signals ();
452 mbox_unlock_compressed (ctx, fp);
453 mutt_unblock_signals ();
458 p_delete(&ctx->compressinfo);
463 mx_t* compress_reg_mx (void) {
464 mx_t* fmt = p_new(mx_t, 1);
465 fmt->type = M_COMPRESSED;
467 fmt->mx_is_magic = mbox_is_magic;
468 fmt->mx_check_empty = mbox_check_empty;
469 fmt->mx_access = access;
470 fmt->mx_open_mailbox = mutt_open_read_compressed;