/* This file is part of mailfromd. Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. 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 . */ #define MF_SOURCE_NAME MF_SOURCE_CACHE #ifdef HAVE_CONFIG_H # include #endif #include #include "mailfromd.h" struct cache_result { time_t timestamp; mf_status status; }; #define EXPIRE_INTERVAL(s) \ ((s) == mf_success ? cache_format->expire_interval : negative_expire_interval) mf_status cache_get(char *email) { mf_status rc; DBM_FILE db; DBM_DATUM key; DBM_DATUM contents; int readonly = 0; int res; if (!cache_format->enabled) return mf_failure; debug1(50, "getting cache info for %s", email); if (mu_dbm_open(cache_format->dbname, &db, MU_STREAM_RDWR, 0600, &readonly)) { mu_error(_("mu_dbm_open(%s) failed: %s"), cache_format->dbname, mu_dbm_strerror()); return mf_failure; } if (readonly) debug1(1, "cannot lock %s: switching to read-only mode", cache_format->dbname); memset (&key, 0, sizeof key); memset (&contents, 0, sizeof contents); MU_DATUM_PTR (key) = email; MU_DATUM_SIZE (key) = strlen (email) + 1; if ((res = mu_dbm_fetch(&db, key, &contents)) == 0) { char timebuf[80]; struct cache_result *res = (struct cache_result *) MU_DATUM_PTR(contents); time_t t = time(NULL); debug3(50, "found status: %s (%d), time: %s", mf_status_str(res->status), res->status, mailfromd_timestr(res->timestamp, timebuf, sizeof timebuf)); if (t - res->timestamp > EXPIRE_INTERVAL(res->status)) { if (!readonly) { debug1(50, "removing expired entry for %s",email); if (mu_dbm_delete(&db, key)) mu_error(_("Cannot remove record `%s' from `%s': %s"), email, db.name, mu_dbm_strerror()); } rc = mf_failure; } else { rc = res->status; } } else { if (res != MU_ERR_NOENT) mu_error(_("Cannot fetch record `%s' from `%s': %s"), email, db.name, mu_dbm_strerror()); rc = mf_failure; } mu_dbm_datum_free(&contents); mu_dbm_close(&db); return rc; } void cache_insert(char *email, mf_status rc) { DBM_FILE db; DBM_DATUM key; DBM_DATUM contents; struct cache_result res; char timebuf[80]; if (!cache_format->enabled) return; time(&res.timestamp); res.status = rc; debug4(50,"inserting cache info for %s. status=%s (%d), time=%s", email, mf_status_str(rc), rc, mailfromd_timestr(res.timestamp, timebuf, sizeof timebuf)); if (mu_dbm_open(cache_format->dbname, &db, MU_STREAM_RDWR, 0600, NULL)) { mu_error(_("mu_dbm_open(%s) failed: %s"), cache_format->dbname, mu_dbm_strerror()); return; } memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); MU_DATUM_PTR(key) = email; MU_DATUM_SIZE(key) = strlen (email) + 1; MU_DATUM_PTR(contents) = (void*)&res; MU_DATUM_SIZE(contents) = sizeof(res); if (mu_dbm_insert(&db, key, contents, 1)) mu_error(_("Cannot insert datum `%s' into `%s': %s"), email, db.name, mu_dbm_strerror()); mu_dbm_close(&db); } static void cache_print_item(const char *email, size_t size, const void *content) { const struct cache_result *res = content; size--; /* Size includes the trailing nul */ printf("%*.*s", size, size, email); printf(" %10.10s ", mf_status_str(res->status)); format_time_str(stdout, res->timestamp); putchar('\n'); } static int cache_expire_item(const void *content) { const struct cache_result *res = (struct cache_result *)content; return !res || time(NULL) - res->timestamp > EXPIRE_INTERVAL(res->status); } mf_status cache_get2(char *email, char *client_addr) { mf_status rc = mf_failure; size_t size; char *key; if (!cache_format->enabled) return mf_failure; size = strlen(email) + 1 + strlen(client_addr) + 1; key = malloc(size); if (key) { strcat(strcat(strcpy(key, email), ":"), client_addr); rc = cache_get(key); free(key); } return rc; } void cache_insert2(char *email, char *client_addr, mf_status rc) { if (!cache_format->enabled) return; else { size_t size = strlen(email) + 1 + strlen(client_addr) + 1; char *key = malloc(size); if (key) { strcat(strcat(strcpy(key, email), ":"), client_addr); cache_insert(key, rc); free(key); } } } static struct db_format cache_format_struct = { "cache", DEFAULT_DATABASE, 1, DEFAULT_EXPIRE_INTERVAL, cache_print_item, cache_expire_item }; struct db_format *cache_format = &cache_format_struct;