NeoMutt  2024-04-25-89-g194907
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 "lib.h"
42#include "mutt_account.h"
43#include "muttlib.h"
44
45struct ConnAccount;
46
51{
52 char *path;
53};
54
63static int bcache_path(struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
64{
65 const char *const c_message_cache_dir = cs_subset_path(NeoMutt->sub, "message_cache_dir");
66 if (!account || !c_message_cache_dir || !bcache)
67 return -1;
68
69 struct stat st = { 0 };
70 if (!((stat(c_message_cache_dir, &st) == 0) && S_ISDIR(st.st_mode)))
71 {
72 mutt_error(_("Cache disabled, $message_cache_dir isn't a directory: %s"), c_message_cache_dir);
73 return -1;
74 }
75
76 struct Url url = { 0 };
77 struct Buffer *host = buf_pool_get();
78
79 /* make up a Url we can turn into a string */
80 mutt_account_tourl(account, &url);
81 /* mutt_account_tourl() just sets up some pointers;
82 * if this ever changes, we have a memleak here */
83 url.path = NULL;
84 if (url_tostring(&url, host->data, host->dsize, U_PATH) < 0)
85 {
86 mutt_debug(LL_DEBUG1, "URL to string failed\n");
87 buf_pool_release(&host);
88 return -1;
89 }
90 buf_fix_dptr(host);
91
92 buf_addstr(host, mailbox);
93
94 struct Buffer *path = buf_pool_get();
95 struct Buffer *dst = buf_pool_get();
96 mutt_encode_path(path, buf_string(host));
97
98 buf_printf(dst, "%s/%s", c_message_cache_dir, buf_string(path));
99 if (*(dst->dptr - 1) != '/')
100 buf_addch(dst, '/');
101
102 mutt_debug(LL_DEBUG3, "path: '%s'\n", buf_string(dst));
103 bcache->path = buf_strdup(dst);
104
105 buf_pool_release(&host);
106 buf_pool_release(&path);
107 buf_pool_release(&dst);
108 return 0;
109}
110
119static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
120{
121 if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
122 return -1;
123
124 struct Buffer *path = buf_pool_get();
125 struct Buffer *newpath = buf_pool_get();
126
127 buf_printf(path, "%s%s", bcache->path, id);
128 buf_printf(newpath, "%s%s", bcache->path, newid);
129
130 mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", buf_string(path), buf_string(newpath));
131
132 int rc = rename(buf_string(path), buf_string(newpath));
133 buf_pool_release(&path);
134 buf_pool_release(&newpath);
135 return rc;
136}
137
148struct BodyCache *mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
149{
150 if (!account)
151 return NULL;
152
153 struct BodyCache *bcache = mutt_mem_calloc(1, sizeof(struct BodyCache));
154 if (bcache_path(account, mailbox, bcache) < 0)
155 {
156 mutt_bcache_close(&bcache);
157 return NULL;
158 }
159
160 return bcache;
161}
162
169void mutt_bcache_close(struct BodyCache **ptr)
170{
171 if (!ptr || !*ptr)
172 return;
173
174 struct BodyCache *bcache = *ptr;
175 FREE(&bcache->path);
176
177 FREE(ptr);
178}
179
187FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
188{
189 if (!id || (*id == '\0') || !bcache)
190 return NULL;
191
192 struct Buffer *path = buf_pool_get();
193 buf_addstr(path, bcache->path);
194 buf_addstr(path, id);
195
196 FILE *fp = mutt_file_fopen(buf_string(path), "r");
197
198 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", buf_string(path), fp ? "yes" : "no");
199
200 buf_pool_release(&path);
201 return fp;
202}
203
214FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
215{
216 if (!id || (*id == '\0') || !bcache)
217 return NULL;
218
219 struct Buffer *path = buf_pool_get();
220 buf_printf(path, "%s%s%s", bcache->path, id, ".tmp");
221
222 struct stat st = { 0 };
223 if (stat(bcache->path, &st) == 0)
224 {
225 if (!S_ISDIR(st.st_mode))
226 {
227 mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
228 return NULL;
229 }
230 }
231 else
232 {
233 if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
234 {
235 mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
236 return NULL;
237 }
238 }
239
240 mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", buf_string(path));
241
242 FILE *fp = mutt_file_fopen(buf_string(path), "w+");
243 buf_pool_release(&path);
244 return fp;
245}
246
254int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
255{
256 struct Buffer *tmpid = buf_pool_get();
257 buf_printf(tmpid, "%s.tmp", id);
258
259 int rc = mutt_bcache_move(bcache, buf_string(tmpid), id);
260 buf_pool_release(&tmpid);
261 return rc;
262}
263
271int mutt_bcache_del(struct BodyCache *bcache, const char *id)
272{
273 if (!id || (*id == '\0') || !bcache)
274 return -1;
275
276 struct Buffer *path = buf_pool_get();
277 buf_addstr(path, bcache->path);
278 buf_addstr(path, id);
279
280 mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", buf_string(path));
281
282 int rc = unlink(buf_string(path));
283 buf_pool_release(&path);
284 return rc;
285}
286
294int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
295{
296 if (!id || (*id == '\0') || !bcache)
297 return -1;
298
299 struct Buffer *path = buf_pool_get();
300 buf_addstr(path, bcache->path);
301 buf_addstr(path, id);
302
303 int rc = 0;
304 struct stat st = { 0 };
305 if (stat(buf_string(path), &st) < 0)
306 rc = -1;
307 else
308 rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
309
310 mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", buf_string(path),
311 (rc == 0) ? "yes" : "no");
312
313 buf_pool_release(&path);
314 return rc;
315}
316
336int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
337{
338 DIR *dir = NULL;
339 struct dirent *de = NULL;
340 int rc = -1;
341
342 if (!bcache || !(dir = mutt_file_opendir(bcache->path, MUTT_OPENDIR_NONE)))
343 goto out;
344
345 rc = 0;
346
347 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
348
349 while ((de = readdir(dir)))
350 {
351 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
352 {
353 continue;
354 }
355
356 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
357
358 if (want_id && (want_id(de->d_name, bcache, data) != 0))
359 goto out;
360
361 rc++;
362 }
363
364out:
365 if (dir)
366 {
367 if (closedir(dir) < 0)
368 rc = -1;
369 }
370 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
371 return rc;
372}
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:294
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:254
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:148
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:63
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:336
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:187
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition: bcache.c:169
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:271
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:214
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:119
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.
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:74
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:148
#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
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
#define FREE(x)
Definition: memory.h:45
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 mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
ConnAccount object used by POP and IMAP.
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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
Key value store.
Local cache of email bodies.
Definition: bcache.c:51
char * path
On-disk path to the file.
Definition: bcache.c:52
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