NeoMutt  2024-12-12-14-g7b49f7
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
bcache.c File Reference

Body Caching (local copies of email bodies) More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "lib.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.
 
static int mutt_bcache_move (struct BodyCache *bcache, const char *id, const char *newid)
 Change the id of a message in the cache.
 
struct BodyCachemutt_bcache_open (struct ConnAccount *account, const char *mailbox)
 Open an Email-Body Cache.
 
void mutt_bcache_close (struct BodyCache **ptr)
 Close an Email-Body Cache.
 
FILE * mutt_bcache_get (struct BodyCache *bcache, const char *id)
 Open a file in the Body Cache.
 
FILE * mutt_bcache_put (struct BodyCache *bcache, const char *id)
 Create a file in the Body Cache.
 
int mutt_bcache_commit (struct BodyCache *bcache, const char *id)
 Move a temporary file into the Body Cache.
 
int mutt_bcache_del (struct BodyCache *bcache, const char *id)
 Delete a file from the Body Cache.
 
int mutt_bcache_exists (struct BodyCache *bcache, const char *id)
 Check if a file exists in the Body Cache.
 
int mutt_bcache_list (struct BodyCache *bcache, bcache_list_t want_id, void *data)
 Find matching entries in the Body Cache.
 

Detailed Description

Body Caching (local copies of email bodies)

Authors
  • Richard Russon
  • Pietro Cerutti

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 61 of file bcache.c.

62{
63 const char *const c_message_cache_dir = cs_subset_path(NeoMutt->sub, "message_cache_dir");
64 if (!account || !c_message_cache_dir || !bcache)
65 return -1;
66
67 struct stat st = { 0 };
68 if (!((stat(c_message_cache_dir, &st) == 0) && S_ISDIR(st.st_mode)))
69 {
70 mutt_error(_("Cache disabled, $message_cache_dir isn't a directory: %s"), c_message_cache_dir);
71 return -1;
72 }
73
74 struct Url url = { 0 };
75 struct Buffer *host = buf_pool_get();
76
77 /* make up a Url we can turn into a string */
78 account_to_url(account, &url);
79 /* account_to_url() just sets up some pointers;
80 * if this ever changes, we have a memleak here */
81 url.path = NULL;
82 if (url_tostring(&url, host->data, host->dsize, U_PATH) < 0)
83 {
84 mutt_debug(LL_DEBUG1, "URL to string failed\n");
85 buf_pool_release(&host);
86 return -1;
87 }
88 buf_fix_dptr(host);
89
90 buf_addstr(host, mailbox);
91
92 struct Buffer *path = buf_pool_get();
93 struct Buffer *dst = buf_pool_get();
94 mutt_encode_path(path, buf_string(host));
95
96 buf_printf(dst, "%s/%s", c_message_cache_dir, buf_string(path));
97 if (*(dst->dptr - 1) != '/')
98 buf_addch(dst, '/');
99
100 mutt_debug(LL_DEBUG3, "path: '%s'\n", buf_string(dst));
101 bcache->path = buf_strdup(dst);
102
103 buf_pool_release(&host);
104 buf_pool_release(&path);
105 buf_pool_release(&dst);
106 return 0;
107}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:182
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:168
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define _(a)
Definition: message.h:28
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:872
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
char * path
On-disk path to the file.
Definition: bcache.c:50
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
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(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:423
#define U_PATH
Definition: url.h:50
+ 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
Return values
0Success
-1Error

Definition at line 117 of file bcache.c.

118{
119 if (!bcache || !id || (*id == '\0') || !newid || (*newid == '\0'))
120 return -1;
121
122 struct Buffer *path = buf_pool_get();
123 struct Buffer *newpath = buf_pool_get();
124
125 buf_printf(path, "%s%s", bcache->path, id);
126 buf_printf(newpath, "%s%s", bcache->path, newid);
127
128 mutt_debug(LL_DEBUG3, "bcache: mv: '%s' '%s'\n", buf_string(path), buf_string(newpath));
129
130 int rc = rename(buf_string(path), buf_string(newpath));
131 buf_pool_release(&path);
132 buf_pool_release(&newpath);
133 return rc;
134}
+ 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 146 of file bcache.c.

147{
148 if (!account)
149 return NULL;
150
151 struct BodyCache *bcache = MUTT_MEM_CALLOC(1, struct BodyCache);
152 if (bcache_path(account, mailbox, bcache) < 0)
153 {
154 mutt_bcache_close(&bcache);
155 return NULL;
156 }
157
158 return bcache;
159}
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:61
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition: bcache.c:167
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
Local cache of email bodies.
Definition: bcache.c:49
+ 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 **  ptr)

Close an Email-Body Cache.

Parameters
[out]ptrBody cache

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

Definition at line 167 of file bcache.c.

168{
169 if (!ptr || !*ptr)
170 return;
171
172 struct BodyCache *bcache = *ptr;
173 FREE(&bcache->path);
174
175 FREE(ptr);
176}
#define FREE(x)
Definition: memory.h:55
+ 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 185 of file bcache.c.

186{
187 if (!id || (*id == '\0') || !bcache)
188 return NULL;
189
190 struct Buffer *path = buf_pool_get();
191 buf_addstr(path, bcache->path);
192 buf_addstr(path, id);
193
194 FILE *fp = mutt_file_fopen(buf_string(path), "r");
195
196 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", buf_string(path), fp ? "yes" : "no");
197
198 buf_pool_release(&path);
199 return fp;
200}
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
+ 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 212 of file bcache.c.

213{
214 if (!id || (*id == '\0') || !bcache)
215 return NULL;
216
217 struct Buffer *path = buf_pool_get();
218 buf_printf(path, "%s%s%s", bcache->path, id, ".tmp");
219
220 struct stat st = { 0 };
221 if (stat(bcache->path, &st) == 0)
222 {
223 if (!S_ISDIR(st.st_mode))
224 {
225 mutt_error(_("Message cache isn't a directory: %s"), bcache->path);
226 return NULL;
227 }
228 }
229 else
230 {
231 if (mutt_file_mkdir(bcache->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
232 {
233 mutt_error(_("Can't create %s: %s"), bcache->path, strerror(errno));
234 return NULL;
235 }
236 }
237
238 mutt_debug(LL_DEBUG3, "bcache: put: '%s'\n", buf_string(path));
239
240 FILE *fp = mutt_file_fopen(buf_string(path), "w+");
241 buf_pool_release(&path);
242 return fp;
243}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
+ 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 252 of file bcache.c.

253{
254 struct Buffer *tmpid = buf_pool_get();
255 buf_printf(tmpid, "%s.tmp", id);
256
257 int rc = mutt_bcache_move(bcache, buf_string(tmpid), id);
258 buf_pool_release(&tmpid);
259 return rc;
260}
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:117
+ 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 269 of file bcache.c.

270{
271 if (!id || (*id == '\0') || !bcache)
272 return -1;
273
274 struct Buffer *path = buf_pool_get();
275 buf_addstr(path, bcache->path);
276 buf_addstr(path, id);
277
278 mutt_debug(LL_DEBUG3, "bcache: del: '%s'\n", buf_string(path));
279
280 int rc = unlink(buf_string(path));
281 buf_pool_release(&path);
282 return rc;
283}
+ 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 292 of file bcache.c.

293{
294 if (!id || (*id == '\0') || !bcache)
295 return -1;
296
297 struct Buffer *path = buf_pool_get();
298 buf_addstr(path, bcache->path);
299 buf_addstr(path, id);
300
301 int rc = 0;
302 struct stat st = { 0 };
303 if (stat(buf_string(path), &st) < 0)
304 rc = -1;
305 else
306 rc = (S_ISREG(st.st_mode) && (st.st_size != 0)) ? 0 : -1;
307
308 mutt_debug(LL_DEBUG3, "bcache: exists: '%s': %s\n", buf_string(path),
309 (rc == 0) ? "yes" : "no");
310
311 buf_pool_release(&path);
312 return rc;
313}
+ 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 334 of file bcache.c.

335{
336 DIR *dir = NULL;
337 struct dirent *de = NULL;
338 int rc = -1;
339
340 if (!bcache || !(dir = mutt_file_opendir(bcache->path, MUTT_OPENDIR_NONE)))
341 goto out;
342
343 rc = 0;
344
345 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
346
347 while ((de = readdir(dir)))
348 {
349 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
350 {
351 continue;
352 }
353
354 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
355
356 if (want_id && (want_id(de->d_name, bcache, data) != 0))
357 goto out;
358
359 rc++;
360 }
361
362out:
363 if (dir)
364 {
365 if (closedir(dir) < 0)
366 rc = -1;
367 }
368 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
369 return rc;
370}
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
+ Here is the call graph for this function:
+ Here is the caller graph for this function: