NeoMutt  2020-06-26-89-g172cd3
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 <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include "mutt/lib.h"
39 #include "email/lib.h"
40 #include "mutt_account.h"
41 #include "muttlib.h"
42 #include "bcache/lib.h"
43 
44 struct ConnAccount;
45 
46 /* These Config Variables are only used in bcache.c */
49 
53 struct BodyCache
54 {
55  char *path;
56 };
57 
66 static int bcache_path(struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
67 {
68  char host[256];
69  struct Url url = { 0 };
70 
71  if (!account || !C_MessageCachedir || !bcache)
72  return -1;
73 
74  /* make up a Url we can turn into a string */
75  mutt_account_tourl(account, &url);
76  /* mutt_account_tourl() just sets up some pointers;
77  * if this ever changes, we have a memleak here */
78  url.path = NULL;
79  if (url_tostring(&url, host, sizeof(host), U_PATH) < 0)
80  {
81  mutt_debug(LL_DEBUG1, "URL to string failed\n");
82  return -1;
83  }
84 
85  struct Buffer *path = mutt_buffer_pool_get();
86  struct Buffer *dst = mutt_buffer_pool_get();
87  mutt_encode_path(path, NONULL(mailbox));
88 
89  mutt_buffer_printf(dst, "%s/%s%s", C_MessageCachedir, host, mutt_b2s(path));
90  if (*(dst->dptr - 1) != '/')
91  mutt_buffer_addch(dst, '/');
92 
93  mutt_debug(LL_DEBUG3, "path: '%s'\n", mutt_b2s(dst));
94  bcache->path = mutt_buffer_strdup(dst);
95 
98  return 0;
99 }
100 
107 static int mutt_bcache_move(struct BodyCache *bcache, const char *id, const char *newid)
108 {
109  if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
110  return -1;
111 
112  struct Buffer *path = mutt_buffer_pool_get();
113  struct Buffer *newpath = mutt_buffer_pool_get();
114 
115  mutt_buffer_printf(path, "%s%s", bcache->path, id);
116  mutt_buffer_printf(newpath, "%s%s", bcache->path, newid);
117 
118  mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", mutt_b2s(path), mutt_b2s(newpath));
119 
120  int rc = rename(mutt_b2s(path), mutt_b2s(newpath));
122  mutt_buffer_pool_release(&newpath);
123  return rc;
124 }
125 
136 struct BodyCache *mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
137 {
138  if (!account)
139  return NULL;
140 
141  struct BodyCache *bcache = mutt_mem_calloc(1, sizeof(struct BodyCache));
142  if (bcache_path(account, mailbox, bcache) < 0)
143  {
144  mutt_bcache_close(&bcache);
145  return NULL;
146  }
147 
148  return bcache;
149 }
150 
157 void mutt_bcache_close(struct BodyCache **bcache)
158 {
159  if (!bcache || !*bcache)
160  return;
161  FREE(&(*bcache)->path);
162  FREE(bcache);
163 }
164 
172 FILE *mutt_bcache_get(struct BodyCache *bcache, const char *id)
173 {
174  if (!id || (*id == '\0') || !bcache)
175  return NULL;
176 
177  struct Buffer *path = mutt_buffer_pool_get();
178  mutt_buffer_addstr(path, bcache->path);
179  mutt_buffer_addstr(path, id);
180 
181  FILE *fp = mutt_file_fopen(mutt_b2s(path), "r");
182 
183  mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", mutt_b2s(path), fp ? "yes" : "no");
184 
186  return fp;
187 }
188 
199 FILE *mutt_bcache_put(struct BodyCache *bcache, const char *id)
200 {
201  if (!id || (*id == '\0') || !bcache)
202  return NULL;
203 
204  struct Buffer *path = mutt_buffer_pool_get();
205  mutt_buffer_printf(path, "%s%s%s", bcache->path, id, ".tmp");
206 
207  struct stat sb;
208  if (stat(bcache->path, &sb) == 0)
209  {
210  if (!S_ISDIR(sb.st_mode))
211  {
212  mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
213  return NULL;
214  }
215  }
216  else
217  {
218  if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
219  {
220  mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
221  return NULL;
222  }
223  }
224 
225  mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", path);
226 
227  FILE *fp = mutt_file_fopen(mutt_b2s(path), "w+");
229  return fp;
230 }
231 
239 int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
240 {
241  struct Buffer *tmpid = mutt_buffer_pool_get();
242  mutt_buffer_printf(tmpid, "%s.tmp", id);
243 
244  int rc = mutt_bcache_move(bcache, mutt_b2s(tmpid), id);
245  mutt_buffer_pool_release(&tmpid);
246  return rc;
247 }
248 
256 int mutt_bcache_del(struct BodyCache *bcache, const char *id)
257 {
258  if (!id || (*id == '\0') || !bcache)
259  return -1;
260 
261  struct Buffer *path = mutt_buffer_pool_get();
262  mutt_buffer_addstr(path, bcache->path);
263  mutt_buffer_addstr(path, id);
264 
265  mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", mutt_b2s(path));
266 
267  int rc = unlink(mutt_b2s(path));
269  return rc;
270 }
271 
279 int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
280 {
281  if (!id || (*id == '\0') || !bcache)
282  return -1;
283 
284  struct Buffer *path = mutt_buffer_pool_get();
285  mutt_buffer_addstr(path, bcache->path);
286  mutt_buffer_addstr(path, id);
287 
288  int rc = 0;
289  struct stat st;
290  if (stat(mutt_b2s(path), &st) < 0)
291  rc = -1;
292  else
293  rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
294 
295  mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", mutt_b2s(path),
296  (rc == 0) ? "yes" : "no");
297 
299  return rc;
300 }
301 
321 int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
322 {
323  DIR *d = NULL;
324  struct dirent *de = NULL;
325  int rc = -1;
326 
327  if (!bcache || !(d = opendir(bcache->path)))
328  goto out;
329 
330  rc = 0;
331 
332  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
333 
334  while ((de = readdir(d)))
335  {
336  if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
337  {
338  continue;
339  }
340 
341  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
342 
343  if (want_id && (want_id(de->d_name, bcache, data) != 0))
344  goto out;
345 
346  rc++;
347  }
348 
349 out:
350  if (d)
351  {
352  if (closedir(d) < 0)
353  rc = -1;
354  }
355  mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
356  return rc;
357 }
#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
bool C_MessageCacheClean
Config: (imap/pop) Clean out obsolete entries from the message cache.
Definition: bcache.c:44
Structs that make up an email.
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:136
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
int mutt_bcache_commit(struct BodyCache *bcache, const char *id)
Move a temporary file into the Body Cache.
Definition: bcache.c:239
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:55
#define _(a)
Definition: message.h:28
char * C_MessageCachedir
Config: (imap/pop) Directory for the message cache.
Definition: bcache.c:48
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
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:321
Some miscellaneous functions.
FILE * mutt_bcache_get(struct BodyCache *bcache, const char *id)
Open a file in the Body Cache.
Definition: bcache.c:172
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:875
int mutt_bcache_exists(struct BodyCache *bcache, const char *id)
Check if a file exists in the Body Cache.
Definition: bcache.c:279
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:199
#define mutt_b2s(buf)
Definition: buffer.h:41
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:165
char * dptr
Current read/write position.
Definition: buffer.h:36
int(* bcache_list_t)(const char *id, struct BodyCache *bcache, void *data)
Prototype for mutt_bcache_list() callback.
Definition: lib.h:46
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:256
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
Login details for a remote server.
Definition: connaccount.h:51
char * path
Path.
Definition: url.h:73
Local cache of email bodies.
Definition: bcache.c:53
Log at debug level 1.
Definition: logging.h:40
#define mutt_error(...)
Definition: logging.h:84
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:66
#define FREE(x)
Definition: memory.h:40
int url_tostring(struct Url *url, char *dest, size_t len, int flags)
Output the URL string for a given Url object.
Definition: url.c:418
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:107
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:157
Log at debug level 3.
Definition: logging.h:42
#define U_PATH
Definition: url.h:48
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to &#39;us-ascii&#39;.
Definition: muttlib.c:1474