NeoMutt  2019-11-11
Teaching an old dog new tricks
DOXYGEN
bcache.c File Reference

Body Caching - local copies of email bodies. More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "email/lib.h"
#include "bcache.h"
#include "mutt_account.h"
#include "muttlib.h"
+ Include dependency graph for bcache.c:

Go to the source code of this file.

Data Structures

struct  BodyCache
 Local cache of email bodies. More...
 

Functions

static int bcache_path (struct ConnAccount *account, const char *mailbox, struct BodyCache *bcache)
 Create the cache path for a given account/mailbox. More...
 
static int mutt_bcache_move (struct BodyCache *bcache, const char *id, const char *newid)
 Change the id of a message in the cache. More...
 
struct BodyCachemutt_bcache_open (struct ConnAccount *account, const char *mailbox)
 Open an Email-Body Cache. More...
 
void mutt_bcache_close (struct BodyCache **bcache)
 Close an Email-Body Cache. More...
 
FILE * mutt_bcache_get (struct BodyCache *bcache, const char *id)
 Open a file in the Body Cache. More...
 
FILE * mutt_bcache_put (struct BodyCache *bcache, const char *id)
 Create a file in the Body Cache. More...
 
int mutt_bcache_commit (struct BodyCache *bcache, const char *id)
 Move a temporary file into the Body Cache. More...
 
int mutt_bcache_del (struct BodyCache *bcache, const char *id)
 Delete a file from the Body Cache. More...
 
int mutt_bcache_exists (struct BodyCache *bcache, const char *id)
 Check if a file exists in the Body Cache. More...
 
int mutt_bcache_list (struct BodyCache *bcache, bcache_list_t *want_id, void *data)
 Find matching entries in the Body Cache. More...
 

Variables

char * C_MessageCachedir
 Config: (imap/pop) Directory for the message cache. More...
 

Detailed Description

Body Caching - local copies of email bodies.

Authors
  • Brendan Cully
  • Rocco Rutte

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file bcache.c.

Function Documentation

◆ bcache_path()

static int bcache_path ( struct ConnAccount account,
const char *  mailbox,
struct BodyCache bcache 
)
static

Create the cache path for a given account/mailbox.

Parameters
accountAccount info
mailboxMailbox name
bcacheBody cache
Return values
0Success
-1Failure

Definition at line 63 of file bcache.c.

64 {
65  char host[256];
66  struct Url url = { U_UNKNOWN };
67 
68  if (!account || !C_MessageCachedir || !bcache)
69  return -1;
70 
71  /* make up a Url we can turn into a string */
72  mutt_account_tourl(account, &url);
73  /* mutt_account_tourl() just sets up some pointers;
74  * if this ever changes, we have a memleak here */
75  url.path = NULL;
76  if (url_tostring(&url, host, sizeof(host), U_PATH) < 0)
77  {
78  mutt_debug(LL_DEBUG1, "URL to string failed\n");
79  return -1;
80  }
81 
82  struct Buffer *path = mutt_buffer_pool_get();
83  struct Buffer *dst = mutt_buffer_pool_get();
84  mutt_buffer_encode_path(path, NONULL(mailbox));
85 
86  mutt_buffer_printf(dst, "%s/%s%s", C_MessageCachedir, host, mutt_b2s(path));
87  if (*(dst->dptr - 1) != '/')
88  mutt_buffer_addch(dst, '/');
89 
90  mutt_debug(LL_DEBUG3, "path: '%s'\n", mutt_b2s(dst));
91  bcache->path = mutt_buffer_strdup(dst);
92 
95  return 0;
96 }
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
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:52
Url wasn&#39;t recognised.
Definition: url.h:34
int url_tostring(struct Url *u, char *dest, size_t len, int flags)
Output the URL string for a given Url object.
Definition: url.c:399
char * C_MessageCachedir
Config: (imap/pop) Directory for the message cache.
Definition: bcache.c:45
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_b2s(buf)
Definition: buffer.h:41
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
char * path
Path.
Definition: url.h:73
Log at debug level 1.
Definition: logging.h:56
void mutt_buffer_encode_path(struct Buffer *buf, const char *src)
Convert a path into the user&#39;s preferred character set.
Definition: muttlib.c:1600
void mutt_account_tourl(struct ConnAccount *account, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:145
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
#define U_PATH
Definition: url.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_move()

static int mutt_bcache_move ( struct BodyCache bcache,
const char *  id,
const char *  newid 
)
static

Change the id of a message in the cache.

Parameters
bcacheBody cache
idPer-mailbox unique identifier for the message
newidNew id for the message

Definition at line 104 of file bcache.c.

105 {
106  if (!bcache || !id || !*id || !newid || !*newid)
107  return -1;
108 
109  struct Buffer *path = mutt_buffer_pool_get();
110  struct Buffer *newpath = mutt_buffer_pool_get();
111 
112  mutt_buffer_printf(path, "%s%s", bcache->path, id);
113  mutt_buffer_printf(newpath, "%s%s", bcache->path, newid);
114 
115  mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", mutt_b2s(path), mutt_b2s(newpath));
116 
117  int rc = rename(mutt_b2s(path), mutt_b2s(newpath));
119  mutt_buffer_pool_release(&newpath);
120  return rc;
121 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:52
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_b2s(buf)
Definition: buffer.h:41
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_open()

struct BodyCache* mutt_bcache_open ( struct ConnAccount account,
const char *  mailbox 
)

Open an Email-Body Cache.

Parameters
accountcurrent mailbox' account (required)
mailboxpath to the mailbox of the account (optional)
Return values
NULLFailure

The driver using it is responsible for ensuring that hierarchies are separated by '/' (if it knows of such a concepts like mailboxes or hierarchies)

Definition at line 133 of file bcache.c.

134 {
135  if (!account)
136  return NULL;
137 
138  struct BodyCache *bcache = mutt_mem_calloc(1, sizeof(struct BodyCache));
139  if (bcache_path(account, mailbox, bcache) < 0)
140  {
141  mutt_bcache_close(&bcache);
142  return NULL;
143  }
144 
145  return bcache;
146 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
Local cache of email bodies.
Definition: bcache.c:50
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
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:154
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_close()

void mutt_bcache_close ( struct BodyCache **  bcache)

Close an Email-Body Cache.

Parameters
[out]bcacheBody cache

Free all memory of bcache and finally FREE() it, too.

Definition at line 154 of file bcache.c.

155 {
156  if (!bcache || !*bcache)
157  return;
158  FREE(&(*bcache)->path);
159  FREE(bcache);
160 }
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ mutt_bcache_get()

FILE* mutt_bcache_get ( struct BodyCache bcache,
const char *  id 
)

Open a file in the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
idPer-mailbox unique identifier for the message
Return values
ptrSuccess
NULLFailure

Definition at line 169 of file bcache.c.

170 {
171  if (!id || !*id || !bcache)
172  return NULL;
173 
174  struct Buffer *path = mutt_buffer_pool_get();
175  mutt_buffer_addstr(path, bcache->path);
176  mutt_buffer_addstr(path, id);
177 
178  FILE *fp = mutt_file_fopen(mutt_b2s(path), "r");
179 
180  mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", mutt_b2s(path), fp ? "yes" : "no");
181 
183  return fp;
184 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:52
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_put()

FILE* mutt_bcache_put ( struct BodyCache bcache,
const char *  id 
)

Create a file in the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
idPer-mailbox unique identifier for the message
Return values
ptrSuccess
NULLFailure

The returned FILE* is in a temporary location. Use mutt_bcache_commit to put it into place

Definition at line 196 of file bcache.c.

197 {
198  if (!id || !*id || !bcache)
199  return NULL;
200 
201  struct Buffer *path = mutt_buffer_pool_get();
202  mutt_buffer_printf(path, "%s%s%s", bcache->path, id, ".tmp");
203 
204  struct stat sb;
205  if (stat(bcache->path, &sb) == 0)
206  {
207  if (!S_ISDIR(sb.st_mode))
208  {
209  mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
210  return NULL;
211  }
212  }
213  else
214  {
215  if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
216  {
217  mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
218  return NULL;
219  }
220  }
221 
222  mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", path);
223 
224  FILE *fp = mutt_file_fopen(mutt_b2s(path), "w+");
226  return fp;
227 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
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
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:873
#define mutt_b2s(buf)
Definition: buffer.h:41
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_commit()

int mutt_bcache_commit ( struct BodyCache bcache,
const char *  id 
)

Move a temporary file into the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
idPer-mailbox unique identifier for the message
Return values
0Success
-1Failure

Definition at line 236 of file bcache.c.

237 {
238  struct Buffer *tmpid = mutt_buffer_pool_get();
239  mutt_buffer_printf(tmpid, "%s.tmp", id);
240 
241  int rc = mutt_bcache_move(bcache, mutt_b2s(tmpid), id);
242  mutt_buffer_pool_release(&tmpid);
243  return rc;
244 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_b2s(buf)
Definition: buffer.h:41
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:104
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_del()

int mutt_bcache_del ( struct BodyCache bcache,
const char *  id 
)

Delete a file from the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
idPer-mailbox unique identifier for the message
Return values
0Success
-1Failure

Definition at line 253 of file bcache.c.

254 {
255  if (!id || !*id || !bcache)
256  return -1;
257 
258  struct Buffer *path = mutt_buffer_pool_get();
259  mutt_buffer_addstr(path, bcache->path);
260  mutt_buffer_addstr(path, id);
261 
262  mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", mutt_b2s(path));
263 
264  int rc = unlink(mutt_b2s(path));
266  return rc;
267 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:52
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_exists()

int mutt_bcache_exists ( struct BodyCache bcache,
const char *  id 
)

Check if a file exists in the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
idPer-mailbox unique identifier for the message
Return values
0Success
-1Failure

Definition at line 276 of file bcache.c.

277 {
278  if (!id || !*id || !bcache)
279  return -1;
280 
281  struct Buffer *path = mutt_buffer_pool_get();
282  mutt_buffer_addstr(path, bcache->path);
283  mutt_buffer_addstr(path, id);
284 
285  int rc = 0;
286  struct stat st;
287  if (stat(mutt_b2s(path), &st) < 0)
288  rc = -1;
289  else
290  rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
291 
292  mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", mutt_b2s(path),
293  (rc == 0) ? "yes" : "no");
294 
296  return rc;
297 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
char * path
Definition: bcache.c:52
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bcache_list()

int mutt_bcache_list ( struct BodyCache bcache,
bcache_list_t want_id,
void *  data 
)

Find matching entries in the Body Cache.

Parameters
bcacheBody Cache from mutt_bcache_open()
want_idCallback function called for each match
dataData to pass to the callback function
Return values
-1Failure
>=0count of matching items

This more or less "examines" the cache and calls a function with each id it finds if given.

The optional callback function gets the id of a message, the very same body cache handle mutt_bcache_list() is called with (to, perhaps, perform further operations on the bcache), and a data cookie which is just passed as-is. If the return value of the callback is non-zero, the listing is aborted and continued otherwise. The callback is optional so that this function can be used to count the items in the cache (see below for return value).

Definition at line 318 of file bcache.c.

319 {
320  DIR *d = NULL;
321  struct dirent *de = NULL;
322  int rc = -1;
323 
324  if (!bcache || !(d = opendir(bcache->path)))
325  goto out;
326 
327  rc = 0;
328 
329  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
330 
331  while ((de = readdir(d)))
332  {
333  if (mutt_str_startswith(de->d_name, ".", CASE_MATCH) ||
334  mutt_str_startswith(de->d_name, "..", CASE_MATCH))
335  {
336  continue;
337  }
338 
339  mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
340 
341  if (want_id && (want_id(de->d_name, bcache, data) != 0))
342  goto out;
343 
344  rc++;
345  }
346 
347 out:
348  if (d)
349  {
350  if (closedir(d) < 0)
351  rc = -1;
352  }
353  mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
354  return rc;
355 }
char * path
Definition: bcache.c:52
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 3.
Definition: logging.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_MessageCachedir

char* C_MessageCachedir

Config: (imap/pop) Directory for the message cache.

Definition at line 45 of file bcache.c.