NeoMutt  2025-12-11-58-g09398d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
compress.c File Reference

Compressed mbox local mailbox type. More...

#include "config.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "lib.h"
#include "expando/lib.h"
#include "expando.h"
#include "hook.h"
#include "mx.h"
#include "protos.h"
+ Include dependency graph for compress.c:

Go to the source code of this file.

Functions

void mutt_comp_init (void)
 Setup Compressed Mailbox commands.
 
static bool lock_realpath (struct Mailbox *m, bool excl)
 Try to lock the Mailbox.realpath.
 
static void unlock_realpath (struct Mailbox *m)
 Unlock the mailbox->realpath.
 
static int setup_paths (struct Mailbox *m)
 Set the mailbox paths.
 
static void store_size (const struct Mailbox *m)
 Save the size of the compressed file.
 
static struct Expandovalidate_compress_expando (const char *s)
 Validate the Compress hooks.
 
static struct CompressInfoset_compress_info (struct Mailbox *m)
 Find the compress hooks for a mailbox.
 
static void compress_info_free (struct Mailbox *m)
 Frees the compress info members and structure.
 
static bool execute_command (struct Mailbox *m, const struct Expando *exp, const char *progress)
 Run a system command.
 
bool mutt_comp_can_append (struct Mailbox *m)
 Can we append to this path?
 
bool mutt_comp_can_read (const char *path)
 Can we read from this file?
 
int mutt_comp_valid_command (const char *cmd)
 Is this command string allowed?
 
static bool comp_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -.
 
static bool comp_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -.
 
static enum MxOpenReturns comp_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -.
 
static bool comp_mbox_open_append (struct Mailbox *m, OpenMailboxFlags flags)
 Open a Mailbox for appending - Implements MxOps::mbox_open_append() -.
 
static enum MxStatus comp_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -.
 
static enum MxStatus comp_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus comp_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -.
 
static bool comp_msg_open (struct Mailbox *m, struct Message *msg, struct Email *e)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -.
 
static bool comp_msg_open_new (struct Mailbox *m, struct Message *msg, const struct Email *e)
 Open a new message in a Mailbox - Implements MxOps::msg_open_new() -.
 
static int comp_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -.
 
static int comp_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -.
 
static int comp_msg_padding_size (struct Mailbox *m)
 Bytes of padding between messages - Implements MxOps::msg_padding_size() -.
 
static int comp_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -.
 
static int comp_tags_edit (struct Mailbox *m, const char *tags, struct Buffer *buf)
 Prompt and validate new messages tags - Implements MxOps::tags_edit() -.
 
static int comp_tags_commit (struct Mailbox *m, struct Email *e, const char *buf)
 Save the tags to a message - Implements MxOps::tags_commit() -.
 
static enum MailboxType comp_path_probe (const char *path, const struct stat *st)
 Is this a compressed Mailbox?
 
static int comp_path_canon (struct Buffer *path)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -.
 

Variables

static const struct Command CompCommands []
 Compression Commands.
 
const struct ExpandoDefinition CompressFormatDef []
 Expando definitions.
 
const struct MxOps MxCompOps
 Compressed Mailbox - Implements MxOps -.
 

Detailed Description

Compressed mbox local mailbox type.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Reto Brunner
  • Tóth János

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, see http://www.gnu.org/licenses/.

Definition in file compress.c.

Function Documentation

◆ mutt_comp_init()

void mutt_comp_init ( void )

Setup Compressed Mailbox commands.

Definition at line 100 of file compress.c.

101{
103}
static const struct Command CompCommands[]
Compression Commands.
Definition compress.c:62
bool commands_register(struct CommandArray *ca, const struct Command *cmds)
Add commands to Commands array.
Definition command.c:51
Container for Accounts, Notifications.
Definition neomutt.h:43
struct CommandArray commands
NeoMutt commands.
Definition neomutt.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ lock_realpath()

static bool lock_realpath ( struct Mailbox * m,
bool excl )
static

Try to lock the Mailbox.realpath.

Parameters
mMailbox to lock
exclLock exclusively?
Return values
trueSuccess (locked or readonly)
falseError (can't lock the file)

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.

Definition at line 116 of file compress.c.

117{
118 if (!m || !m->compress_info)
119 return false;
120
121 struct CompressInfo *ci = m->compress_info;
122
123 if (ci->locked)
124 return true;
125
126 if (excl)
127 ci->fp_lock = mutt_file_fopen(m->realpath, "a");
128 else
129 ci->fp_lock = mutt_file_fopen(m->realpath, "r");
130 if (!ci->fp_lock)
131 {
132 mutt_perror("%s", m->realpath);
133 return false;
134 }
135
136 int r = mutt_file_lock(fileno(ci->fp_lock), excl, true);
137 if (r == 0)
138 {
139 ci->locked = true;
140 }
141 else if (excl)
142 {
144 m->readonly = true;
145 return true;
146 }
147
148 return r == 0;
149}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition file.c:1095
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define mutt_perror(...)
Definition logging2.h:94
Private data for compress.
Definition lib.h:60
FILE * fp_lock
fp used for locking
Definition lib.h:67
bool locked
if realpath is locked
Definition lib.h:66
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:81
void * compress_info
Compressed mbox module private data.
Definition mailbox.h:121
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:116
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ unlock_realpath()

static void unlock_realpath ( struct Mailbox * m)
static

Unlock the mailbox->realpath.

Parameters
mMailbox to unlock

Unlock a mailbox previously locked by lock_mailbox().

Definition at line 157 of file compress.c.

158{
159 if (!m || !m->compress_info)
160 return;
161
162 struct CompressInfo *ci = m->compress_info;
163
164 if (!ci->locked)
165 return;
166
167 mutt_file_unlock(fileno(ci->fp_lock));
168
169 ci->locked = false;
171}
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition file.c:1142
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ setup_paths()

static int setup_paths ( struct Mailbox * m)
static

Set the mailbox paths.

Parameters
mMailbox to modify
Return values
0Success
-1Error

Save the compressed filename in mailbox->realpath. Create a temporary filename and put its name in mailbox->path. The temporary file is created to prevent symlink attacks.

Definition at line 183 of file compress.c.

184{
185 if (!m)
186 return -1;
187
188 /* Setup the right paths */
190
191 /* We will uncompress to TMPDIR */
192 struct Buffer *buf = buf_pool_get();
193 buf_mktemp(buf);
194 buf_copy(&m->pathbuf, buf);
195 buf_pool_release(&buf);
196
197 return mutt_file_touch(mailbox_path(m)) ? 0 : -1;
198}
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:214
bool mutt_file_touch(const char *path)
Make sure a file exists.
Definition file.c:981
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:282
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
String manipulation buffer.
Definition buffer.h:36
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:80
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ store_size()

static void store_size ( const struct Mailbox * m)
static

Save the size of the compressed file.

Parameters
mMailbox

Save the compressed file size in the compress_info struct.

Definition at line 206 of file compress.c.

207{
208 if (!m || !m->compress_info)
209 return;
210
211 struct CompressInfo *ci = m->compress_info;
212
214}
long mutt_file_get_size(const char *path)
Get the size of a file.
Definition file.c:1412
long size
size of the compressed file
Definition lib.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ validate_compress_expando()

static struct Expando * validate_compress_expando ( const char * s)
static

Validate the Compress hooks.

Parameters
sCommand string
Return values
ptrExpando

Definition at line 221 of file compress.c.

222{
223 struct Buffer *err = buf_pool_get();
224
225 struct Expando *exp = expando_parse(s, CompressFormatDef, err);
226 if (!exp)
227 {
228 mutt_error(_("Expando parse error: %s"), buf_string(err));
229 }
230
231 buf_pool_release(&err);
232 return exp;
233}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct ExpandoDefinition CompressFormatDef[]
Expando definitions.
Definition compress.c:89
struct Expando * expando_parse(const char *str, const struct ExpandoDefinition *defs, struct Buffer *err)
Parse an Expando string.
Definition expando.c:81
#define mutt_error(...)
Definition logging2.h:93
#define _(a)
Definition message.h:28
Parsed Expando trees.
Definition expando.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_compress_info()

static struct CompressInfo * set_compress_info ( struct Mailbox * m)
static

Find the compress hooks for a mailbox.

Parameters
mMailbox to examine
Return values
ptrCompressInfo Hook info for the mailbox's path
NULLError

When a mailbox is opened, we check if there are any matching hooks.

Definition at line 243 of file compress.c.

244{
245 if (!m)
246 return NULL;
247
248 if (m->compress_info)
249 return m->compress_info;
250
251 /* Open is compulsory */
252 const char *o = mutt_find_hook(MUTT_OPEN_HOOK, mailbox_path(m));
253 if (!o)
254 return NULL;
255
256 const char *c = mutt_find_hook(MUTT_CLOSE_HOOK, mailbox_path(m));
257 const char *a = mutt_find_hook(MUTT_APPEND_HOOK, mailbox_path(m));
258
259 struct CompressInfo *ci = MUTT_MEM_CALLOC(1, struct CompressInfo);
260 m->compress_info = ci;
261
265
266 return ci;
267}
static struct Expando * validate_compress_expando(const char *s)
Validate the Compress hooks.
Definition compress.c:221
char * mutt_find_hook(HookFlags type, const char *pat)
Find a matching hook.
Definition hook.c:1339
#define MUTT_OPEN_HOOK
open-hook: to read a compressed mailbox
Definition hook.h:49
#define MUTT_CLOSE_HOOK
close-hook: write to a compressed mailbox
Definition hook.h:51
#define MUTT_APPEND_HOOK
append-hook: append to a compressed mailbox
Definition hook.h:50
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
struct Expando * cmd_open
open-hook command
Definition lib.h:63
struct Expando * cmd_append
append-hook command
Definition lib.h:61
struct Expando * cmd_close
close-hook command
Definition lib.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compress_info_free()

static void compress_info_free ( struct Mailbox * m)
static

Frees the compress info members and structure.

Parameters
mMailbox to free compress_info for

Definition at line 273 of file compress.c.

274{
275 if (!m || !m->compress_info)
276 return;
277
278 struct CompressInfo *ci = m->compress_info;
282
284
285 FREE(&m->compress_info);
286}
static void unlock_realpath(struct Mailbox *m)
Unlock the mailbox->realpath.
Definition compress.c:157
void expando_free(struct Expando **ptr)
Free an Expando object.
Definition expando.c:61
#define FREE(x)
Definition memory.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ execute_command()

static bool execute_command ( struct Mailbox * m,
const struct Expando * exp,
const char * progress )
static

Run a system command.

Parameters
mMailbox to work with
expCommand expando to execute
progressMessage to show the user
Return values
trueSuccess
falseFailure

Run the supplied command, taking care of all the NeoMutt requirements, such as locking files and blocking signals.

Definition at line 299 of file compress.c.

300{
301 if (!m || !exp || !progress)
302 return false;
303
304 if (m->verbose)
305 mutt_message(progress, m->realpath);
306
307 bool rc = true;
308 struct Buffer *sys_cmd = buf_pool_get();
309 buf_alloc(sys_cmd, STR_COMMAND);
310
312 mutt_endwin();
313 fflush(stdout);
314
316 sys_cmd->dsize, sys_cmd);
317
318 if (mutt_system(buf_string(sys_cmd)) != 0)
319 {
320 rc = false;
322 mutt_error(_("Error running \"%s\""), buf_string(sys_cmd));
323 }
324
326
327 buf_pool_release(&sys_cmd);
328 return rc;
329}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
const struct ExpandoRenderCallback CompressRenderCallbacks[]
Callbacks for Compression Hook Expandos.
Definition expando.c:70
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition expando.c:118
#define mutt_message(...)
Definition logging2.h:92
int mutt_system(const char *cmd)
Run an external command.
Definition system.c:52
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition render.h:33
void mutt_sig_block(void)
Block signals during critical operations.
Definition signal.c:227
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition signal.c:245
#define STR_COMMAND
Enough space for a long command line.
Definition string2.h:41
size_t dsize
Length of data.
Definition buffer.h:39
bool verbose
Display status messages?
Definition mailbox.h:117
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_comp_can_append()

bool mutt_comp_can_append ( struct Mailbox * m)

Can we append to this path?

Parameters
mMailbox
Return values
trueYes, we can append to the file
falseNo, appending isn't possible

To append to a file we can either use an 'append-hook' or a combination of 'open-hook' and 'close-hook'.

A match means it's our responsibility to append to the file.

Definition at line 342 of file compress.c.

343{
344 if (!m)
345 return false;
346
347 /* If this succeeds, we know there's an open-hook */
348 struct CompressInfo *ci = set_compress_info(m);
349 if (!ci)
350 return false;
351
352 /* We have an open-hook, so to append we need an append-hook,
353 * or a close-hook. */
354 if (ci->cmd_append || ci->cmd_close)
355 return true;
356
357 mutt_error(_("Can't append without an append-hook or close-hook : %s"), mailbox_path(m));
358 return false;
359}
static struct CompressInfo * set_compress_info(struct Mailbox *m)
Find the compress hooks for a mailbox.
Definition compress.c:243
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_comp_can_read()

bool mutt_comp_can_read ( const char * path)

Can we read from this file?

Parameters
pathPathname of file to be tested
Return values
trueYes, we can read the file
falseNo, we can't read the file

Search for an 'open-hook' with a regex that matches the path.

A match means it's our responsibility to open the file.

Definition at line 371 of file compress.c.

372{
373 if (!path)
374 return false;
375
377 return true;
378
379 return false;
380}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_comp_valid_command()

int mutt_comp_valid_command ( const char * cmd)

Is this command string allowed?

Parameters
cmdCommand string
Return values
1Valid command
0"%f" and/or "%t" is missing

A valid command string must have both "%f" (from file) and "%t" (to file). We don't check if we can actually run the command.

Definition at line 391 of file compress.c.

392{
393 if (!cmd)
394 return 0;
395
396 return strstr(cmd, "%f") && strstr(cmd, "%t");
397}
+ Here is the caller graph for this function:

Variable Documentation

◆ CompCommands

const struct Command CompCommands[]
static
Initial value:
= {
N_("Define command to append to a compressed mailbox"),
N_("append-hook <regex> <shell-command>"),
"optionalfeatures.html#append-hook" },
N_("Define command to close a compressed mailbox"),
N_("close-hook <regex> <shell-command>"),
"optionalfeatures.html#close-hook" },
N_("Define command to open a compressed mailbox"),
N_("open-hook <regex> <shell-command>"),
"optionalfeatures.html#open-hook" },
{ NULL, NULL, 0, NULL, NULL, NULL, CF_NO_FLAGS },
}
#define CF_NO_FLAGS
No flags are set.
Definition command.h:46
enum CommandResult parse_hook_compress(const struct Command *cmd, struct Buffer *line, struct Buffer *err)
Parse compress hook commands - Implements Command::parse() -.
Definition hook.c:927
#define N_(a)
Definition message.h:32

Compression Commands.

Definition at line 62 of file compress.c.

62 {
63 // clang-format off
64 { "append-hook", parse_hook_compress, MUTT_APPEND_HOOK,
65 N_("Define command to append to a compressed mailbox"),
66 N_("append-hook <regex> <shell-command>"),
67 "optionalfeatures.html#append-hook" },
68 { "close-hook", parse_hook_compress, MUTT_CLOSE_HOOK,
69 N_("Define command to close a compressed mailbox"),
70 N_("close-hook <regex> <shell-command>"),
71 "optionalfeatures.html#close-hook" },
72 { "open-hook", parse_hook_compress, MUTT_OPEN_HOOK,
73 N_("Define command to open a compressed mailbox"),
74 N_("open-hook <regex> <shell-command>"),
75 "optionalfeatures.html#open-hook" },
76
77 { NULL, NULL, 0, NULL, NULL, NULL, CF_NO_FLAGS },
78 // clang-format on
79};

◆ CompressFormatDef

const struct ExpandoDefinition CompressFormatDef[]
Initial value:
= {
{ "f", "from", ED_COMPRESS, ED_CMP_FROM, NULL },
{ "t", "to", ED_COMPRESS, ED_CMP_TO, NULL },
{ NULL, NULL, 0, -1, NULL }
}
@ ED_CMP_FROM
'from' path
Definition lib.h:50
@ ED_CMP_TO
'to' path
Definition lib.h:51
@ ED_COMPRESS
Compress ED_CMP_ ExpandoDataCompress.
Definition domain.h:40

Expando definitions.

Config:

  • append-hook
  • close-hook
  • open-hook

Definition at line 89 of file compress.c.

89 {
90 // clang-format off
91 { "f", "from", ED_COMPRESS, ED_CMP_FROM, NULL },
92 { "t", "to", ED_COMPRESS, ED_CMP_TO, NULL },
93 { NULL, NULL, 0, -1, NULL }
94 // clang-format on
95};