NeoMutt  2022-04-29-249-gaae397
Teaching an old dog new tricks
DOXYGEN
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_cachedir = cs_subset_path(NeoMutt->sub, "message_cachedir");
69 if (!account || !c_message_cachedir || !bcache)
70 return -1;
71
72 struct stat st = { 0 };
73 if (!((stat(c_message_cachedir, &st) == 0) && S_ISDIR(st.st_mode)))
74 {
75 mutt_error(_("Cache disabled, $message_cachedir isn't a directory: %s"), c_message_cachedir);
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 = mutt_buffer_pool_get();
91 struct Buffer *dst = mutt_buffer_pool_get();
92 mutt_encode_path(path, NONULL(mailbox));
93
94 mutt_buffer_printf(dst, "%s/%s%s", c_message_cachedir, host, mutt_buffer_string(path));
95 if (*(dst->dptr - 1) != '/')
96 mutt_buffer_addch(dst, '/');
97
98 mutt_debug(LL_DEBUG3, "path: '%s'\n", mutt_buffer_string(dst));
99 bcache->path = mutt_buffer_strdup(dst);
100
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 = mutt_buffer_pool_get();
120 struct Buffer *newpath = mutt_buffer_pool_get();
121
122 mutt_buffer_printf(path, "%s%s", bcache->path, id);
123 mutt_buffer_printf(newpath, "%s%s", bcache->path, newid);
124
125 mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", mutt_buffer_string(path),
126 mutt_buffer_string(newpath));
127
128 int rc = rename(mutt_buffer_string(path), mutt_buffer_string(newpath));
130 mutt_buffer_pool_release(&newpath);
131 return rc;
132}
133
144struct BodyCache *mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
145{
146 if (!account)
147 return NULL;
148
149 struct BodyCache *bcache = mutt_mem_calloc(1, sizeof(struct BodyCache));
150 if (bcache_path(account, mailbox, bcache) < 0)
151 {
152 mutt_bcache_close(&bcache);
153 return NULL;
154 }
155
156 return bcache;
157}
158
165void mutt_bcache_close(struct BodyCache **bcache)
166{
167 if (!bcache || !*bcache)
168 return;
169 FREE(&(*bcache)->path);
170 FREE(bcache);
171}
172
180FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
181{
182 if (!id || (*id == '\0') || !bcache)
183 return NULL;
184
185 struct Buffer *path = mutt_buffer_pool_get();
186 mutt_buffer_addstr(path, bcache->path);
187 mutt_buffer_addstr(path, id);
188
189 FILE *fp = mutt_file_fopen(mutt_buffer_string(path), "r");
190
191 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", mutt_buffer_string(path),
192 fp ? "yes" : "no");
193
195 return fp;
196}
197
208FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
209{
210 if (!id || (*id == '\0') || !bcache)
211 return NULL;
212
213 struct Buffer *path = mutt_buffer_pool_get();
214 mutt_buffer_printf(path, "%s%s%s", bcache->path, id, ".tmp");
215
216 struct stat st = { 0 };
217 if (stat(bcache->path, &st) == 0)
218 {
219 if (!S_ISDIR(st.st_mode))
220 {
221 mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
222 return NULL;
223 }
224 }
225 else
226 {
227 if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
228 {
229 mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
230 return NULL;
231 }
232 }
233
234 mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", mutt_buffer_string(path));
235
236 FILE *fp = mutt_file_fopen(mutt_buffer_string(path), "w+");
238 return fp;
239}
240
248int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
249{
250 struct Buffer *tmpid = mutt_buffer_pool_get();
251 mutt_buffer_printf(tmpid, "%s.tmp", id);
252
253 int rc = mutt_bcache_move(bcache, mutt_buffer_string(tmpid), id);
255 return rc;
256}
257
265int mutt_bcache_del(struct BodyCache *bcache, const char *id)
266{
267 if (!id || (*id == '\0') || !bcache)
268 return -1;
269
270 struct Buffer *path = mutt_buffer_pool_get();
271 mutt_buffer_addstr(path, bcache->path);
272 mutt_buffer_addstr(path, id);
273
274 mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", mutt_buffer_string(path));
275
276 int rc = unlink(mutt_buffer_string(path));
278 return rc;
279}
280
288int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
289{
290 if (!id || (*id == '\0') || !bcache)
291 return -1;
292
293 struct Buffer *path = mutt_buffer_pool_get();
294 mutt_buffer_addstr(path, bcache->path);
295 mutt_buffer_addstr(path, id);
296
297 int rc = 0;
298 struct stat st = { 0 };
299 if (stat(mutt_buffer_string(path), &st) < 0)
300 rc = -1;
301 else
302 rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
303
304 mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", mutt_buffer_string(path),
305 (rc == 0) ? "yes" : "no");
306
308 return rc;
309}
310
330int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
331{
332 DIR *d = NULL;
333 struct dirent *de = NULL;
334 int rc = -1;
335
336 if (!bcache || !(d = opendir(bcache->path)))
337 goto out;
338
339 rc = 0;
340
341 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
342
343 while ((de = readdir(d)))
344 {
345 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
346 {
347 continue;
348 }
349
350 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
351
352 if (want_id && (want_id(de->d_name, bcache, data) != 0))
353 goto out;
354
355 rc++;
356 }
357
358out:
359 if (d)
360 {
361 if (closedir(d) < 0)
362 rc = -1;
363 }
364 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
365 return rc;
366}
int(* bcache_list_t)(const char *id, struct BodyCache *bcache, void *data)
Definition: lib.h:55
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition: bcache.c:288
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:248
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:144
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:330
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:180
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:265
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:208
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:165
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
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
Structs that make up an email.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
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:43
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:227
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
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:1484
Some miscellaneous functions.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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:34
char * dptr
Current read/write position.
Definition: buffer.h:36
Login details for a remote server.
Definition: connaccount.h:53
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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(struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:418
#define U_PATH
Definition: url.h:50