NeoMutt  2024-04-16-36-g75b6fb
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 char host[256] = { 0 };
66 struct Url url = { 0 };
67
68 const char *const c_message_cache_dir = cs_subset_path(NeoMutt->sub, "message_cache_dir");
69 if (!account || !c_message_cache_dir || !bcache)
70 return -1;
71
72 struct stat st = { 0 };
73 if (!((stat(c_message_cache_dir, &st) == 0) && S_ISDIR(st.st_mode)))
74 {
75 mutt_error(_("Cache disabled, $message_cache_dir isn't a directory: %s"), c_message_cache_dir);
76 return -1;
77 }
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, sizeof(host), U_PATH) < 0)
85 {
86 mutt_debug(LL_DEBUG1, "URL to string failed\n");
87 return -1;
88 }
89
90 struct Buffer *path = buf_pool_get();
91 struct Buffer *dst = buf_pool_get();
92 mutt_encode_path(path, NONULL(mailbox));
93
94 buf_printf(dst, "%s/%s%s", c_message_cache_dir, host, buf_string(path));
95 if (*(dst->dptr - 1) != '/')
96 buf_addch(dst, '/');
97
98 mutt_debug(LL_DEBUG3, "path: '%s'\n", buf_string(dst));
99 bcache->path = buf_strdup(dst);
100
101 buf_pool_release(&path);
102 buf_pool_release(&dst);
103 return 0;
104}
105
114static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
115{
116 if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
117 return -1;
118
119 struct Buffer *path = buf_pool_get();
120 struct Buffer *newpath = buf_pool_get();
121
122 buf_printf(path, "%s%s", bcache->path, id);
123 buf_printf(newpath, "%s%s", bcache->path, newid);
124
125 mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", buf_string(path), buf_string(newpath));
126
127 int rc = rename(buf_string(path), buf_string(newpath));
128 buf_pool_release(&path);
129 buf_pool_release(&newpath);
130 return rc;
131}
132
143struct BodyCache *mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
144{
145 if (!account)
146 return NULL;
147
148 struct BodyCache *bcache = mutt_mem_calloc(1, sizeof(struct BodyCache));
149 if (bcache_path(account, mailbox, bcache) < 0)
150 {
151 mutt_bcache_close(&bcache);
152 return NULL;
153 }
154
155 return bcache;
156}
157
164void mutt_bcache_close(struct BodyCache **ptr)
165{
166 if (!ptr || !*ptr)
167 return;
168
169 struct BodyCache *bcache = *ptr;
170 FREE(&bcache->path);
171
172 FREE(ptr);
173}
174
182FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
183{
184 if (!id || (*id == '\0') || !bcache)
185 return NULL;
186
187 struct Buffer *path = buf_pool_get();
188 buf_addstr(path, bcache->path);
189 buf_addstr(path, id);
190
191 FILE *fp = mutt_file_fopen(buf_string(path), "r");
192
193 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", buf_string(path), fp ? "yes" : "no");
194
195 buf_pool_release(&path);
196 return fp;
197}
198
209FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
210{
211 if (!id || (*id == '\0') || !bcache)
212 return NULL;
213
214 struct Buffer *path = buf_pool_get();
215 buf_printf(path, "%s%s%s", bcache->path, id, ".tmp");
216
217 struct stat st = { 0 };
218 if (stat(bcache->path, &st) == 0)
219 {
220 if (!S_ISDIR(st.st_mode))
221 {
222 mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
223 return NULL;
224 }
225 }
226 else
227 {
228 if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
229 {
230 mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
231 return NULL;
232 }
233 }
234
235 mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", buf_string(path));
236
237 FILE *fp = mutt_file_fopen(buf_string(path), "w+");
238 buf_pool_release(&path);
239 return fp;
240}
241
249int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
250{
251 struct Buffer *tmpid = buf_pool_get();
252 buf_printf(tmpid, "%s.tmp", id);
253
254 int rc = mutt_bcache_move(bcache, buf_string(tmpid), id);
255 buf_pool_release(&tmpid);
256 return rc;
257}
258
266int mutt_bcache_del(struct BodyCache *bcache, const char *id)
267{
268 if (!id || (*id == '\0') || !bcache)
269 return -1;
270
271 struct Buffer *path = buf_pool_get();
272 buf_addstr(path, bcache->path);
273 buf_addstr(path, id);
274
275 mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", buf_string(path));
276
277 int rc = unlink(buf_string(path));
278 buf_pool_release(&path);
279 return rc;
280}
281
289int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
290{
291 if (!id || (*id == '\0') || !bcache)
292 return -1;
293
294 struct Buffer *path = buf_pool_get();
295 buf_addstr(path, bcache->path);
296 buf_addstr(path, id);
297
298 int rc = 0;
299 struct stat st = { 0 };
300 if (stat(buf_string(path), &st) < 0)
301 rc = -1;
302 else
303 rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
304
305 mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", buf_string(path),
306 (rc == 0) ? "yes" : "no");
307
308 buf_pool_release(&path);
309 return rc;
310}
311
331int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
332{
333 DIR *dir = NULL;
334 struct dirent *de = NULL;
335 int rc = -1;
336
337 if (!bcache || !(dir = mutt_file_opendir(bcache->path, MUTT_OPENDIR_NONE)))
338 goto out;
339
340 rc = 0;
341
342 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
343
344 while ((de = readdir(dir)))
345 {
346 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
347 {
348 continue;
349 }
350
351 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
352
353 if (want_id && (want_id(de->d_name, bcache, data) != 0))
354 goto out;
355
356 rc++;
357 }
358
359out:
360 if (dir)
361 {
362 if (closedir(dir) < 0)
363 rc = -1;
364 }
365 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
366 return rc;
367}
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:289
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:249
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:143
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:331
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:182
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition: bcache.c:164
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:266
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:209
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:114
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
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:169
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:971
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:640
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:74
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
#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:50
#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:907
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.
#define NONULL(x)
Definition: string2.h:37
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
Login details for a remote server.
Definition: connaccount.h:53
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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