NeoMutt  2021-02-05-666-ge300cd
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 =
69  cs_subset_path(NeoMutt->sub, "message_cachedir");
70  if (!account || !c_message_cachedir || !bcache)
71  return -1;
72 
73  struct stat sb;
74  if (!((stat(c_message_cachedir, &sb) == 0) && S_ISDIR(sb.st_mode)))
75  {
76  mutt_error(_("Cache disabled, $message_cachedir isn't a directory: %s"), c_message_cachedir);
77  return -1;
78  }
79 
80  /* make up a Url we can turn into a string */
81  mutt_account_tourl(account, &url);
82  /* mutt_account_tourl() just sets up some pointers;
83  * if this ever changes, we have a memleak here */
84  url.path = NULL;
85  if (url_tostring(&url, host, sizeof(host), U_PATH) < 0)
86  {
87  mutt_debug(LL_DEBUG1, "URL to string failed\n");
88  return -1;
89  }
90 
91  struct Buffer *path = mutt_buffer_pool_get();
92  struct Buffer *dst = mutt_buffer_pool_get();
93  mutt_encode_path(path, NONULL(mailbox));
94 
95  mutt_buffer_printf(dst, "%s/%s%s", c_message_cachedir, host, mutt_buffer_string(path));
96  if (*(dst->dptr - 1) != '/')
97  mutt_buffer_addch(dst, '/');
98 
99  mutt_debug(LL_DEBUG3, "path: '%s'\n", mutt_buffer_string(dst));
100  bcache->path = mutt_buffer_strdup(dst);
101 
104  return 0;
105 }
106 
113 static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
114 {
115  if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
116  return -1;
117 
118  struct Buffer *path = mutt_buffer_pool_get();
119  struct Buffer *newpath = mutt_buffer_pool_get();
120 
121  mutt_buffer_printf(path, "%s%s", bcache->path, id);
122  mutt_buffer_printf(newpath, "%s%s", bcache->path, newid);
123 
124  mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", mutt_buffer_string(path),
125  mutt_buffer_string(newpath));
126 
127  int rc = rename(mutt_buffer_string(path), mutt_buffer_string(newpath));
129  mutt_buffer_pool_release(&newpath);
130  return rc;
131 }
132 
143 struct 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 
164 void mutt_bcache_close(struct BodyCache **bcache)
165 {
166  if (!bcache || !*bcache)
167  return;
168  FREE(&(*bcache)->path);
169  FREE(bcache);
170 }
171 
179 FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
180 {
181  if (!id || (*id == '\0') || !bcache)
182  return NULL;
183 
184  struct Buffer *path = mutt_buffer_pool_get();
185  mutt_buffer_addstr(path, bcache->path);
186  mutt_buffer_addstr(path, id);
187 
188  FILE *fp = mutt_file_fopen(mutt_buffer_string(path), "r");
189 
190  mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", mutt_buffer_string(path),
191  fp ? "yes" : "no");
192 
194  return fp;
195 }
196 
207 FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
208 {
209  if (!id || (*id == '\0') || !bcache)
210  return NULL;
211 
212  struct Buffer *path = mutt_buffer_pool_get();
213  mutt_buffer_printf(path, "%s%s%s", bcache->path, id, ".tmp");
214 
215  struct stat sb;
216  if (stat(bcache->path, &sb) == 0)
217  {
218  if (!S_ISDIR(sb.st_mode))
219  {
220  mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
221  return NULL;
222  }
223  }
224  else
225  {
226  if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
227  {
228  mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
229  return NULL;
230  }
231  }
232 
233  mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", path);
234 
235  FILE *fp = mutt_file_fopen(mutt_buffer_string(path), "w+");
237  return fp;
238 }
239 
247 int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
248 {
249  struct Buffer *tmpid = mutt_buffer_pool_get();
250  mutt_buffer_printf(tmpid, "%s.tmp", id);
251 
252  int rc = mutt_bcache_move(bcache, mutt_buffer_string(tmpid), id);
253  mutt_buffer_pool_release(&tmpid);
254  return rc;
255 }
256 
264 int mutt_bcache_del(struct BodyCache *bcache, const char *id)
265 {
266  if (!id || (*id == '\0') || !bcache)
267  return -1;
268 
269  struct Buffer *path = mutt_buffer_pool_get();
270  mutt_buffer_addstr(path, bcache->path);
271  mutt_buffer_addstr(path, id);
272 
273  mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", mutt_buffer_string(path));
274 
275  int rc = unlink(mutt_buffer_string(path));
277  return rc;
278 }
279 
287 int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
288 {
289  if (!id || (*id == '\0') || !bcache)
290  return -1;
291 
292  struct Buffer *path = mutt_buffer_pool_get();
293  mutt_buffer_addstr(path, bcache->path);
294  mutt_buffer_addstr(path, id);
295 
296  int rc = 0;
297  struct stat st;
298  if (stat(mutt_buffer_string(path), &st) < 0)
299  rc = -1;
300  else
301  rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
302 
303  mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", mutt_buffer_string(path),
304  (rc == 0) ? "yes" : "no");
305 
307  return rc;
308 }
309 
329 int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
330 {
331  DIR *d = NULL;
332  struct dirent *de = NULL;
333  int rc = -1;
334 
335  if (!bcache || !(d = opendir(bcache->path)))
336  goto out;
337 
338  rc = 0;
339 
340  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
341 
342  while ((de = readdir(d)))
343  {
344  if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
345  {
346  continue;
347  }
348 
349  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
350 
351  if (want_id && (want_id(de->d_name, bcache, data) != 0))
352  goto out;
353 
354  rc++;
355  }
356 
357 out:
358  if (d)
359  {
360  if (closedir(d) < 0)
361  rc = -1;
362  }
363  mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
364  return rc;
365 }
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:143
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:68
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:247
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:52
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
Container for Accounts, Notifications.
Definition: neomutt.h:36
Convenience wrapper for the config headers.
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:329
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Some miscellaneous functions.
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:179
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:877
Convenience wrapper for the core headers.
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition: bcache.c:287
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
Body Caching - local copies of email bodies.
FILE * mutt_bcache_put(struct BodyCache *bcache, const char *id)
Create a file in the Body Cache.
Definition: bcache.c:207
ConnAccount object used by POP and IMAP.
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
char * dptr
Current read/write position.
Definition: buffer.h:36
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
int(* bcache_list_t)(const char *id, struct BodyCache *bcache, void *data)
Prototype for mutt_bcache_list() callback.
Definition: lib.h:52
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:264
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
Login details for a remote server.
Definition: connaccount.h:51
char * path
Path.
Definition: url.h:75
Local cache of email bodies.
Definition: bcache.c:50
Log at debug level 1.
Definition: logging.h:40
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
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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:113
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:164
Log at debug level 3.
Definition: logging.h:42
#define U_PATH
Definition: url.h:50
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to &#39;us-ascii&#39;.
Definition: muttlib.c:1490