NeoMutt  2022-04-29-145-g9b6a0e
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 
45 struct ConnAccount;
46 
50 struct BodyCache
51 {
52  char *path;
53 };
54 
63 static int bcache_path(struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
64 {
65  char host[256];
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 
114 static 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 
144 struct 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 
165 void mutt_bcache_close(struct BodyCache **bcache)
166 {
167  if (!bcache || !*bcache)
168  return;
169  FREE(&(*bcache)->path);
170  FREE(bcache);
171 }
172 
180 FILE *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 
208 FILE *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 
248 int 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);
254  mutt_buffer_pool_release(&tmpid);
255  return rc;
256 }
257 
265 int 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 
288 int 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 
330 int 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 
358 out:
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
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:144
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:248
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
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
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:180
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:238
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:223
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
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.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
#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