NeoMutt  2024-12-12-14-g7b49f7
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
bcache.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <dirent.h>
32#include <errno.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include "mutt/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "conn/lib.h"
42#include "lib.h"
43#include "muttlib.h"
44
49{
50 char *path;
51};
52
61static int bcache_path(struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
62{
63 const char *const c_message_cache_dir = cs_subset_path(NeoMutt->sub, "message_cache_dir");
64 if (!account || !c_message_cache_dir || !bcache)
65 return -1;
66
67 struct stat st = { 0 };
68 if (!((stat(c_message_cache_dir, &st) == 0) && S_ISDIR(st.st_mode)))
69 {
70 mutt_error(_("Cache disabled, $message_cache_dir isn't a directory: %s"), c_message_cache_dir);
71 return -1;
72 }
73
74 struct Url url = { 0 };
75 struct Buffer *host = buf_pool_get();
76
77 /* make up a Url we can turn into a string */
78 account_to_url(account, &url);
79 /* account_to_url() just sets up some pointers;
80 * if this ever changes, we have a memleak here */
81 url.path = NULL;
82 if (url_tostring(&url, host->data, host->dsize, U_PATH) < 0)
83 {
84 mutt_debug(LL_DEBUG1, "URL to string failed\n");
85 buf_pool_release(&host);
86 return -1;
87 }
88 buf_fix_dptr(host);
89
90 buf_addstr(host, mailbox);
91
92 struct Buffer *path = buf_pool_get();
93 struct Buffer *dst = buf_pool_get();
94 mutt_encode_path(path, buf_string(host));
95
96 buf_printf(dst, "%s/%s", c_message_cache_dir, buf_string(path));
97 if (*(dst->dptr - 1) != '/')
98 buf_addch(dst, '/');
99
100 mutt_debug(LL_DEBUG3, "path: '%s'\n", buf_string(dst));
101 bcache->path = buf_strdup(dst);
102
103 buf_pool_release(&host);
104 buf_pool_release(&path);
105 buf_pool_release(&dst);
106 return 0;
107}
108
117static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
118{
119 if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
120 return -1;
121
122 struct Buffer *path = buf_pool_get();
123 struct Buffer *newpath = buf_pool_get();
124
125 buf_printf(path, "%s%s", bcache->path, id);
126 buf_printf(newpath, "%s%s", bcache->path, newid);
127
128 mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", buf_string(path), buf_string(newpath));
129
130 int rc = rename(buf_string(path), buf_string(newpath));
131 buf_pool_release(&path);
132 buf_pool_release(&newpath);
133 return rc;
134}
135
146struct BodyCache *mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
147{
148 if (!account)
149 return NULL;
150
151 struct BodyCache *bcache = MUTT_MEM_CALLOC(1, struct BodyCache);
152 if (bcache_path(account, mailbox, bcache) < 0)
153 {
154 mutt_bcache_close(&bcache);
155 return NULL;
156 }
157
158 return bcache;
159}
160
167void mutt_bcache_close(struct BodyCache **ptr)
168{
169 if (!ptr || !*ptr)
170 return;
171
172 struct BodyCache *bcache = *ptr;
173 FREE(&bcache->path);
174
175 FREE(ptr);
176}
177
185FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
186{
187 if (!id || (*id == '\0') || !bcache)
188 return NULL;
189
190 struct Buffer *path = buf_pool_get();
191 buf_addstr(path, bcache->path);
192 buf_addstr(path, id);
193
194 FILE *fp = mutt_file_fopen(buf_string(path), "r");
195
196 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", buf_string(path), fp ? "yes" : "no");
197
198 buf_pool_release(&path);
199 return fp;
200}
201
212FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
213{
214 if (!id || (*id == '\0') || !bcache)
215 return NULL;
216
217 struct Buffer *path = buf_pool_get();
218 buf_printf(path, "%s%s%s", bcache->path, id, ".tmp");
219
220 struct stat st = { 0 };
221 if (stat(bcache->path, &st) == 0)
222 {
223 if (!S_ISDIR(st.st_mode))
224 {
225 mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
226 return NULL;
227 }
228 }
229 else
230 {
231 if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
232 {
233 mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
234 return NULL;
235 }
236 }
237
238 mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", buf_string(path));
239
240 FILE *fp = mutt_file_fopen(buf_string(path), "w+");
241 buf_pool_release(&path);
242 return fp;
243}
244
252int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
253{
254 struct Buffer *tmpid = buf_pool_get();
255 buf_printf(tmpid, "%s.tmp", id);
256
257 int rc = mutt_bcache_move(bcache, buf_string(tmpid), id);
258 buf_pool_release(&tmpid);
259 return rc;
260}
261
269int mutt_bcache_del(struct BodyCache *bcache, const char *id)
270{
271 if (!id || (*id == '\0') || !bcache)
272 return -1;
273
274 struct Buffer *path = buf_pool_get();
275 buf_addstr(path, bcache->path);
276 buf_addstr(path, id);
277
278 mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", buf_string(path));
279
280 int rc = unlink(buf_string(path));
281 buf_pool_release(&path);
282 return rc;
283}
284
292int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
293{
294 if (!id || (*id == '\0') || !bcache)
295 return -1;
296
297 struct Buffer *path = buf_pool_get();
298 buf_addstr(path, bcache->path);
299 buf_addstr(path, id);
300
301 int rc = 0;
302 struct stat st = { 0 };
303 if (stat(buf_string(path), &st) < 0)
304 rc = -1;
305 else
306 rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
307
308 mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", buf_string(path),
309 (rc == 0) ? "yes" : "no");
310
311 buf_pool_release(&path);
312 return rc;
313}
314
334int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
335{
336 DIR *dir = NULL;
337 struct dirent *de = NULL;
338 int rc = -1;
339
340 if (!bcache || !(dir = mutt_file_opendir(bcache->path, MUTT_OPENDIR_NONE)))
341 goto out;
342
343 rc = 0;
344
345 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
346
347 while ((de = readdir(dir)))
348 {
349 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
350 {
351 continue;
352 }
353
354 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
355
356 if (want_id && (want_id(de->d_name, bcache, data) != 0))
357 goto out;
358
359 rc++;
360 }
361
362out:
363 if (dir)
364 {
365 if (closedir(dir) < 0)
366 rc = -1;
367 }
368 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
369 return rc;
370}
int(* bcache_list_t)(const char *id, struct BodyCache *bcache, void *data)
Definition: lib.h:54
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition: bcache.c:292
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:252
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:146
static int bcache_path(struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
Create the cache path for a given account/mailbox.
Definition: bcache.c:61
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:334
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:185
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition: bcache.c:167
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:269
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:212
static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
Change the id of a message in the cache.
Definition: bcache.c:117
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:182
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:168
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
Structs that make up an email.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:872
Some miscellaneous functions.
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
Key value store.
Local cache of email bodies.
Definition: bcache.c:49
char * path
On-disk path to the file.
Definition: bcache.c:50
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
Login details for a remote server.
Definition: connaccount.h:53
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * path
Path.
Definition: url.h:75
int url_tostring(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:423
#define U_PATH
Definition: url.h:50