NeoMutt  2024-03-23-147-g885fbc
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 "lib.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.
 
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 63 of file bcache.c.

64{
65 char host[256] = { 0 };
66 struct Url url = { 0 };
67
68 const char *const c_message_cache_dir = cs_subset_path(NeoMutt->sub, "message_cache_dir");
69 if (!account || !c_message_cache_dir || !bcache)
70 return -1;
71
72 struct stat st = { 0 };
73 if (!((stat(c_message_cache_dir, &st) == 0) && S_ISDIR(st.st_mode)))
74 {
75 mutt_error(_("Cache disabled, $message_cache_dir isn't a directory: %s"), c_message_cache_dir);
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 = buf_pool_get();
91 struct Buffer *dst = buf_pool_get();
92 mutt_encode_path(path, NONULL(mailbox));
93
94 buf_printf(dst, "%s/%s%s", c_message_cache_dir, host, buf_string(path));
95 if (*(dst->dptr - 1) != '/')
96 buf_addch(dst, '/');
97
98 mutt_debug(LL_DEBUG3, "path: '%s'\n", buf_string(dst));
99 bcache->path = buf_strdup(dst);
100
101 buf_pool_release(&path);
102 buf_pool_release(&dst);
103 return 0;
104}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
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:169
#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 mutt_account_tourl(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:907
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define NONULL(x)
Definition: string2.h:37
char * path
On-disk path to the file.
Definition: bcache.c:52
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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: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 114 of file bcache.c.

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

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}
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 **ptr)
Close an Email-Body Cache.
Definition: bcache.c:164
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:51
+ 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 164 of file bcache.c.

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

183{
184 if (!id || (*id == '\0') || !bcache)
185 return NULL;
186
187 struct Buffer *path = buf_pool_get();
188 buf_addstr(path, bcache->path);
189 buf_addstr(path, id);
190
191 FILE *fp = mutt_file_fopen(buf_string(path), "r");
192
193 mutt_debug(LL_DEBUG3, "bcache: get: '%s': %s\n", buf_string(path), fp ? "yes" : "no");
194
195 buf_pool_release(&path);
196 return fp;
197}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
+ 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 209 of file bcache.c.

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

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

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

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

332{
333 DIR *dir = NULL;
334 struct dirent *de = NULL;
335 int rc = -1;
336
337 if (!bcache || !(dir = mutt_file_opendir(bcache->path, MUTT_OPENDIR_NONE)))
338 goto out;
339
340 rc = 0;
341
342 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s'\n", bcache->path);
343
344 while ((de = readdir(dir)))
345 {
346 if (mutt_str_startswith(de->d_name, ".") || mutt_str_startswith(de->d_name, ".."))
347 {
348 continue;
349 }
350
351 mutt_debug(LL_DEBUG3, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name);
352
353 if (want_id && (want_id(de->d_name, bcache, data) != 0))
354 goto out;
355
356 rc++;
357 }
358
359out:
360 if (dir)
361 {
362 if (closedir(dir) < 0)
363 rc = -1;
364 }
365 mutt_debug(LL_DEBUG3, "bcache: list: did %d entries\n", rc);
366 return rc;
367}
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:640
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:74
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: