mutt stable branch with some hacks
at jcs 309 lines 7.6 kB view raw
1/* 2 * Copyright (C) 2006-2007,2009,2017 Brendan Cully <brendan@kublai.com> 3 * Copyright (C) 2006,2009 Rocco Rutte <pdmef@gmx.net> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21#include "config.h" 22#endif /* HAVE_CONFIG_H */ 23 24#include <sys/types.h> 25#include <errno.h> 26#include <dirent.h> 27#include <stdio.h> 28#include <libgen.h> 29 30#include "mutt.h" 31#include "account.h" 32#include "url.h" 33#include "bcache.h" 34 35#include "lib.h" 36 37struct body_cache { 38 char *path; 39}; 40 41static int bcache_path(ACCOUNT *account, const char *mailbox, body_cache_t *bcache) 42{ 43 char host[STRING]; 44 BUFFER *path, *dst; 45 ciss_url_t url; 46 47 if (!account || !MessageCachedir || !bcache) 48 return -1; 49 50 /* make up a ciss_url_t we can turn into a string */ 51 memset (&url, 0, sizeof (ciss_url_t)); 52 mutt_account_tourl (account, &url); 53 /* 54 * mutt_account_tourl() just sets up some pointers; 55 * if this ever changes, we have a memleak here 56 */ 57 url.path = NULL; 58 if (url_ciss_tostring (&url, host, sizeof (host), U_PATH) < 0) 59 { 60 dprint (1, (debugfile, "bcache_path: URL to string failed\n")); 61 return -1; 62 } 63 64 path = mutt_buffer_pool_get (); 65 dst = mutt_buffer_pool_get (); 66 mutt_encode_path (path, NONULL (mailbox)); 67 68 mutt_buffer_printf (dst, "%s/%s%s", MessageCachedir, host, mutt_b2s (path)); 69 if (*(dst->dptr - 1) != '/') 70 mutt_buffer_addch (dst, '/'); 71 mutt_buffer_addstr (dst, "cur/", 4); 72 73 dprint (3, (debugfile, "bcache_path: path: '%s'\n", mutt_b2s (dst))); 74 bcache->path = safe_strdup (mutt_b2s (dst)); 75 76 mutt_buffer_pool_release (&path); 77 mutt_buffer_pool_release (&dst); 78 return 0; 79} 80 81body_cache_t *mutt_bcache_open (ACCOUNT *account, const char *mailbox) 82{ 83 struct body_cache *bcache = NULL; 84 85 if (!account) 86 goto bail; 87 88 bcache = safe_calloc (1, sizeof (struct body_cache)); 89 if (bcache_path (account, mailbox, bcache) < 0) 90 goto bail; 91 92 return bcache; 93 94bail: 95 mutt_bcache_close (&bcache); 96 return NULL; 97} 98 99void mutt_bcache_close (body_cache_t **bcache) 100{ 101 if (!bcache || !*bcache) 102 return; 103 FREE (&(*bcache)->path); 104 FREE(bcache); /* __FREE_CHECKED__ */ 105} 106 107FILE* mutt_bcache_get(body_cache_t *bcache, const char *id) 108{ 109 BUFFER *path; 110 FILE* fp = NULL; 111 112 if (!id || !*id || !bcache) 113 return NULL; 114 115 path = mutt_buffer_pool_get (); 116 mutt_buffer_addstr (path, bcache->path); 117 mutt_buffer_addstr (path, id); 118 119 fp = safe_fopen (mutt_b2s (path), "r"); 120 121 dprint (3, (debugfile, "bcache: get: '%s': %s\n", mutt_b2s (path), 122 fp == NULL ? "no" : "yes")); 123 124 mutt_buffer_pool_release (&path); 125 return fp; 126} 127 128FILE* mutt_bcache_put(body_cache_t *bcache, const char *id, int tmp) 129{ 130 BUFFER *path = NULL; 131 BUFFER *newpath = NULL; 132 FILE* fp = NULL; 133 char* s = NULL; 134 struct stat sb; 135 136 if (!id || !*id || !bcache) 137 return NULL; 138 139 path = mutt_buffer_pool_get (); 140 mutt_buffer_printf (path, "%s%s%s", bcache->path, id, 141 tmp ? ".tmp" : ""); 142 143 if ((fp = safe_fopen (mutt_b2s (path), "w+"))) 144 goto out; 145 146 if (errno == EEXIST) 147 /* clean up leftover tmp file */ 148 mutt_unlink (mutt_b2s (path)); 149 150 if (mutt_buffer_len (path)) 151 s = strchr (path->data + 1, '/'); 152 while (!(fp = safe_fopen (mutt_b2s (path), "w+")) && errno == ENOENT && s) 153 { 154 /* create missing path components */ 155 *s = '\0'; 156 if (stat (mutt_b2s (path), &sb) < 0 && 157 (errno != ENOENT || mkdir (mutt_b2s (path), 0777) < 0)) 158 goto out; 159 *s = '/'; 160 s = strchr (s + 1, '/'); 161 } 162 163 /* make sure new and tmp dirs exist in parent to be like real maildirs */ 164 if ((s = dirname(path))) { 165 s = dirname(s); 166 167 newpath = mutt_buffer_pool_get (); 168 mutt_buffer_printf (newpath, "%s/new", s); 169 170 if (stat (mutt_b2s (newpath), &sb) < 0 && 171 (errno != ENOENT || mkdir (mutt_b2s (newpath), 0777) < 0)) 172 return NULL; 173 174 mutt_buffer_printf (newpath, "%s/tmp", s); 175 if (stat (mutt_b2s (newpath), &sb) < 0 && 176 (errno != ENOENT || mkdir (mutt_b2s (newpath), 0777) < 0)) 177 return NULL; 178 179 mutt_buffer_pool_release (&newpath); 180 } else 181 return NULL; 182 183out: 184 dprint (3, (debugfile, "bcache: put: '%s'\n", mutt_b2s (path))); 185 mutt_buffer_pool_release (&path); 186 return fp; 187} 188 189int mutt_bcache_commit(body_cache_t* bcache, const char* id) 190{ 191 BUFFER *tmpid; 192 int rv; 193 194 tmpid = mutt_buffer_pool_get (); 195 mutt_buffer_printf (tmpid, "%s.tmp", id); 196 197 rv = mutt_bcache_move (bcache, mutt_b2s (tmpid), id); 198 199 mutt_buffer_pool_release (&tmpid); 200 return rv; 201} 202 203int mutt_bcache_move(body_cache_t* bcache, const char* id, const char* newid) 204{ 205 BUFFER *path, *newpath; 206 int rv; 207 208 if (!bcache || !id || !*id || !newid || !*newid) 209 return -1; 210 211 path = mutt_buffer_pool_get (); 212 newpath = mutt_buffer_pool_get (); 213 214 mutt_buffer_printf (path, "%s%s", bcache->path, id); 215 mutt_buffer_printf (newpath, "%s%s", bcache->path, newid); 216 217 dprint (3, (debugfile, "bcache: mv: '%s' '%s'\n", 218 mutt_b2s (path), mutt_b2s (newpath))); 219 220 rv = rename (mutt_b2s (path), mutt_b2s (newpath)); 221 222 mutt_buffer_pool_release (&path); 223 mutt_buffer_pool_release (&newpath); 224 return rv; 225} 226 227int mutt_bcache_del(body_cache_t *bcache, const char *id) 228{ 229 BUFFER *path; 230 int rv; 231 232 if (!id || !*id || !bcache) 233 return -1; 234 235 path = mutt_buffer_pool_get (); 236 mutt_buffer_addstr (path, bcache->path); 237 mutt_buffer_addstr (path, id); 238 239 dprint (3, (debugfile, "bcache: del: '%s'\n", mutt_b2s (path))); 240 241 rv = unlink (mutt_b2s (path)); 242 243 mutt_buffer_pool_release (&path); 244 return rv; 245} 246 247int mutt_bcache_exists(body_cache_t *bcache, const char *id) 248{ 249 BUFFER *path; 250 struct stat st; 251 int rc = 0; 252 253 if (!id || !*id || !bcache) 254 return -1; 255 256 path = mutt_buffer_pool_get (); 257 mutt_buffer_addstr (path, bcache->path); 258 mutt_buffer_addstr (path, id); 259 260 if (stat (mutt_b2s (path), &st) < 0) 261 rc = -1; 262 else 263 rc = S_ISREG(st.st_mode) && st.st_size != 0 ? 0 : -1; 264 265 dprint (3, (debugfile, "bcache: exists: '%s': %s\n", 266 mutt_b2s (path), rc == 0 ? "yes" : "no")); 267 268 mutt_buffer_pool_release (&path); 269 return rc; 270} 271 272int mutt_bcache_list(body_cache_t *bcache, 273 int (*want_id)(const char *id, body_cache_t *bcache, 274 void *data), void *data) 275{ 276 DIR *d = NULL; 277 struct dirent *de; 278 int rc = -1; 279 280 if (!bcache || !(d = opendir (bcache->path))) 281 goto out; 282 283 rc = 0; 284 285 dprint (3, (debugfile, "bcache: list: dir: '%s'\n", bcache->path)); 286 287 while ((de = readdir (d))) 288 { 289 if (mutt_strncmp (de->d_name, ".", 1) == 0 || 290 mutt_strncmp (de->d_name, "..", 2) == 0) 291 continue; 292 293 dprint (3, (debugfile, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name)); 294 295 if (want_id && want_id (de->d_name, bcache, data) != 0) 296 goto out; 297 298 rc++; 299 } 300 301out: 302 if (d) 303 { 304 if (closedir (d) < 0) 305 rc = -1; 306 } 307 dprint (3, (debugfile, "bcache: list: did %d entries\n", rc)); 308 return rc; 309}