mutt stable branch with some hacks
at master 267 lines 6.5 kB view raw
1/* 2 * Copyright (C) 2006-2007,2009 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 29#include "mutt.h" 30#include "account.h" 31#include "url.h" 32#include "bcache.h" 33 34#include "lib.h" 35 36struct body_cache { 37 char path[_POSIX_PATH_MAX]; 38 size_t pathlen; 39}; 40 41static int bcache_path(ACCOUNT *account, const char *mailbox, 42 char *dst, size_t dstlen) 43{ 44 char host[STRING]; 45 char path[_POSIX_PATH_MAX]; 46 ciss_url_t url; 47 int len; 48 49 if (!account || !MessageCachedir || !*MessageCachedir || !dst || !dstlen) 50 return -1; 51 52 /* make up a ciss_url_t we can turn into a string */ 53 memset (&url, 0, sizeof (ciss_url_t)); 54 mutt_account_tourl (account, &url); 55 /* 56 * mutt_account_tourl() just sets up some pointers; 57 * if this ever changes, we have a memleak here 58 */ 59 url.path = NULL; 60 if (url_ciss_tostring (&url, host, sizeof (host), U_PATH) < 0) 61 { 62 dprint (1, (debugfile, "bcache_path: URL to string failed\n")); 63 return -1; 64 } 65 66 mutt_encode_path (path, sizeof (path), NONULL (mailbox)); 67 68 len = snprintf (dst, dstlen-1, "%s/%s%s%s", MessageCachedir, 69 host, path, 70 (*path && path[mutt_strlen (path) - 1] == '/') ? "" : "/"); 71 72 dprint (3, (debugfile, "bcache_path: rc: %d, path: '%s'\n", len, dst)); 73 74 if (len < 0 || len >= dstlen-1) 75 return -1; 76 77 dprint (3, (debugfile, "bcache_path: directory: '%s'\n", dst)); 78 79 return 0; 80} 81 82body_cache_t *mutt_bcache_open (ACCOUNT *account, const char *mailbox) 83{ 84 struct body_cache *bcache = NULL; 85 86 if (!account) 87 goto bail; 88 89 bcache = safe_calloc (1, sizeof (struct body_cache)); 90 if (bcache_path (account, mailbox, bcache->path, 91 sizeof (bcache->path)) < 0) 92 goto bail; 93 bcache->pathlen = mutt_strlen (bcache->path); 94 95 return bcache; 96 97bail: 98 if (bcache) 99 FREE(&bcache); 100 return NULL; 101} 102 103void mutt_bcache_close (body_cache_t **bcache) 104{ 105 if (!bcache || !*bcache) 106 return; 107 FREE(bcache); /* __FREE_CHECKED__ */ 108} 109 110FILE* mutt_bcache_get(body_cache_t *bcache, const char *id) 111{ 112 char path[_POSIX_PATH_MAX]; 113 FILE* fp = NULL; 114 115 if (!id || !*id || !bcache) 116 return NULL; 117 118 path[0] = '\0'; 119 safe_strncat (path, sizeof (path), bcache->path, bcache->pathlen); 120 safe_strncat (path, sizeof (path), id, mutt_strlen (id)); 121 122 fp = safe_fopen (path, "r"); 123 124 dprint (3, (debugfile, "bcache: get: '%s': %s\n", path, fp == NULL ? "no" : "yes")); 125 126 return fp; 127} 128 129FILE* mutt_bcache_put(body_cache_t *bcache, const char *id, int tmp) 130{ 131 char path[_POSIX_PATH_MAX]; 132 FILE* fp; 133 char* s; 134 struct stat sb; 135 136 if (!id || !*id || !bcache) 137 return NULL; 138 139 snprintf (path, sizeof (path), "%s%s%s", bcache->path, id, 140 tmp ? ".tmp" : ""); 141 142 if ((fp = safe_fopen (path, "w+"))) 143 goto out; 144 145 if (errno == EEXIST) 146 /* clean up leftover tmp file */ 147 mutt_unlink (path); 148 149 s = strchr (path + 1, '/'); 150 while (!(fp = safe_fopen (path, "w+")) && errno == ENOENT && s) 151 { 152 /* create missing path components */ 153 *s = '\0'; 154 if (stat (path, &sb) < 0 && (errno != ENOENT || mkdir (path, 0777) < 0)) 155 return NULL; 156 *s = '/'; 157 s = strchr (s + 1, '/'); 158 } 159 160 out: 161 dprint (3, (debugfile, "bcache: put: '%s'\n", path)); 162 163 return fp; 164} 165 166int mutt_bcache_commit(body_cache_t* bcache, const char* id) 167{ 168 char tmpid[_POSIX_PATH_MAX]; 169 170 snprintf (tmpid, sizeof (tmpid), "%s.tmp", id); 171 172 return mutt_bcache_move (bcache, tmpid, id); 173} 174 175int mutt_bcache_move(body_cache_t* bcache, const char* id, const char* newid) 176{ 177 char path[_POSIX_PATH_MAX]; 178 char newpath[_POSIX_PATH_MAX]; 179 180 if (!bcache || !id || !*id || !newid || !*newid) 181 return -1; 182 183 snprintf (path, sizeof (path), "%s%s", bcache->path, id); 184 snprintf (newpath, sizeof (newpath), "%s%s", bcache->path, newid); 185 186 dprint (3, (debugfile, "bcache: mv: '%s' '%s'\n", path, newpath)); 187 188 return rename (path, newpath); 189} 190 191int mutt_bcache_del(body_cache_t *bcache, const char *id) 192{ 193 char path[_POSIX_PATH_MAX]; 194 195 if (!id || !*id || !bcache) 196 return -1; 197 198 path[0] = '\0'; 199 safe_strncat (path, sizeof (path), bcache->path, bcache->pathlen); 200 safe_strncat (path, sizeof (path), id, mutt_strlen (id)); 201 202 dprint (3, (debugfile, "bcache: del: '%s'\n", path)); 203 204 return unlink (path); 205} 206 207int mutt_bcache_exists(body_cache_t *bcache, const char *id) 208{ 209 char path[_POSIX_PATH_MAX]; 210 struct stat st; 211 int rc = 0; 212 213 if (!id || !*id || !bcache) 214 return -1; 215 216 path[0] = '\0'; 217 safe_strncat (path, sizeof (path), bcache->path, bcache->pathlen); 218 safe_strncat (path, sizeof (path), id, mutt_strlen (id)); 219 220 if (stat (path, &st) < 0) 221 rc = -1; 222 else 223 rc = S_ISREG(st.st_mode) && st.st_size != 0 ? 0 : -1; 224 225 dprint (3, (debugfile, "bcache: exists: '%s': %s\n", path, rc == 0 ? "yes" : "no")); 226 227 return rc; 228} 229 230int mutt_bcache_list(body_cache_t *bcache, 231 int (*want_id)(const char *id, body_cache_t *bcache, 232 void *data), void *data) 233{ 234 DIR *d = NULL; 235 struct dirent *de; 236 int rc = -1; 237 238 if (!bcache || !(d = opendir (bcache->path))) 239 goto out; 240 241 rc = 0; 242 243 dprint (3, (debugfile, "bcache: list: dir: '%s'\n", bcache->path)); 244 245 while ((de = readdir (d))) 246 { 247 if (mutt_strncmp (de->d_name, ".", 1) == 0 || 248 mutt_strncmp (de->d_name, "..", 2) == 0) 249 continue; 250 251 dprint (3, (debugfile, "bcache: list: dir: '%s', id :'%s'\n", bcache->path, de->d_name)); 252 253 if (want_id && want_id (de->d_name, bcache, data) != 0) 254 goto out; 255 256 rc++; 257 } 258 259out: 260 if (d) 261 { 262 if (closedir (d) < 0) 263 rc = -1; 264 } 265 dprint (3, (debugfile, "bcache: list: did %d entries\n", rc)); 266 return rc; 267}